这是我参与8月更文挑战的第5天,活动详情查看:8月更文挑战markdown
function identify() {
return this.name.toUpperCase();
}
function speak() {
var greeting = "Hello, I'm " + identify.call( this );
console.log( greeting );
}
var me = {
name: "Kyle"
};
var you = {
name: "Reader"
};
identify.call( me ); // KYLE
identify.call( you ); // READER
speak.call( me ); // Hello, 我是 KYLE
speak.call( you ); // Hello, 我是 READE
复制代码
这段代码能够在不一样的上下文对象(me 和 you)中重复使用函数 identify() 和 speak(), 不用针对每一个对象编写不一样版本的函数。app
若是不使用 this,那就须要给 identify() 和 speak() 显式传入一个上下文对象。ide
function identify(context) {
return context.name.toUpperCase();
}
function speak(context) {
var greeting = "Hello, I'm " + identify( context );
console.log( greeting );
}
identify( you ); // READER
speak( me ); //hello, 我是 KYLE
复制代码
this
关键字, 被自动定义在全部函数的做用域中。函数
注意:this的指向在函数建立时肯定不了,被调用时才能肯定。post
咱们在找this指向时,要先找到调用位置
,而后判断符合哪一条绑定规则,同时注意绑定规则的优先级。ui
在找不到函数的调用对象时,this
注意: 对于默认绑定来讲,决定 this 绑定对象的并非调用位置是否处于严格模式,而是函数体是否处于严格模式
。编码
例1:函数调用前面没有对象spa
function sayHi(){
console.log('Hello,', this.name);
}
var name = 'YvetteLau';
sayHi();
// 'Hello,' YvetteLau
复制代码
经过对象调用函数,那么函数中this会指向最后调用它的对象。code
隐式丢失
1.将obj.fn()赋值给某个变量
虽然 bar 是 obj.foo 的一个引用,可是实际上,它引用的是 foo 函数自己,所以此时的 bar() 实际上是一个不带任何修饰的函数调用,所以应用了默认绑定。
以下示例, o.foo
的 this
隐式绑定在了 o
对象上, 而 bar
引用了 o.foo
函数自己, 因此此时的 bar()
实际上是一个不带任何修饰的函数调用, 所以使用了 默认绑定 规则:
var o = {
a: 1,
foo() {
console.log(this.a)
}
}
var bar = o.foo
o.foo() // 1
bar() // undefined
复制代码
2.将obj.fn()赋值给函数的形参
参数传递其实就是一种隐式赋值,所以咱们传入函数时也会被隐式赋值。示例中, bar(o.foo)
实际上采用了隐式赋值: callback = o.foo
, 事实上跟上面的例子同样, 都是直接引用了 o.foo
函数自己, 因此形成了 隐式丢失:
function bar(callback) {
callback()
}
var o = {
a: 1,
foo() {
console.log(this.a)
}
}
bar(o.foo) // undefined
复制代码
3.setTimeOut函数中的this
例2:setTimeOut中包含的函数,在后面执行时,并无对象去调用这个函数,因此也是默认绑定。
btn.onclick = function(){
setTimeout(function(){
console.log(this);
},0)
}
btn.onclick();
// window
复制代码
虽然onclick函数是btn对象调用的,但setTimeout函数中的内容并没有
在btn对象调用onclick函数时当即执行
,等到setTimeout函数执行时,setTimeout函数找不到调用对象,这时变为默认绑定
,非严格模式下,setTimeout函数内的this指向window
。
(setTimeOut任务是宏任务
,会在下一轮事件循环
执行。具体参见:juejin.cn/post/693532…)
咱们有时想要强制为某个函数绑定this,能够经过使用 call()
和 apply()
方法来实现;
函数.call(要绑定this的对象, 参数1, 参数2, ...)
函数.apply(要绑定this的对象, [参数1, 参数2, ...])
硬绑定
function foo() {
console.log( this.a );
}
var obj = {
a:2
};
var bar = function() {
foo.call( obj );
};
bar(); // 2
setTimeout( bar, 100 ); // 2
// 硬绑定的 bar 不可能再修改它的 this
bar.call( window ); // 2
复制代码
咱们建立了函数 bar(),并在它的内部手动调用 了 foo.call(obj) ,所以强制把 foo 的 this 绑定到了 obj。不管以后如何调用函数 bar,它 总会手动在 obj 上调用 foo。这种绑定是一种显式的强制绑定,所以咱们称之为硬绑定。
硬绑定ES5API
bind(..) 会返回一个硬编码的新函数,它会把参数设置为 this 的上下文并调用原始函数。
硬绑定时传入null/undefined,则会忽略本次硬绑定,采用默认绑定规则。
当使用 new 操做符调用某个函数时,这个函数被构造调用
。
new
操做符在调用函数时作的工做:
this
会指向这个新对象new
表达式中的函数调用会自动返回这个新对象new绑定 > 显式绑定 > 隐式绑定 > 默认绑定
判断this:
- 函数是否在 new 中调用(new 绑定)?若是是的话 this 绑定的是新建立的对象。
- 函数是否经过 call、apply(显式绑定)或者硬绑定调用?若是是的话,this 绑定的是 指定的对象。
- 函数是否在某个上下文对象中调用(隐式绑定)?若是是的话,this 绑定的是那个上 下文对象。
- 若是都不是的话,使用默认绑定。若是在严格模式下,就绑定到 undefined,不然绑定到全局对象。
箭头函数没法使用上述规则。根据根据外层(函数或者全局)做用域来决定 this。
箭头函数的this指向它外层做用域调用时的this。
foo() 内部建立的箭头函数会捕获调用时 foo() 的 this
。因为 foo() 的 this 绑定到 obj1, bar(引用箭头函数)的 this 也会绑定到 obj1,箭头函数的绑定没法被修改。(new 也不行!)
function foo() {
// 返回一个箭头函数
return (a) => {
//this 继承自 foo()
console.log( this.a );
};
}
var obj1 = {
a:2
};
var obj2 = {
a:3
};
var bar = foo.call( obj1 );
bar.call( obj2 ); // 2, 不是 3
复制代码
箭头函数会继承外层函数调用的 this 绑定(不管 this 绑定到什么)。
你不知道的JavaScript