- 默认绑定
- 隐式绑定(隐式丢失)
- 显式绑定
- new 绑定
- 严格模式下的 this
- 箭头函数绑定
默认绑定
this 指向 window
- 例子 1:在全局环境中,this 默认绑定到 window
console.log(this === window);
// 输出
// true
// 例子2:函数独立调用的时候,this默认绑定到window
- 例子 2:函数独立调用的时候,this 默认绑定到 window
function foo1() {
console.log(this === window);
}
foo1();
// 输出
// true
- 例子 3:被嵌套函数独立调用的时候,this 默认绑定到 window
var a = 0;
var obj1 = {
a: 2,
foo: function() {
function test() {
console.log(this.a);
}
test();
}
};
obj1.foo();
// 输出
// 0
- 例子 4:IIFE 立即执行函数实际上是函数声明后直接调用执行
var a = 0;
function foo2() {
(function test() {
console.log(this.a);
})();
}
var obj = {
a: 2,
foo: foo2
};
obj.foo();
// 输出
// 0
相当于
var a = 0;
var obj = {
a: 2,
foo: function() {
function test() {
console.log(this.a);
}
test();
}
};
obj.foo();
// 输出
// 0
- 例子 5:闭包下的 this
// 例子4:闭包
var a = 0;
function foo3() {
function test() {
console.log(this.a);
}
return test;
}
var obj = {
a: 2,
foo: foo3
};
obj.foo()();
// 输出
// 0
- 例子 6:如何访问嵌套函数 this 的值
var a = 0;
function foo4() {
var that = this;
function test() {
console.log(that.a);
}
return test;
}
var obj = {
a: 2,
foo: foo4
};
obj.foo()();
// 输出
// 2
隐式绑定
被对象的方法调用时,this 隐式绑定到该对象
- 例子 1
function foo5() {
console.log(this.a);
}
var obj1 = {
a: 1,
foo: foo5,
obj2: {
a: 2,
foo: foo5
}
};
obj1.foo();
obj1.obj2.foo();
// 输出
// 1
// 2
- 例子 2
function foo() {
console.log(this.a);
}
var a = 2;
var o = {
a: 3,
foo: foo
};
var p = {
a: 4
};
o.foo();
// 这个和 var bar = obj.foo; 隐式丢失不一样,这是把函数赋值给p.foo,属于p对象的foo函数执行
p.foo = o.foo;
p.foo();
// 输出
// 3
// 4
隐式丢失
隐式绑定的函数丢失了绑定对象,导致 this 绑定到 window
- 例子 1:函数别名导致隐式丢失
把 obj.foo 赋给变量 bar,导致了隐式丢失,只是把函数赋给了 bar,bar 与 obj 无任何关系
var a = 0;
function foo6() {
return this.a;
}
var obj = {
a: 2,
foo: foo6
};
console.log(obj.foo());
var bar = obj.foo;
console.log(bar());
// 输出
// 2
// 0
// 等价于
var a = 0;
var bar2 = function foo() {
console.log(this.a);
};
bar2();
- 例子 2:参数传递导致隐式丢失
obj.foo 作为参数传递给 bar3 函数,知识把 foo8 函数赋给了 fn,fn 与 obj 没有关系
var a = 0;
function foo8() {
console.log(this.a);
}
function bar3(fn) {
fn();
}
var obj = {
a: 2,
foo: foo8
};
console.log(bar3(obj.foo));
// 输出
// 0
// 等价于
var a = 0;
function bar4(fn) {
fn();
}
bar4(function foo() {
console.log(this.a);
});
- 例子 3:内置函数导致隐式丢失
var a = 0;
function foo9() {
console.log(this.a);
}
var obj = {
a: 2,
foo: foo9
};
setTimeout(obj.foo, 100);
// 输出
// 0
// 等价于
var a = 0;
setTimeout(function foo() {
console.log(this.a);
}, 100);
- 例子 4:间接引用导致隐式丢失
只是将 o.foo 函数赋值给 p.foo 函数,然后立即执行,仅仅是 foo 函数的立即执行
function foo10() {
console.log(this.a);
}
var a = 0;
var o = {
a: 3,
foo: foo10
};
var p = {
a: 4
};
o.foo();
(p.foo = o.foo)();
// 输出
// 3
// 0
- 例子 5:其他情况丢失了 this 绑定
var a = 0;
function foo11() {
console.log(this.a);
}
var obj4 = {
a: 2,
foo: foo11
};
// obj.foo和foo的内存地址不一样,所以this指向window
(obj.foo = obj4.foo)();
// 执行的是obj4.foo=bj4.foo
(false || obj4.foo)();
// 执行的是obj4.foo=bj4.foo
(1, obj4.foo)();
// 输出
// 0
// 0
// 0
显式绑定
通过 call()、apply()、bind()把对象绑定到 this 上
- 例子 1
var a = 0;
function foo12() {
console.log(this.a);
}
var obj = {
a: 2
};
foo12();
foo12.call(obj);
// 输出
// 0
// 2
- 例子 2:硬绑定
在函数内部,强制 this 指向绑定的对象
var a = 0;
function foo13() {
console.log(this.a);
}
var obj = {
a: 2
};
var bar = function() {
foo13.call(obj);
};
bar();
setTimeout(bar, 100);
bar.call(window);
// 输出
// 2
// 2
// 2
- 例子 3
数组内置方法 map()、forEach()、filter()、some()、every()可以进行显示绑定
var a = 0;
function foo() {
console.log(this.a);
}
var obj = {
a: 2
};
[1].forEach(foo);
[1].forEach(foo, obj);
// 输出
// 0
// 2
new 绑定
如果函数或者方法调用之前有关键字 new,构成了构造函数,对于 this 来说,称为 new 绑定
- 例子 1
function fn2() {
this.a = 2;
}
var test = new fn2();
console.log(test.a);
// 输出
// 2
- 例子 2
function fn3() {
this.a = 2;
return 1;
}
var test = new fn3();
console.log(test.a);
// 输出
// 2
- 例子 3
var obj = {
a: 0
};
function fn4() {
this.a = 2;
return obj;
}
var test = new fn4();
console.log(test.a);
// 输出
// 0
- 例子 4
new 对象的方法,this 的指向不是这个对象,而是这个构造函数
var o = {
m: function() {
return this;
}
};
var obj = new o.m();
console.log(obj === o);
console.log(obj.constructor === o.m);
// 输出
// false
// true
严格模式绑定
函数的 this 值始终是指定的值
- 例子 1
独立调用的函数的 this 值始终是指定 undefined
function fn5() {
'use strict';
console.log(this);
}
fn5();
// 输出
// undefined
箭头函数绑定
this 指向定义时所在的对象,而不是运行时所在的对象
- 例子 1
// 箭头函数定义时所在的对象
function foo14() {
var id = 2;
setTimeout(() => {
console.log(this.id);
}, 100);
}
foo14.call({
id: 0
});
// 输出
// 0
// 函数运行时所在的对象
var id = 2;
function foo15() {
setTimeout(function() {
console.log(this.id);
}, 100);
}
foo15.call({
id: 0
});
// 输出
// 2
- 例子 2
// 箭头函数定义时所在的对象
var a = 0;
var obj5 = {
a: 2,
foo: () => {
console.log(this.a);
}
};
obj5.foo();
// 输出
// 0
// 函数运行时所在的对象
var a = 0;
var obj6 = {
a: 2,
foo: function() {
console.log(this.a, 1);
}
};
obj6.foo();
// 输出
// 2
- 例子 3
箭头函数的 this 无法通过 bind,call,apply 来直接修改
function foo16() {
return () => {
return () => {
return () => {
console.log(this.a);
};
};
};
}
var f = foo16.call({
a: 0
});
var t1 = f.call({
a: 1
})()();
var t2 = f().call({
a: 2
})();
var t3 = f()().call({
a: 3
});
// 输出
// 0
// 0
// 0
function foo17() {
return function() {
return function() {
return function() {
console.log(this.a);
};
};
};
}
var f = foo17.call({
a: 0
});
var t1 = f.call({
a: 1
})()();
var t2 = f().call({
a: 2
})();
var t3 = f()().call({
a: 3
});
// 输出
// 0
// 0
// 0
箭头函数的特点
- 箭头函数不绑定 this,箭头函数的 this 相当于普通变量
- 箭头函数的 this 寻值行为与普通变量相同,在作用域中逐级寻找
- 箭头函数 this 无法通过 bind,call,apply 来直接修改
- 改变作用域中的 this 指向就可以改变箭头函数的 this
确认评论邮箱
邀请制评论