this 现实上是在函数被挪用时发作的绑定,它指向什么完整取决于函数的挪用位置(也就是函数的挪用要领)。
四条划定规矩:(你不知道的JS)
1. 默许绑定
function foo() {
console.log( this.a );
}
var a = 2;
foo(); // 2
不管是不是在严厉形式下,在全局实行高低文中(在任何函数体外部)this 都指代全局对象。(MDN)
在严厉形式下,this将坚持他进入实行高低文时的值,假如 this 没有被实行高低文(execution context)定义,那它将坚持为 undefined。(MDN)
function foo() {
"use strict";
console.log( this.a );
}
var a = 2;
foo(); // TypeError: this is undefined
2. 隐式绑定/丧失
当函数作为对象里的要领被挪用时,它们的 this 是挪用该函数的对象,且绑定只受最靠近的成员援用的影响。(MDN)
//隐式绑定
function foo() {
console.log( this.a );
}
var obj2 = {
a: 42,
foo: foo
};
var obj1 = {
a: 2,
obj2: obj2
};
obj1.obj2.foo(); // 42
//隐式丧失
function foo() {
console.log( this.a );
}
function doFoo(fn) {
// fn 实在援用的是 foo
fn(); // <-- 挪用位置!
}
var obj = {
a: 2,
foo: foo
};
var a = "oops, global"; // a 是全局对象的属性
doFoo( obj.foo ); // "oops, global"
3. 显现绑定
假如要想把 this 的值从一个高低文传到另一个,就要用 call 或许apply 要领。(MDN)
挪用f.bind(someObject)会建立一个与f具有雷同函数体和作用域的函数,但是在这个新函数中,this将永远地被绑定到了bind的第一个参数,不管这个函数是怎样被挪用的。
var obj = {
count: 0,
cool: function coolFn() {
if (this.count < 1) {
setTimeout( function timer(){
this.count++; // this 是平安的
// 由于 bind(..)
console.log( "more awesome" );
}.bind( this ), 100 ); // look, bind()!
}
}
};
obj.cool(); // 更酷了。
硬绑定
建立一个包裹函数,传入一切的参数并返回接收到的一切值。
硬绑定会大大下降函数的灵活性,运用硬绑定以后就没法运用隐式绑定或许显式绑定来修正 this 。
// 简朴的辅佐绑定函数
function bind(fn, obj) {
return function() {
return fn.apply( obj, arguments );
};
}
软绑定
给默许绑定指定一个全局对象和 undefined 之外的值,那就能够完成和硬绑定雷同的结果,同时保存隐式绑定或许显式绑定修正 this 的才能。
Function.prototype.softBind = function(obj) {
var fn = this;
var curried = [].slice.call( arguments, 1 );// 捕捉一切 curried 参数
var bound = function() {
return fn.apply(
(!this || this === (window || global))?obj : this
curried.concat.apply( curried, arguments )
);
};
bound.prototype = Object.create( fn.prototype );
return bound;
};
4. new 绑定
当一个函数用作组织函数时(运用new关键字),它的this被绑定到正在组织的新对象。(MDN)
运用 new 来挪用函数,或许说发作组织函数挪用时,会自动实行下面的操纵(你不知道的JS)
- 建立(或许说组织)一个全新的对象。
- 这个新对象会被实行 [[ 原型 ]] 衔接。
- 这个新对象会绑定到函数挪用的 this 。
- 假如函数没有返回其他对象,那末 new 表达式中的函数挪用会自动返回这个新对象。
function foo(a) {
this.a = a;
}
var bar = new foo(2);
console.log( bar.a ); // 2
四条划定规矩优先级
new 绑定 > 显式绑定 > 隐式绑定 > 默许绑定
函数是不是在 new 中挪用( new 绑定)?假如是的话 this 绑定的是新建立的对象。
var bar = new foo()
函数是不是经由过程 call 、 apply (显式绑定)或许硬绑定挪用?假如是的话, this 绑定的是指定的对象。
别的:假如绑定 null 或许 undefined ,现实运用的是默许绑定划定规矩。var bar = foo.call(obj2)
函数是不是在某个高低文对象中挪用(隐式绑定)?假如是的话, this 绑定的是谁人高低文对象。
var bar = obj1.foo()
假如都不是的话,运用默许绑定。假如在严厉形式下,就绑定到 undefined ,不然绑定到全局对象。
var bar = foo()
个中:间接援用函数会运用默许绑定划定规矩
function foo() { console.log( this.a ); } var a = 2; var o = { a: 3, foo: foo }; var p = { a: 4 }; o.foo(); // 3 (p.foo = o.foo)(); // 2
破例
1. 箭头函数
箭头函数不运用 this 的四种规范划定规矩,而是依据外层(函数或许全局)作用域来决议 this 。
在箭头函数中,this与关闭词法高低文的this坚持一致。(MDN)
箭头函数会继续外层函数挪用的 this 绑定(不管 this 绑定到什么)。这实在和self = this 机制一样。
箭头函数的绑定没法被修正。
2. nodejs
setTimeout(function() {
console.log(this)
//浏览器中:window
//nodejs中:Timeout实例
}, 0)
其他诠释
https://www.zhihu.com/questio…
func(p1, p2) 等价于
func.call(undefined, p1, p2)
obj.child.method(p1, p2) 等价于
obj.child.method.call(obj.child, p1, p2)
假如你传的 context 就 null 或许 undefined,那末 window 对象就是默许的 context(严厉形式下默许 context 是 undefined)
例子
var number = 50;
var obj = {
number: 60,
getNum: function () {
var number = 70;
return this.number;
}
};
alert(obj.getNum());
alert(obj.getNum.call());
alert(obj.getNum.call({number:20}));
参考资料:
深切明白JavaScript系列(13):This? Yes,this!
MDN-this
《你不知道的JS上卷》浏览小记之setTimeout的this指向题目Script
JavaScript 的 this 道理-阮一峰
怎样明白 JavaScript 中的 this 关键字?-方应杭-知乎
JS this 相干题目