关于 This指向问题
1 定义
this 关键字是函数运行时自动生成的一个内部对象。
函数不执行,this没有意义。只能在函数内部使用,
总指向调用它的对象
2 绑定规则
- 默认绑定: 默认指向window, 独立调用也指向window
- new绑定
- 显式绑定:call apply bind
- 隐式绑定: 谁调用就指向谁(特例:隐式丢失,参数赋值)
例: 默认绑定
// 全局环境中定义person函数,内部使用this关键字
// **独立执行函数,this指向window**
var name = 'Jenny';
function person() {
return this.name;
}
console.log(person()); //Jenny
例:new绑定
// 通过构建函数new关键字生成一个实例对象,此时this指向这个实例对象
function test() {
this.x = 1;
}
var obj = new test();
obj.x // 1
特殊情况1:
// new过程遇到return一个对象,此时this指向为返回的对象
function fn() {
this.user = 'xxx';
return {};
}
var a = new fn();
console.log(a.user); //undefined
特殊情况2:
// 如果返回一个简单类型的时候,则this指向实例对象
function fn() {
this.user = 'xxx';
return 1;
}
var a = new fn;
console.log(a.user); //xxx
特殊情况3:
// 注意的是null虽然也是对象,但是此时new仍然指向实例对象
function fn() {
this.user = 'xxx';
return null;
}
var a = new fn;
console.log(a.user); //xxx
例:显式绑定
apply()、call()、bind()是函数的一个方法,作用是改变函数的调用对象。它的第一个参数就表示改变后的调用这个函数的对象。因此,这时this指的就是这第一个参数
var x = 0;
function test() {
console.log(this.x);
}
var obj = {};
obj.x = 1;
obj.m = test;
obj.m.apply(obj) // 1
function test(a,b,c,d) {
console.log(a, b, c, d)
}
const obj = {
a:2,
foo: test
}
var bar = obj.foo
obj.foo(1, 2, 3, 4)
bar.call(obj, 1, 2, 3, 4)
bar.apply(obj, [1, 2, 3, 4])
bar.bind(obj)(1, 2, 3, 4)
例: 隐式绑定
// 函数还可以作为某个对象的方法使用,这时this指向这个上级对象
function test() {
console.log(this.x)
function inner() {
console.log(this)
}
inner()
// 注意 这里的inner属于独立执行 则指向window
}
const obj = {}
obj.x = 1
obj.m = test
obj.m() // 1 window
// 自执行函数在任何情况下无论怎么调用 this都指向window
// 如果在node 环境中 则指向对应的全局对象
(function foo() {
console.log(this) // window
})()
// 这里属于闭包, obj.foo() 相当于test函数
// 则 obj.foo()()则相当于test(), 独立调用则this指向window
const obj = {
a: 'xxx',
foo: function() {
function test() {
console.log(this)
}
return test()
}
}
obj.foo()() // window
// 函数中包含多个对象,尽管这个函数被外层的对象所调用,this指向的也只是它的上一级对象
var o = {
a: 10,
b: {
fn: function() {
console.log(this.a)
}
}
}
o.b.fn()
// 上述内容中this的上一级对象是b,b没有a变量的定义,所以结构是undefined
特殊情况1: 变量赋值(隐式丢失)
var o = {
a:10,
b:{
a:12,
fn:function(){
console.log(this.a); //undefined
console.log(this); //window
}
}
}
var j = o.b.fn;
j();
// 此时指向的是window, this永远指向最后调用它的对象。不调用则this没有意义。
// 虽然fn是b的方法,但是fn赋值给j并没有执行,所以最终指向window.
// 属于 函数的独立调用
特殊情况2:参数赋值
var a = 0
function foo() {
console.log(this)
}
function bar(fn) {
fn()
}
var obj = {
a: 2,
foo: foo
}
// 预编译的过程中,实参被赋值为形参(值的拷贝过程,浅拷贝)
bar(obj.foo)
// bar(obj.foo) 其实就是执行bar函数,fn就是代表 foo函数
// 执行fn() 则就是独立调用foo函数 所以执行的是window
3 优先级
默认绑定 < 隐式绑定 < 显示绑定 < new 绑定
function foo(b) {
this.a = b
}
var obj1 = {}
var bar = foo.bind(obj1)
bar(2)
console.log(obj1.a) // 2
var baz = new bar(3)
console.log(obj1.a) // 2
console.log(baz) // 3