We read every piece of feedback, and take your input very seriously.
To see all available qualifiers, see our documentation.
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
作者:valentinogagliardi 译者:前端小智 来源:github
作者:valentinogagliardi
译者:前端小智
来源:github
阿里云最近在做活动,低至2折,有兴趣可以看看: https://promotion.aliyun.com/ntms/yunparter/invite.html?userCode=pxuujn3r
为了保证的可读性,本文采用意译而非直译。
JS 中的this关键字对于初学者来说是一个谜,对于经验丰富的开发人员来说则是一个永恒的难题。this 实际上是一个移动的目标,在代码执行过程中可能会发生变化,而没有任何明显的原因。首先,看一下this关键字在其他编程语言中是什么样子的。 以下是 JS 中的一个 Person 类:
this
Person
class Person { constructor(name) { this.name = name; } greet() { console.log("Hello " + this.name); } }
Python 类也有一个跟 this 差不多的东西,叫做self:
Python
self
class Person: def __init__(self, name): self.name = name def greet(self): return 'Hello' + self.name
在Python类中,self表示类的实例:即从类开始创建的新对象
me = Person('Valentino')
PHP中也有类似的东西:
class Person { public $name; public function __construct($name){ $this->name = $name; } public function greet(){ echo 'Hello ' . $this->name; } }
这里$this是类实例。再次使用JS类来创建两个新对象,可以看到每当咱们调用object.name时,都会返回正确的名字:
$this
object.name
class Person { constructor(name) { this.name = name; } greet() { console.log("Hello " + this.name); } } const me = new Person("前端小智"); console.log(me.name); // '前端小智' const you = new Person("小智"); console.log(you.name); // '小智'
JS 中类似乎类似于Python、Java和PHP,因为 this 看起来似乎指向实际的类实例?
这是不对的。咱们不要忘记JS不是一种面向对象的语言,而且它是宽松的、动态的,并且没有真正的类。this与类无关,咱们可以先用一个简单的JS函数(试试浏览器)来证明这一点:
function whoIsThis() { console.log(this); } whoIsThis();
如果在浏览器中运行以下代码
输出如下:
Window {postMessage: ƒ, blur: ƒ, focus: ƒ, close: ƒ, parent: Window, …}
如上所示,咱们当 this 没有在任何类中的时候,this 仍然有值。当一个函数在全局环境中被调用时,该函数会将它的this指向全局对象,在咱们的例子中是window。
window
这是JS的第一条规则,叫作默认绑定。默认绑定就像一个回退,大多数情况下它是不受欢迎的。在全局环境中运行的任何函数都可能“污染”全局变量并破坏代码。考虑下面的代码:
function firstDev() { window.globalSum = function(a, b) { return a + b; }; } function nastyDev() { window.globalSum = null; } firstDev(); nastyDev(); var result = firstDev(); console.log(result); // Output: undefined
第一个开发人员创建一个名为globalSum的全局变量,并为其分配一个函数。接着,另一个开发人员将null分配给相同的变量,从而导致代码出现故障。
globalSum
null
处理全局变量总是有风险的,因此JS引入了**“安全模式”:严格模式。严格模式是通过使用“use Strict”启用。严格模式中的一个好处就是消除了默认绑定**。在严格模式下,当试图从全局上下文中访问this时,会得到 undefined 。
“use Strict”
undefined
"use strict"; function whoIsThis() { console.log(this); } whoIsThis(); // Output: undefined
严格的模式使JS代码更安全。
小结一下,默认绑定是JS中的第一条规则:当引擎无法找出this是什么时,它会返回到全局对象。接下看看另外三条规则。
“隐式绑定”是一个令人生畏的术语,但它背后的理论并不那么复杂。它把范围缩小到对象。
var widget = { items: ["a", "b", "c"], printItems: function() { console.log(this.items); } };
当一个函数被赋值为一个对象的属性时,该对象就成为函数运行的宿主。换句话说,函数中的this将自动指向该对象。这是JS中的第二条规则,名为隐式绑定。即使在全局上下文中调用函数,隐式绑定也在起作用
咱们无法从代码中看出,但是JS引擎将该函数分配给全局对象 window 上的一个新属性,如下所示:
window.whoIsThis = function() { console.log(this); };
咱们可以很容易地证实这个假设。在浏览器中运行以下代码:
function whoIsThis() { console.log(this); } console.log(typeof window.whoIsThis)
打印"function"。对于这一点你可能会问:在全局函数中this 的真正规则是什么?
"function"
像是缺省绑定,但实际上更像是隐式绑定。有点令人困惑,但只要记住,JS引擎在在无法确定上下文(默认绑定)时总是返回全局this。另一方面,当函数作为对象的一部分调用时,this 指向该调用的对象(隐式绑定)。
如果不是 JS 使用者,很难看到这样的代码:
someObject.call(anotherObject); Someobject.prototype.someMethod.apply(someOtherObject);
这就是显式绑定,在 React 会经常看到这中绑定方式:
class Button extends React.Component { constructor(props) { super(props); this.state = { text: "" }; // bounded method this.handleClick = this.handleClick.bind(this); } handleClick() { this.setState(() => { return { text: "PROCEED TO CHECKOUT" }; }); } render() { return ( <button onClick={this.handleClick}> {this.state.text || this.props.text} </button> ); } }
现在React Hooks 使得类几乎没有必要了,但是仍然有很多使用ES6类的“遗留”React组件。大多数初学者会问的一个问题是,为什么咱们要在 React 中通过 bind` 方法重新绑定事件处理程序方法?
React Hooks 使得类几乎没有必要了,但是仍然有很多使用ES6类的“遗留”React组件。大多数初学者会问的一个问题是,为什么咱们要在 React 中通过
call、apply、bind 这三个方法都属于Function.prototype。用于的显式绑定(规则3):显式绑定指显示地将this绑定到一个上下文。但为什么要显式绑定或重新绑定函数呢?考虑一些遗留的JS代码:
call
apply
bind
Function.prototype
var legacyWidget = { html: "", init: function() { this.html = document.createElement("div"); }, showModal: function(htmlElement) { var newElement = document.createElement(htmlElement); this.html.appendChild(newElement); window.document.body.appendChild(this.html); } };
showModal是绑定到对象legacyWidget的“方法”。this.html 属于硬编码,把创建的元素写死了(div)。这样咱们没有办法把内容附加到咱们想附加的标签上。
showModal
legacyWidget
this.html
解决方法就是可以使用显式绑定this来更改showModal的对象。。现在,咱们可以创建一个小部件,并提供一个不同的HTML元素作附加的对象:
var legacyWidget = { html: "", init: function() { this.html = document.createElement("div"); }, showModal: function(htmlElement) { var newElement = document.createElement(htmlElement); this.html.appendChild(newElement); window.document.body.appendChild(this.html); } }; var shinyNewWidget = { html: "", init: function() { // A different HTML element this.html = document.createElement("section"); } };
接着,使用 call 调用原始的方法:
var legacyWidget = { html: "", init: function() { this.html = document.createElement("div"); }, showModal: function(htmlElement) { var newElement = document.createElement(htmlElement); this.html.appendChild(newElement); window.document.body.appendChild(this.html); } }; var shinyNewWidget = { html: "", init: function() { this.html = document.createElement("section"); } }; // 使用不同的HTML元素初始化 shinyNewWidget.init(); // 使用新的上下文对象运行原始方法 legacyWidget.showModal.call(shinyNewWidget, "p");
如果你仍然对显式绑定感到困惑,请将其视为重用代码的基本模板。这种看起来有点繁琐冗长,但如果有遗留的JS代码需要重构,这种方式是非常合适的。
此外,你可能想知道什么是apply和bind。apply具有与call相同的效果,只是前者接受一个参数数组,而后者是参数列表。
var obj = { version: "0.0.1", printParams: function(param1, param2, param3) { console.log(this.version, param1, param2, param3); } }; var newObj = { version: "0.0.2" }; obj.printParams.call(newObj, "aa", "bb", "cc");
而apply需要一个参数数组
var obj = { version: "0.0.1", printParams: function(param1, param2, param3) { console.log(this.version, param1, param2, param3); } }; var newObj = { version: "0.0.2" }; obj.printParams.apply(newObj, ["aa", "bb", "cc"]);
那么bind呢? bind 是绑定函数最强大的方法。bind仍然为给定的函数接受一个新的上下文对象,但它不只是用新的上下文对象调用函数,而是返回一个永久绑定到该对象的新函数。
var obj = { version: "0.0.1", printParams: function(param1, param2, param3) { console.log(this.version, param1, param2, param3); } }; var newObj = { version: "0.0.2" }; var newFunc = obj.printParams.bind(newObj); newFunc("aa", "bb", "cc");
bind的一个常见用例是对原始函数的 this 永久重新绑定:
var obj = { version: "0.0.1", printParams: function(param1, param2, param3) { console.log(this.version, param1, param2, param3); } }; var newObj = { version: "0.0.2" }; obj.printParams = obj.printParams.bind(newObj); obj.printParams("aa", "bb", "cc");
从现在起obj.printParams 里面的 this 总是指向newObj。现在应该清楚为什么要在 React 使用 bind来重新绑定类方法了吧。
obj.printParams
newObj
class Button extends React.Component { constructor(props) { super(props); this.state = { text: "" }; this.handleClick = this.handleClick.bind(this); } handleClick() { this.setState(() => { return { text: "PROCEED TO CHECKOUT" }; }); } render() { return ( <button onClick={this.handleClick}> {this.state.text || this.props.text} </button> ); } }
但现实更为微妙,与“丢失绑定”有关。当咱们将事件处理程序作为一个prop分配给React元素时,该方法将作为引用而不是函数传递,这就像在另一个回调中传递事件处理程序引用:
prop
React
// 丢失绑定 const handleClick = this.handleClick; element.addEventListener("click", function() { handleClick(); });
赋值操作会破坏了绑定。在上面的示例组件中,handleClick方法(分配给button元素)试图通过调用this.setState()更新组件的状态。当调用该方法时,它已经失去了绑定,不再是类本身:现在它的上下文对象是window全局对象。此时,会得到"TypeError: Cannot read property 'setState' of undefined"的错误。
handleClick
button
this.setState()
"TypeError: Cannot read property 'setState' of undefined"
React组件大多数时候导出为ES2015模块:this未定义的,因为ES模块默认使用严格模式,因此禁用默认绑定,ES6 的类也启用严格模式。咱们可以使用一个模拟React组件的简单类进行测试。handleClick调用setState方法来响应单击事件
setState
class ExampleComponent { constructor() { this.state = { text: "" }; } handleClick() { this.setState({ text: "New text" }); alert(`New state is ${this.state.text}`); } setState(newState) { this.state = newState; } render() { const element = document.createElement("button"); document.body.appendChild(element); const text = document.createTextNode("Click me"); element.appendChild(text); const handleClick = this.handleClick; element.addEventListener("click", function() { handleClick(); }); } } const component = new ExampleComponent(); component.render();
错误的代码行是
const handleClick = this.handleClick;
然后点击按钮,查看控制台,会看到 ·"TypeError: Cannot read property 'setState' of undefined"·.。要解决这个问题,可以使用bind使方法绑定到正确的上下文,即类本身
constructor() { this.state = { text: "" }; this.handleClick = this.handleClick.bind(this); }
再次单击该按钮,运行正确。显式绑定比隐式绑定和默认绑定都更强。使用apply、call和bind,咱们可以通过为函数提供一个动态上下文对象来随意修改它。
构造函数模式,有助于用JS封装创建新对象的行为:
function Person(name, age) { this.name = name; this.age = age; } Person.prototype.greet = function() { console.log("Hello " + this.name); }; var me = new Person("Valentino"); me.greet(); // Output: "Hello Valentino"
这里,咱们为一个名为“Person”的实体创建一个蓝图。根据这个蓝图,就可以通过“new”调用“构造”Person类型的新对象:
为“Person
“new”
var me = new Person("Valentino");
在JS中有很多方法可以改变 this 指向,但是当在构造函数上使用new时,this 指向就确定了,它总是指向新创建的对象。在构造函数原型上定义的任何函数,如下所示
new
Person.prototype.greet = function() { console.log("Hello " + this.name); };
这样始终知道“this”指向是啥,因为大多数时候this指向操作的宿主对象。在下面的例子中,greet是由me的调用
“this”
greet
me
var me = new Person("Valentino"); me.greet(); // Output: "Hello Valentino"
由于me是通过构造函数调用构造的,所以它的含义并不含糊。当然,仍然可以从Person借用greet并用另一个对象运行它:
Person.prototype.greet.apply({ name: "Tom" }); // Output: "Hello Tom"
正如咱们所看到的,this非常灵活,但是如果不知道this所依据的规则,咱们就不能做出有根据的猜测,也不能利用它的真正威力。长话短说,this是基于四个“简单”的规则。
箭头函数的语法方便简洁,但是建议不要滥用它们。当然,箭头函数有很多有趣的特性。首先考虑一个名为Post的构造函数。只要咱们从构造函数中创建一个新对象,就会有一个针对REST API的Fetch请求:
Post
Fetch
"use strict"; function Post(id) { this.data = []; fetch("https://jsonplaceholder.typicode.com/posts/" + id) .then(function(response) { return response.json(); }) .then(function(json) { this.data = json; }); } var post1 = new Post(3);
上面的代码处于严格模式,因此禁止默认绑定(回到全局this)。尝试在浏览器中运行该代码,会报错:"TypeError: Cannot set property 'data' of undefined at :11:17"。
"TypeError: Cannot set property 'data' of undefined at :11:17"
这报错做是对的。全局变量 this 在严格模式下是undefined为什么咱们的函数试图更新 window.data而不是post.data?
window.data
原因很简单:由Fetch触发的回调在浏览器中运行,因此它指向 window。为了解决这个问题,早期有个老做法,就是使用临时亦是:“that”。换句话说,就是将this引用保存在一个名为that的变量中:
“that”
that
"use strict"; function Post(id) { var that = this; this.data = []; fetch("https://jsonplaceholder.typicode.com/posts/" + id) .then(function(response) { return response.json(); }) .then(function(json) { that.data = json; }); } var post1 = new Post(3);
如果不用这样,最简单的做法就是使用箭头函数:
"use strict"; function Post(id) { this.data = []; fetch("https://jsonplaceholder.typicode.com/posts/" + id) .then(response => { return response.json(); }) .then(json => { this.data = json; }); } var post1 = new Post(3);
问题解决。现在 this.data 总是指向post1。为什么? 箭头函数将this指向其封闭的环境(也称“词法作用域”)。换句话说,箭头函数并不关心它是否在window对象中运行。它的封闭环境是对象post1,以post1为宿主。当然,这也是箭头函数最有趣的用例之一。
post1
JS 中 this 是什么? 这得视情况而定。this 建立在四个规则上:默认绑定、隐式绑定、显式绑定和 “new”绑定。
隐式绑定表示当一个函数引用 this 并作为 JS 对象的一部分运行时,this 将指向这个“宿主”对象。但 JS 函数总是在一个对象中运行,这是任何全局函数在所谓的全局作用域中定义的情况。
在浏览器中工作时,全局作用域是 window。在这种情况下,在全局中运行的任何函数都将看到this 就是 window:它是 this 的默认绑定。
大多数情况下,不希望与全局作用域交互,JS 为此就提供了一种用严格模式来中和默认绑定的方法。在严格模式下,对全局对象的任何引用都是 undefined,这有效地保护了我们避免愚蠢的错误。
除了隐式绑定和默认绑定之外,还有“显式绑定”,我们可以使用三种方法来实现这一点:apply、call和bind。 这些方法对于传递给定函数应在其上运行的显式宿主对象很有用。
最后同样重要的是“new”绑定,它在通过调用“构造函数”时在底层做了五处理。对于大多数开发人员来说,this 是一件可怕的事情,必须不惜一切代价避免。但是对于那些想深入研究的人来说,this 是一个强大而灵活的系统,可以重用 JS 代码。
“new”绑定
代码部署后可能存在的BUG没法实时知道,事后为了解决这些BUG,花了大量的时间进行log 调试,这边顺便给大家推荐一个好用的BUG监控工具 Fundebug。
原文:https://github.com/valentinogagliardi/Little-JavaScript-Book/blob/v1.0.0/manuscript/README.md
阿里云最近在做活动,低至2折,有兴趣可以看看:https://promotion.aliyun.com/ntms/yunparter/invite.html?userCode=pxuujn3r
干货系列文章汇总如下,觉得不错点个Star,欢迎 加群 互相学习。
https://github.com/qq449245884/xiaozhi
因为篇幅的限制,今天的分享只到这里。如果大家想了解更多的内容的话,可以去扫一扫每篇文章最下面的二维码,然后关注咱们的微信公众号,了解更多的资讯和有价值的内容。
每次整理文章,一般都到2点才睡觉,一周4次左右,挺苦的,还望支持,给点鼓励
The text was updated successfully, but these errors were encountered:
谢谢作者。
Sorry, something went wrong.
No branches or pull requests
为了保证的可读性,本文采用意译而非直译。
揭秘 "this"
JS 中的
this
关键字对于初学者来说是一个谜,对于经验丰富的开发人员来说则是一个永恒的难题。this
实际上是一个移动的目标,在代码执行过程中可能会发生变化,而没有任何明显的原因。首先,看一下this
关键字在其他编程语言中是什么样子的。以下是 JS 中的一个
Person
类:Python
类也有一个跟this
差不多的东西,叫做self
:在Python类中,
self
表示类的实例:即从类开始创建的新对象PHP中也有类似的东西:
这里
$this
是类实例。再次使用JS类来创建两个新对象,可以看到每当咱们调用object.name
时,都会返回正确的名字:JS 中类似乎类似于Python、Java和PHP,因为
this
看起来似乎指向实际的类实例?这是不对的。咱们不要忘记JS不是一种面向对象的语言,而且它是宽松的、动态的,并且没有真正的类。
this
与类无关,咱们可以先用一个简单的JS函数(试试浏览器)来证明这一点:规则1:回到全局“this”(即默认绑定)
如果在浏览器中运行以下代码
输出如下:
如上所示,咱们当
this
没有在任何类中的时候,this
仍然有值。当一个函数在全局环境中被调用时,该函数会将它的this
指向全局对象,在咱们的例子中是window
。这是JS的第一条规则,叫作默认绑定。默认绑定就像一个回退,大多数情况下它是不受欢迎的。在全局环境中运行的任何函数都可能“污染”全局变量并破坏代码。考虑下面的代码:
第一个开发人员创建一个名为
globalSum
的全局变量,并为其分配一个函数。接着,另一个开发人员将null
分配给相同的变量,从而导致代码出现故障。处理全局变量总是有风险的,因此JS引入了**“安全模式”:严格模式。严格模式是通过使用
“use Strict”
启用。严格模式中的一个好处就是消除了默认绑定**。在严格模式下,当试图从全局上下文中访问this
时,会得到undefined
。严格的模式使JS代码更安全。
小结一下,默认绑定是JS中的第一条规则:当引擎无法找出
this
是什么时,它会返回到全局对象。接下看看另外三条规则。规则2: 当“this”是宿主对象时(即隐式绑定)
“隐式绑定”是一个令人生畏的术语,但它背后的理论并不那么复杂。它把范围缩小到对象。
当一个函数被赋值为一个对象的属性时,该对象就成为函数运行的宿主。换句话说,函数中的
this
将自动指向该对象。这是JS中的第二条规则,名为隐式绑定。即使在全局上下文中调用函数,隐式绑定也在起作用咱们无法从代码中看出,但是JS引擎将该函数分配给全局对象 window 上的一个新属性,如下所示:
咱们可以很容易地证实这个假设。在浏览器中运行以下代码:
打印
"function"
。对于这一点你可能会问:在全局函数中this
的真正规则是什么?像是缺省绑定,但实际上更像是隐式绑定。有点令人困惑,但只要记住,JS引擎在在无法确定上下文(默认绑定)时总是返回全局
this
。另一方面,当函数作为对象的一部分调用时,this
指向该调用的对象(隐式绑定)。规则 3: 显示指定 “this”(即显式绑定)
如果不是 JS 使用者,很难看到这样的代码:
这就是显式绑定,在 React 会经常看到这中绑定方式:
现在
React Hooks 使得类几乎没有必要了,但是仍然有很多使用ES6类的“遗留”React组件。大多数初学者会问的一个问题是,为什么咱们要在 React 中通过
bind` 方法重新绑定事件处理程序方法?call
、apply
、bind
这三个方法都属于Function.prototype
。用于的显式绑定(规则3):显式绑定指显示地将this
绑定到一个上下文。但为什么要显式绑定或重新绑定函数呢?考虑一些遗留的JS代码:showModal
是绑定到对象legacyWidget
的“方法”。this.html
属于硬编码,把创建的元素写死了(div)。这样咱们没有办法把内容附加到咱们想附加的标签上。解决方法就是可以使用显式绑定
this
来更改showModal
的对象。。现在,咱们可以创建一个小部件,并提供一个不同的HTML元素作附加的对象:接着,使用
call
调用原始的方法:如果你仍然对显式绑定感到困惑,请将其视为重用代码的基本模板。这种看起来有点繁琐冗长,但如果有遗留的JS代码需要重构,这种方式是非常合适的。
此外,你可能想知道什么是
apply
和bind
。apply
具有与call
相同的效果,只是前者接受一个参数数组,而后者是参数列表。而
apply
需要一个参数数组那么
bind
呢?bind
是绑定函数最强大的方法。bind
仍然为给定的函数接受一个新的上下文对象,但它不只是用新的上下文对象调用函数,而是返回一个永久绑定到该对象的新函数。bind
的一个常见用例是对原始函数的this
永久重新绑定:从现在起
obj.printParams
里面的this
总是指向newObj
。现在应该清楚为什么要在 React 使用bind
来重新绑定类方法了吧。但现实更为微妙,与“丢失绑定”有关。当咱们将事件处理程序作为一个
prop
分配给React
元素时,该方法将作为引用而不是函数传递,这就像在另一个回调中传递事件处理程序引用:赋值操作会破坏了绑定。在上面的示例组件中,
handleClick
方法(分配给button
元素)试图通过调用this.setState()
更新组件的状态。当调用该方法时,它已经失去了绑定,不再是类本身:现在它的上下文对象是window
全局对象。此时,会得到"TypeError: Cannot read property 'setState' of undefined"
的错误。React组件大多数时候导出为ES2015模块:
this
未定义的,因为ES模块默认使用严格模式,因此禁用默认绑定,ES6 的类也启用严格模式。咱们可以使用一个模拟React组件的简单类进行测试。handleClick
调用setState
方法来响应单击事件错误的代码行是
然后点击按钮,查看控制台,会看到 ·"TypeError: Cannot read property 'setState' of undefined"·.。要解决这个问题,可以使用
bind
使方法绑定到正确的上下文,即类本身再次单击该按钮,运行正确。显式绑定比隐式绑定和默认绑定都更强。使用
apply
、call
和bind
,咱们可以通过为函数提供一个动态上下文对象来随意修改它。规则 4:"new" 绑定
构造函数模式,有助于用JS封装创建新对象的行为:
这里,咱们为一个名
为“Person
”的实体创建一个蓝图。根据这个蓝图,就可以通过“new”
调用“构造”Person
类型的新对象:在JS中有很多方法可以改变
this
指向,但是当在构造函数上使用new
时,this
指向就确定了,它总是指向新创建的对象。在构造函数原型上定义的任何函数,如下所示这样始终知道
“this”
指向是啥,因为大多数时候this
指向操作的宿主对象。在下面的例子中,greet
是由me
的调用由于
me
是通过构造函数调用构造的,所以它的含义并不含糊。当然,仍然可以从Person
借用greet
并用另一个对象运行它:正如咱们所看到的,
this
非常灵活,但是如果不知道this
所依据的规则,咱们就不能做出有根据的猜测,也不能利用它的真正威力。长话短说,this
是基于四个“简单”的规则。箭头函数和 "this"
箭头函数的语法方便简洁,但是建议不要滥用它们。当然,箭头函数有很多有趣的特性。首先考虑一个名为
Post
的构造函数。只要咱们从构造函数中创建一个新对象,就会有一个针对REST API的Fetch
请求:上面的代码处于严格模式,因此禁止默认绑定(回到全局
this
)。尝试在浏览器中运行该代码,会报错:"TypeError: Cannot set property 'data' of undefined at :11:17"
。这报错做是对的。全局变量
this
在严格模式下是undefined
为什么咱们的函数试图更新window.data
而不是post.data?原因很简单:由Fetch触发的回调在浏览器中运行,因此它指向 window。为了解决这个问题,早期有个老做法,就是使用临时亦是:
“that”
。换句话说,就是将this
引用保存在一个名为that
的变量中:如果不用这样,最简单的做法就是使用箭头函数:
问题解决。现在 this.data 总是指向
post1
。为什么? 箭头函数将this
指向其封闭的环境(也称“词法作用域”)。换句话说,箭头函数并不关心它是否在window
对象中运行。它的封闭环境是对象post1
,以post1
为宿主。当然,这也是箭头函数最有趣的用例之一。总结
JS 中
this
是什么? 这得视情况而定。this
建立在四个规则上:默认绑定、隐式绑定、显式绑定和 “new”绑定。隐式绑定表示当一个函数引用
this
并作为 JS 对象的一部分运行时,this
将指向这个“宿主”对象。但 JS 函数总是在一个对象中运行,这是任何全局函数在所谓的全局作用域中定义的情况。在浏览器中工作时,全局作用域是
window
。在这种情况下,在全局中运行的任何函数都将看到this
就是window
:它是this
的默认绑定。大多数情况下,不希望与全局作用域交互,JS 为此就提供了一种用严格模式来中和默认绑定的方法。在严格模式下,对全局对象的任何引用都是
undefined
,这有效地保护了我们避免愚蠢的错误。除了隐式绑定和默认绑定之外,还有“显式绑定”,我们可以使用三种方法来实现这一点:
apply
、call
和bind
。 这些方法对于传递给定函数应在其上运行的显式宿主对象很有用。最后同样重要的是
“new”绑定
,它在通过调用“构造函数”时在底层做了五处理。对于大多数开发人员来说,this
是一件可怕的事情,必须不惜一切代价避免。但是对于那些想深入研究的人来说,this
是一个强大而灵活的系统,可以重用 JS 代码。代码部署后可能存在的BUG没法实时知道,事后为了解决这些BUG,花了大量的时间进行log 调试,这边顺便给大家推荐一个好用的BUG监控工具 Fundebug。
原文:https://github.com/valentinogagliardi/Little-JavaScript-Book/blob/v1.0.0/manuscript/README.md
交流
阿里云最近在做活动,低至2折,有兴趣可以看看:https://promotion.aliyun.com/ntms/yunparter/invite.html?userCode=pxuujn3r
干货系列文章汇总如下,觉得不错点个Star,欢迎 加群 互相学习。
因为篇幅的限制,今天的分享只到这里。如果大家想了解更多的内容的话,可以去扫一扫每篇文章最下面的二维码,然后关注咱们的微信公众号,了解更多的资讯和有价值的内容。
每次整理文章,一般都到2点才睡觉,一周4次左右,挺苦的,还望支持,给点鼓励
The text was updated successfully, but these errors were encountered: