Discuss / JavaScript / 感觉这篇博客做出的解释会比较清晰点。

感觉这篇博客做出的解释会比较清晰点。

Topic source

viper1090

#1 Created at ... [Delete] [Delete and Lock User]

https://github.com/zhengweikeng/blog/blob/master/posts/2016/%E7%AE%AD%E5%A4%B4%E5%87%BD%E6%95%B0%E4%B8%ADthis%E7%9A%84%E7%94%A8%E6%B3%95.md

我个人比较好的建议是:先理解一下什么叫词法作用域,然后理解Arrow Function是如何解释词法作用域的。

其实 var obj = { birth: 1990, getAge: function (year) { var b = this.birth; // 1990 var fn = (y) => y - this.birth; // this.birth仍是1990 return fn.call({birth:2000}, year); } }; obj.getAge(2015); // 25

中的getAge就是将箭头函数放置在了一个普通函数中,箭头函数在定义时根据词法作用域绑定了getAge函数的this,而getAge函数是在调用的时候绑定的obj,所以obj.getAge(2015)的内部的箭头函数绑定的就是obj自身。

viper1090

#2 Created at ... [Delete] [Delete and Lock User]

额,最后的描述有误"getAge就是将箭头函数放置在了一个普通函数中,箭头函数在定义时根据词法作用域绑定了getAge函数的this,而getAge函数是在调用的时候绑定的obj,所以obj.getAge(2015)的内部的箭头函数绑定的就是obj自身",这里应该描述成:“getAge就是将箭头函数放置在了一个普通函数中,箭头函数在定义时根据词法作用域绑定了getAge函数的this,也就是ob“,”而getAge函数是在调用的时候绑定的obj“的描述是错误的,因为getAage函数在调用时依然是window在调用。

悵空

#3 Created at ... [Delete] [Delete and Lock User]

不对哦,调用getAge方法的是obj。所以getAge函数的this才指向了obj。而箭头函数的词法作用域就是getAge(),所以箭头函数的this就是getAge()中的this

狮子云湮

#4 Created at ... [Delete] [Delete and Lock User]

我觉得应该是运行普通函数getAge()的调用方法是通过dot(.)调用的,所以也创建了它的this对象(指向dot(.)之前的obj),而getAge()里的箭头函数的this是通过向上查找找到getAge()有this对象,所以就绑定了getAge()的this对象;

viper1090

#5 Created at ... [Delete] [Delete and Lock User]

上面两位。我的理解没问题。首先调用函数和绑定上下文的this是不一样的,可我可以通过window调用一个函数,但是可以将他的上下文的this,绑定到其他对象里。比如下面的例子: function taskA() { var arrow_fn = () => { console.log(this) console.log(this.name) } arrow_fn() } var obj = {name: 'Jack'} taskA.bind(obj)()

上面的taskA.bind(obj)()等同与window.taskA.bind(obj)().只不过它将函数的上下文this绑定了obj中,而不是obj调用了函数。

同样的上面例子中的obj.getAge(2015);其实可以写成: var fn = obj.getAge; fn(2015); 而fn()其实是window在调用。obj.getAge(2015);其实不有两层含义,1、通过obj.getAge拿到,函数指针,2、然后调用函数实现。

viper1090

#6 Created at ... [Delete] [Delete and Lock User]

我的理解是:js本身就是词法作用域,不存在什么动态作用域一说。不论是箭头函数还是其他普通函数,它们的上下文this,一开始就是定义好的。 我们可以分析以下两种情况: 1.完全明确的定义了父函数中的this。 var obj = { birth: 1990, getAge: function (year) { var b = this.birth; // 1990 var fn = (y) => y - this.birth; // this.birth仍是1990 return fn.call({birth:2000}, year); } }; 比如上面例子中的fn,他的this开始就已经定义好了,和getAge指向的函数中的this一直。而getAge为fn的父函数,它的this,一开始就确定为了obj,所以。fn中的this,直接指向了obj,而后面的fn.call({birth:2000},year)是无效的绑定。

2.父函数的this并没有明确指定(其实默认指定的是window)。比如下面的例子: function taskA() { var arrow_fn = () => { console.log(this) console.log(this.name) } arrow_fn() } var obj = {name: 'Jack'} taskA.bind(obj)() 同上一样arrow_fn的this和taskA的this默认情况下都是window,但是taskA.bind(obj)()将taskA的上下文绑定到了obj。 总而言之,对于箭头函数的在定义的时候就明确了this的绑定,其实指的就是在箭头函数定义的时候它的this其实和父函数的this是一致的,至于父函数的this具体是如何绑定的,得看上面的1,2来分析了。

viper1090

#7 Created at ... [Delete] [Delete and Lock User]

比如上面链接中的一个例子: var obj = { field: 'hello', getField: () => { console.log(this.field) } } obj.getField() // undefined

上面的obj.getField(),并没有和想像中的一样,输出hello。是不是很奇怪。其实一点都不奇怪,因为getField: () => { console.log(this.field) }首先该箭头函数没有父函数,也就找不到父作用域。这时候的this,默认绑定的就是window。所以输出undefined一点都不奇怪。改成这样就行了: var obj = { field: 'hello', getField(){ console.log(this.field) } } 所以我们一般不建议对象中定义函数的时候使用Arrow Function,毕竟this就会造成错误了。要么写成上面的方式,要么就将箭头函数包裹在一个父函数中,让父函数的this有明确指定。

viper1090

#8 Created at ... [Delete] [Delete and Lock User]

可能有人会对“js本身就是词法作用域,不存在什么动态作用域一说。”这句话有疑问。比如下面的例子: var obj = { birth: 1990, getAge: function () { var b = this.birth; // 1990 var fn = function () { return new Date().getFullYear() - this.birth; // this指向window或undefined }; return fn(); } };

有的人说既然js都是词法作用域,那么我这么理解:“fn的父作用域为getAge的作用域,而getAge的作用域里的this就是obj,在fn中没有找到this.brith,那我就往getAge上找,发现他有this.brith,为什么不能在实际情况下限还是window和undefined? 如果把fn中的return new Date().getFullYear() - this.birth;,改成“return new Date().getFullYear() - b;”就可以解释了,改成b后我们就会输出正常的结果,满足词法作用域的解释。箭头函数可以直接绑定父函数作用域中的this,如果没有副函数直接绑定window或undefined,对于普通函数一般的变量都是词法作用域的,找不到该变量就向父作用域查找,但对于this并不是普通函数的this,是根据调用时的上下文决定的,我们用obj.getAge(),其实就是先通过obj.getAge找到函数的指针地址,然后用window进行调用。

这位同学写了自己相当详细的理解,但是对于this指向的还是需要再多消化一下。 其中最为严重的错误是“不论是箭头函数还是其他普通函数,它们的上下文this,一开始就是定义好的。” JS确实是词法作用域,所以作用域是在编译阶段就确定的,但是this是动态,所以箭头函数this会和自己的宿主保持一致,而宿主的this是可以动态变化的。基于这个逻辑基点,你的推导过程和结论都是有不少问题的。附上一段代码供参考:

var obj = {
    birth: 1990,
    getAge: function (year) {
        var b = this.birth; 
        var fn = (y) => y - this.birth; 
        return fn.call({birth:2000}, year);
    }
};
obj.getAge.call({birth:2000},2015); //15

var fn = obj.getAge;
fn();//NaN

  • 1

Reply