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
昨天面试的时候问了一个关于箭头函数的问题,回来发现好像自己说错了(装逼失败),于是便重新认识一下这个 ES6 用得最多的东西。
这段时间面试了很多人,当问到箭头函数带来的好处时,大部分人都只说到了写得少(???) ,不需要用 that、self 之类的变量,可以直接使用 this。但当细问下去,其实很多人不了解箭头函数的 this 就是是啥回事(或者包括我自己
that
self
this
先说说在此之前我对箭头函数的理解吧:箭头函数里的 this 是「继承」的,本身不存在自己的 this,当调用到 this 时用的其实是上一层作用域的 this。现在看来这个理解还是有一定偏差。
摘录一段犀牛书的代码,就能很好说明闭包和词法作用域的问题了:
var scope = 'global scope'; function checkscope() { var scope = 'local scope'; function f() { return scope; } return f; } checkscope()();
这里返回的是 'local scope',是因为在函数 f 函数体内访问 scope 变量时,会沿着从 f 开始的作用域链往上查找,因此第一个查找到的变量是在 checkscope 作用域内定义的 scope。
'local scope'
scope
checkscope
注意无论 f 在何时何地调用,返回的 scope 总是 'local scope',这是由于作用域查找总是从 f 开始,因此 scope 的值通过词法作用域确定了。
在 ES5 中,函数中的 this 是动态变化的,会根据调用方式的不同产生不同的绑定,只有在被调用时才能确定 this 的值:
window
call
apply
用代码说明一下:
function f(change) { if (change) { this.a = 300; } console.log(this.a); } var a = 100; var obj = { a: 200 }; // 普通调用,输出 100 f(); // 方法调用,输出 200 obj.f = f; obj.f(); // 构造函数调用,改变的是新对象的 a,输出 300, 100, 300 var newObj = new f(true); console.log(a); console.log(newObj.a);
先看 MDN 的说明:MDN - 箭头函数,其实写得很清楚了。关键在于箭头函数的 this 是词法作用域绑定这个概念。这意味着箭头函数的 this 类似于一个变量,在定义的时候就已经确定了指向的上下文,而非动态获取。看个例子:
var a = 100; var obj1 = { a: 200, b: () => { console.log(this.a); } }; obj1.b(); var obj2 = { a: 200, b: function () { var f = () => { console.log(this.a); } f(); } }; obj2.b(); var ff = obj2.b; ff();
在箭头函数中,this 可以看成是一个变量,而非关键字,箭头函数本身作用域里并没有 this 的定义,当引用 this 时,会沿着作用域链往上查找(跟闭包那个 scope 好像哦)。
因此例子中的 obj1.b() 跟 obj2.b() 输出分别为 100 和 200,由于 obj1.b 在查找 this 时会一直查找到全局作用域,因此 this.a = 100;而 obj2.b 在 function 作用域就找到了 this(注意使用了 function 定义了函数),而这时的 this 为方法调用的对象 obj2,因此 this.a = 200。
obj1.b()
obj2.b()
obj1.b
this.a = 100
obj2.b
function
obj2
this.a = 200
进一步说明这种作用域查找规则的是下面两行,输出是 100. 由于此时 obj2.b 的调用是一个普通函数调用,因此 this 的值是全局对象,所以输出的是 window.a 了。
window.a
在了解到箭头函数内部的 this 其实是一个词法绑定的变量时,我不禁怀疑这个箭头函数究竟是个啥,甚至于它是不是一个函数,有没有自己的作用域?
以前很多对箭头函数的简单解释是「JavaScript 函数的语法糖」,根据前文所述的 this 获取值的不同,已经知道箭头函数与普通函数其实有很大的不同,于是尝试一下:
var f = () => {}; // 'function' typeof f; // true f instanceof Function; // true f.__proto__ === Function.prototype; // 根据 MDN,箭头函数没有原型:undefined f.prototype
各种证据表明这个箭头函数的确是一个「函数」,只是没有原型对象,因此也就无法作为构造函数调用(new f())。另外 MDN 提到,箭头函数内除了 this,还有其他普通函数中常用的变量如 arguments 也是词法绑定的,这些变量在箭头函数调用时是沿着作用域链向上查找的。
new f()
arguments
14.2.16 Runtime Semantics: Evaluation
里面的 Note 提到箭头函数没有对 this 进行 local binding(本地绑定),这些变量的绑定是在 lexically enclosing environment 中进行的,实际上就是包含箭头函数定义的函数执行环境中定义的,这与我们上文的结论一致。
The text was updated successfully, but these errors were encountered:
No branches or pull requests
昨天面试的时候问了一个关于箭头函数的问题,回来发现好像自己说错了(装逼失败),于是便重新认识一下这个 ES6 用得最多的东西。
这段时间面试了很多人,当问到箭头函数带来的好处时,大部分人都只说到了写得少(???)
,不需要用
that
、self
之类的变量,可以直接使用this
。但当细问下去,其实很多人不了解箭头函数的this
就是是啥回事(或者包括我自己先说说在此之前我对箭头函数的理解吧:箭头函数里的
this
是「继承」的,本身不存在自己的this
,当调用到this
时用的其实是上一层作用域的this
。现在看来这个理解还是有一定偏差。闭包与词法作用域
摘录一段犀牛书的代码,就能很好说明闭包和词法作用域的问题了:
这里返回的是
'local scope'
,是因为在函数 f 函数体内访问scope
变量时,会沿着从 f 开始的作用域链往上查找,因此第一个查找到的变量是在checkscope
作用域内定义的scope
。注意无论 f 在何时何地调用,返回的
scope
总是'local scope'
,这是由于作用域查找总是从 f 开始,因此scope
的值通过词法作用域确定了。Function 的 this
在 ES5 中,函数中的
this
是动态变化的,会根据调用方式的不同产生不同的绑定,只有在被调用时才能确定this
的值:window
)call
、apply
调用,为绑定的值(第一个参数)用代码说明一下:
Arrow Function 的 this
先看 MDN 的说明:MDN - 箭头函数,其实写得很清楚了。关键在于箭头函数的
this
是词法作用域绑定这个概念。这意味着箭头函数的this
类似于一个变量,在定义的时候就已经确定了指向的上下文,而非动态获取。看个例子:在箭头函数中,
this
可以看成是一个变量,而非关键字,箭头函数本身作用域里并没有this
的定义,当引用this
时,会沿着作用域链往上查找(跟闭包那个scope
好像哦)。因此例子中的
obj1.b()
跟obj2.b()
输出分别为 100 和 200,由于obj1.b
在查找this
时会一直查找到全局作用域,因此this.a = 100
;而obj2.b
在function
作用域就找到了this
(注意使用了function
定义了函数),而这时的this
为方法调用的对象obj2
,因此this.a = 200
。进一步说明这种作用域查找规则的是下面两行,输出是 100. 由于此时
obj2.b
的调用是一个普通函数调用,因此this
的值是全局对象,所以输出的是window.a
了。Arrow Function 到底是啥
在了解到箭头函数内部的
this
其实是一个词法绑定的变量时,我不禁怀疑这个箭头函数究竟是个啥,甚至于它是不是一个函数,有没有自己的作用域?以前很多对箭头函数的简单解释是「JavaScript 函数的语法糖」,根据前文所述的
this
获取值的不同,已经知道箭头函数与普通函数其实有很大的不同,于是尝试一下:各种证据表明这个箭头函数的确是一个「函数」,只是没有原型对象,因此也就无法作为构造函数调用(
new f()
)。另外 MDN 提到,箭头函数内除了this
,还有其他普通函数中常用的变量如arguments
也是词法绑定的,这些变量在箭头函数调用时是沿着作用域链向上查找的。看看规范
14.2.16 Runtime Semantics: Evaluation
里面的 Note 提到箭头函数没有对
this
进行 local binding(本地绑定),这些变量的绑定是在 lexically enclosing environment 中进行的,实际上就是包含箭头函数定义的函数执行环境中定义的,这与我们上文的结论一致。The text was updated successfully, but these errors were encountered: