this的绑定只受最靠近的成员引用的影响
- new > 显示绑定 > 隐式绑定 > 默认绑定。
默认绑定
-
全局
-
函数独立调用 window
-
闭包
function t(){ return function(){ console.log(this) //window,也属于函数独立调用 } }
隐式绑定
-
function foo(){ console.log(this.a); } var obj1 = { a : 1; foo: foo, //this -> obj1 obj2 : { a:2, foo:foo //this -> obj2 } } -
隐式丢失
-
【函数别名】 var a = 0; function foo(){ console.log(this.a); } var obj = { a: 1, foo:foo } obj.foo(); //this指向obj var bar = obj.foo; //最靠近成员是bar 他所在的是作用域是全局 bar();//0 --------------------------------------------------- 【参数传递】 var a = 0; function foo() { console.log(this.a); } function bar(fn) { fn(); } var obj = { a: 2, foo } bar(obj.foo); // var fn = obj.foo 隐式赋值 this就是fn -------------------------------------------------------- 【内置函数】 var a = 0; function foo(){ console.log(this.a); } var obj = { a : 2, foo:foo } setTimeout(obj.foo,100);//0 var callback = obj.foo ----------------------------------------------------------- 【间接调用】 function foo(){ console.log(this.a); } var a = 2; var o = {a: 3,foo: foo}; var p = {a: 4}; o.foo();//3; //将o.foo函数赋值给p.foo函数,然后立即执行。相当于仅仅是foo()函数的立即调用 (p.foo = o.foo)();//2 var bar = (p.foo = o.foo) //另一种情况 function foo() { console.log( this.a ); } var a = 2; var o = { a: 3, foo: foo }; var p = { a: 4 }; o.foo(); // 3 //将o.foo函数赋值给p.foo函数,之后p.foo函数再执行,是属于p对象的foo函数的执行 p.foo = o.foo; p.foo();//4 ------------------------------------------------ 其他情况 在javascript引擎内部,obj和obj.foo储存在两个内存地址,简称为M1和M2。只有obj.foo()这样调用时,是从M1调用M2,因此this指向obj。但是,下面三种情况,都是直接取出M2进行运算,然后就在全局环境执行运算结果(还是M2),因此this指向全局环境 var a = 0; var obj = { a:2, foo:foo } function foo(){ console.log(this.a); } (obj.foo = obj.foo)();//0 立即执行 (false || obj.foo)();//0 (1,obj.foo)();//0
-
显示绑定
通过call()、apply()、bind()方法把对象绑定到this上,叫做显示绑定。对于被调用的函数来说,叫做间接调用
var a = 0;
function foo(){
console.log(this.a);
}
var obj = {
a : 2
};
foo();//0
foo.call(obj);//2
显示绑定无法解决隐式丢失问题
硬绑定
硬绑定是显式绑定的一个变种,使this不能再被修改
var a = 0;
function foo(){
console.log(this.a);
}
var obj = {
a:2
};
var bar = function (){
foo.call(obj);
}
//在bar函数内部手动调用foo.call(obj)。因此,无论之后如何调用函数bar,它总会手动会在obj上调用foo
bar();//2
setTimeout(bar,2000);//2
bar.call(window);//2
api
javascript中新增了许多内置函数,具有显式绑定的功能,如数组的5个迭代方法:map()、forEach()、filter()、some()、every()
//forEach(fn,对象)
var id = 'window';
function foo(value){
console.log(value,index,this.id);
}
var obj = {
id: 'fn'
};
[1,2,3].forEach(foo);//1 0 "window" 2 1 "window" 3 2 "window"
[1,2,3].forEach(foo,obj);//1 "fn" 2 "fn" 3 "fn"
bind
ECMAScript 5 引入了 Function.prototype.bind。调用f.bind(someObject)会创建一个与f具有相同函数体和作用域的函数,但是在这个新函数中,this将永久地被绑定到了bind的第一个参数,无论这个函数是如何被调用的。
function f(){
return this.a;
}
var g = f.bind({a:"azerty"});
console.log(g()); // azerty
var h = g.bind({a:'yoo'}); // bind只生效一次!
console.log(h()); // azerty
var o = {a:37, f:f, g:g, h:h};
console.log(o.f(), o.g(), o.h()); // 37, azerty, azerty
new 绑定
var o = {
m:function(){
return this;
}
}
var obj = new o.m();
console.log(obj,obj === o);//{} false
console.log(obj.contructor === o.m);//true
this场景
严格模式
- 独立调用的函数的this指向undefined
- 使用call和apply时,null和undefined不会转换成全局对象,如果不指定的话会出错
getter 与 setter 中的 this
用作 getter 或 setter 的函数都会把 this 绑定到设置或获取属性的对象。
function sum() {
return this.a + this.b + this.c;
}
var o = {
a: 1,
b: 2,
c: 3,
get average() {
return (this.a + this.b + this.c) / 3;
}
};
Object.defineProperty(o, 'sum', {
get: sum, enumerable: true, configurable: true});
console.log(o.average, o.sum); // logs 2, 6
原型链中的 this
指向调用这个方法的对象
var o = {
f: function() {
return this.a + this.b;
}
};
var p = Object.create(o);
p.a = 1;
p.b = 4;
console.log(p.f()); // 5 p调用这个方法。this指向他
DOM事件处理函数
this指向触发事件的函数
this === e.currentTarget
ul>li ul.onclick ==>this是ul e.target是li
箭头函数
this就是封闭词法环境的this
var foo = () => this;
无论如何,foo 的 this 被设置为他被创建时的环境