我喜欢在JS中更改函数执行上下文的指向,也称为 this 指向。
例如,咱们可以在类数组对象上使用数组方法:
const reduce = Array.prototype.reduce;
function sumArgs() {
return reduce.call(arguments, (sum, value) => {
return sum += value;
});
}
sumArgs(1, 2, 3); // => 6
另一方面,this 很难把握。
咱们经常会发现自己用的 this 指向不正确。下面的教你如何简单地将 this 绑定到所需的值。
在开始之前,我需要一个辅助函数execute(func),它仅执行作为参数提供的函数。
function execute(func) {
return func();
}
execute(function() { return 10 }); // => 10
现在,继续理解围绕this错误的本质:方法分离。
假设有一个类Person包含字段firstName和lastName。此外,它还有一个方法getFullName(),该方法返回此人的全名。如下所示:
function Person(firstName, lastName) {
this.firstName = firstName;
this.lastName = lastName;
this.getFullName = function() {
this === agent; // => true
return `${this.firstName} ${this.lastName}`;
}
}
const agent = new Person('前端', '小智');
agent.getFullName(); // => '前端 小智'
可以看到Person函数作为构造函数被调用:new Person('前端', '小智')。 函数内部的 this 表示新创建的实例。
getfullname()返回此人的全名:'前端 小智'。正如预期的那样,getFullName()方法内的 this 等于agent。
如果辅助函数执行agent.getFullName方法会发生什么:
execute(agent.getFullName); // => 'undefined undefined'
执行结果不正确:'undefined undefined',这是 this 指向不正确导致的问题。
现在在getFullName() 方法中,this的值是全局对象(浏览器环境中的 window )。 this 等于 window,${window.firstName} ${window.lastName} 执行结果是 'undefined undefined'。
发生这种情况是因为在调用execute(agent.getFullName)时该方法与对象分离。 基本上发生的只是常规函数调用(不是方法调用):
execute(agent.getFullName); // => 'undefined undefined'
// 等价于:
const getFullNameSeparated = agent.getFullName;
execute(getFullNameSeparated); // => 'undefined undefined'
这个就是所谓的方法从它的对象中分离出来,当方法被分离,然后执行时,this 与原始对象没有连接。
为了确保方法内部的this指向正确的对象,必须这样做
方法分离问题,以及由此导致this指向不正确,一般会在下面的几种情况中出现:
回调
// `methodHandler()`中的`this`是全局对象
setTimeout(object.handlerMethod, 1000);
在设置事件处理程序时
// react: `methodHandler()`中的`this`是全局对象
<button onClick={object.handlerMethod}>
Click me
</button>
接着介绍一些有用的方法,即如果方法与对象分离,如何使this指向所需的对象。
保持this指向类实例的最简单方法是使用一个额外的变量self:
function Person(firstName, lastName) {
this.firstName = firstName;
this.lastName = lastName;
const self = this;
this.getFullName = function() {
self === agent; // => true
return `${self.firstName} ${self.lastName}`;
}
}
const agent = new Person('前端', '小智');
agent.getFullName(); // => '前端 小智'
execute(agent.getFullName); // => '前端 小智'
getFullName()静态地关闭self变量,有效地对this进行手动绑定。
现在,当调用execute(agent.getFullName)时,一切工作正常,因为getFullName()方法内 this 总是指向正确的值。
有没有办法在没有附加变量的情况下静态绑定this? 是的,这正是箭头函数的作用。
使用箭头函数重构Person:
function Person(firstName, lastName) {
this.firstName = firstName;
this.lastName = lastName;
this.getFullName = () => `${this.firstName} ${this.lastName}`;
}
const agent = new Person('前端', '小智');
agent.getFullName(); // => '前端 小智'
execute(agent.getFullName); // => '前端 小智'
箭头函数以词法方式绑定this。 简单来说,它使用来自其定义的外部函数this的值。
建议在需要使用外部函数上下文的所有情况下都使用箭头函数。
现在让咱们更进一步,使用ES6中的类重构Person。
class Person {
constructor(firstName, lastName) {
this.firstName = firstName;
this.lastName = lastName;
}
getFullName() {
return `${this.firstName} ${this.lastName}`;
}
}
const agent = new Person('前端', '小智');
agent.getFullName(); // => '前端 小智'
execute(agent.getFullName); // => 'undefined undefined'
不幸的是,即使使用新的类语法,execute(agent.getFullName)仍然返回“undefined undefined”。
在类的情况下,使用附加的变量self或箭头函数来修复this的指向是行不通的。
但是有一个涉及bind()方法的技巧,它将方法的上下文绑定到构造函数中:
class Person {
constructor(firstName, lastName) {
this.firstName = firstName;
this.lastName = lastName;
this.getFullName = this.getFullName.bind(this);
}
getFullName() {
return `${this.firstName} ${this.lastName}`;
}
}
const agent = new Person('前端', '小智');
agent.getFullName(); // => '前端 小智'
execute(agent.getFullName); // => '前端 小智'
构造函数中的this.getFullName = this.getFullName.bind(this)将方法getFullName()绑定到类实例。
execute(agent.getFullName) 按预期工作,返回'前端 小智'。
bind 方式有点太过冗长,咱们可以使用胖箭头的方式:
class Person {
constructor(firstName, lastName) {
this.firstName = firstName;
this.lastName = lastName;
}
getFullName = () => {
return `${this.firstName} ${this.lastName}`;
}
}
const agent = new Person('前端', '小智');
agent.getFullName(); // => '前端 小智'
execute(agent.getFullName); // => '前端 小智'
胖箭头方法getFullName =() =>{…}绑定到类实例,即使将方法与其对象分离。
这种方法是在类中绑定this的最有效和最简洁的方法。
与对象分离的方法会产生 this 指向不正确问题。静态地绑定this,可以手动使用一个附加变量self来保存正确的上下文对象。然而,更好的替代方法是使用箭头函数,其本质上是为了在词法上绑定this。
在类中,可以使用bind()方法手动绑定构造函数中的类方法。当然如果你不用使用 bind 这种冗长方式,也可以使用简洁方便的胖箭头表示方法。
原文:https://github.com/valentinogagliardi/Little-JavaScript-Book/blob/v1.0.0/manuscript/chapter5.md
作者:Dmitri Pavlutin
译者:前端小智
JavaScript中有很多令人困惑的地方,或者叫做机制。但是,就是这些东西让JavaScript显得那么美好而与众不同。比方说函数也是对象、闭包、原型链继承等等,而这其中就包括颇让人费解的this机制。
this的绑定过程之前的调用栈 和 调用位置,this绑定规则:1、默认模式,2、隐式绑定,3、显式绑定,4、new绑定
在 JavaScript 中,this 这个特殊的变量是相对比较复杂的,因为 this 不仅仅用在面向对象环境中,在其他任何地方也是可用的。 本篇博文中会解释 this 是如何工作的以及使用中可能导致问题的地方,最后奉上最佳实践。
this关键字在js中的指向问题不管是工作还是面试中都会经常遇到,所以在此对它进行一下总结:全局作用域中、闭包中指window、函数调用模式:谁调用就指谁、构造函数中,this指实例对象、apply/call改变this的指向、bind改变this指向等
如果这很难明白,为什么我们不停止使用它呢?认真的思考一下?如果你读过 将90%的垃圾扔进垃圾桶后,我如何重新发现对JavaScript的爱, 当我说扔掉它时,你不会感到惊讶,this被丢弃了
this的用法:直接在函数中使用 谁调用这个函数this就指向谁 ,对象中使用, 一般情况下指向该对象 ,在构造函数中使用
this的四种绑定策略:默认绑定、隐式绑定、显示绑定、new绑定。首先要明确的是一般情况下,this不是函数被定义时绑定,而是函数被调用时被绑定 ,那么函数中的this有四种绑定方式:
this是Javascript语言的一个关键字。它代表函数运行时,自动生成的一个内部对象.this永远指向函数的调用者。随着函数使用场合的不同,this的值会发生变化。但是有一个总的原则,那就是this指的是,调用函数的那个对象。
apply和call的区别就是传的参数形式不一样。call是一个一个的传,apply可以将参数以数组的形式传进去。而bind是传入第二个和后面的参数,且绑定this,返回一个转化后的函数。
以函数形式调用,this指向window;以方法形式调用,this指向调用方法的那个对象;构造函数调用,this指向实例的对象;使用window对象的方法使,指向window;多重场景改变this指向
内容以共享、参考、研究为目的,不存在任何商业目的。其版权属原作者所有,如有侵权或违规,请与小编联系!情况属实本人将予以删除!