转的es6 =>函数
箭头函数=>无疑是ES6中最受关注的一个新特性了,通过它可以简写 function 函数表达式,你也可以在各种提及箭头函数的地方看到这样的观点——“=> 就是一个新的 function”。
箭头函数的句法规则甚至早已延伸到各项标准和技术文档中去了,虽然它早已不稀奇,却给我们一种刚刚发现的新鲜感。
粉我的人都知道俺因为某些原因不怎么喜欢 => 的语法,不过别担心,本文并非讲述我为何不喜欢它,如果你对这个观点感兴趣,可以查看我《YDKJS:ES6 & Beyonf》一书的第二章。
我想在这里理清一下箭头函数到底对 this 和 arguments 等东东做了些啥,事实上我在之前从未准确解释过这一点,对此感到有点愧疚,于是乎想洗白下自己。你可以在这里看到我对于该话题的第一次陈述。
是否局部(Lexical)?
包括我在内的许多人,都会这么描述箭头函数里 this 的行为:局部的 this。
什么意思呢?
复制代码
function foo() {
setTimeout( () => {
console.log("id:", this.id);
},100);
}
foo.call( { id: 42 } );
// id: 42
复制代码
这里的 => 箭头函数看起来把它内部的 this 绑定为父函数 foo() 里的 this。如果这个内部函数是一个常规的函数(声明或表达式),它的 this 将类似 setTimeout 如何调用函数一样被控制着。如果你对 this 绑定的规则还不清楚,可以查阅我《YDKJS:this & Object Prototypes》一书的第二章。
局部变量 this
一个描述 this 行为观察的常用伎俩是:
复制代码
function foo() {
var self = this;
setTimeout(function() {
console.log("id:", self.id);
},100);
}
foo.call( { id: 42 } );
// id: 42
复制代码
旁注:上方“self”的变量名其实是一个非常糟糕、容易误解的名字,它意味着把 this 指向函数自己,而它并没有这么做。
var that = this 也是一个同样不妥的语义,特别当存在多个作用域而使用(that1, that2, ...)的时候更糟糕。如果你想起个语义妥当的好名字,可以试试 var context = this,因为它能准确描述 this 是什么——一个动态的上下文。
从上方的代码段我们可以看到,我们并没有在内部函数中使用到 this,取而代之的是一个更具预见性的局部变量。我们在外部函数中声明了变量 self,简单地关联了内部函数里用到的变量。
这么一来我们通过使用局部作用域以及闭包的原理,彻底地绕过方程式(示例代码中的内部函数)中绑定 this 的规则。
这样的结果看起来跟 => 箭头函数是一样的,换句话说,我们会(错误地)认为 => 箭头函数有着一个跟局部变量/闭包机制一样的“局部 this”行为。
但这种观点并不正确,坑爹了。
箭头函数的this绑定
咱可通过另一个方法来观察箭头函数中 this 的行为——给内部函数做一个强制绑定:
复制代码
function foo() {
setTimeout(function() {
console.log("id:", this.id);
}.bind(this),100);
}
foo.call( { id: 42 } );
// id: 42
复制代码
你可以看到我们使用了 .bind(this) 来把内部函数中的 this 绑定到了外部函数去,这样一来无论 setTimeout 会选择如何调用赋予它的函数,该函数都会使用 foo() 里所使用到的 this。
是的,这个版本的代码中我们观测到的行为跟之前两段示例代码所要论述的一样,它更准确么?许多童鞋都认为 => 箭头函数就是这么工作的。
啧啧~图样图森破了~
生来局部
TC39的常客 Dave Herman 曾更仔细、准确地向我阐述过这个问题,但我很愧疚一直没能完全了解他所陈述的含义,因此对于我往日不准确的言论我就更感歉意了,也更能接纳他人的观点。
Dave 主要对我这么说,“你提及的'局部 this'的描述很蹩脚,因为 this 无论如何都是局部的”。
真的么?嗯哼~
他继续说道,“箭头函数 => 所改变的并非把 this 局部化,而是完全不把 this 绑定到里面去”。
等等,这样合理么?我明明可以在 => 箭头函数里使用 this 的不是么?
当然可以,不过一切是这么发生的 —— 虽然 => 箭头函数没有一个自己的 this,但当你在内部使用了 this,常规的局部作用域准则就起作用了,它会指向最近一层作用域内的 this。
来个示例:
复制代码
function foo() {
return () => {
return () => {
return () => {
console.log("id:", this.id);
};
};
};
}
foo.call( { id: 42 } )()()();
// id: 42
复制代码
思考下,在这段代码中,
有多少次 this 的绑定执行了呢?大部分人会认为有4次——每个函数里各一次。
事实上更准确地说,只有一次才对,它发生于 foo() 函数中。
这些接连内嵌的函数们都没有声明它们自己的 this,所以 this.id 的引用会简单地顺着作用域链查找,一直查到 foo() 函数,它是第一处能找到一个确切存在的 this 的地方。
说白了跟其它局部变量的常规处理是一致的!
换句话说,正如同 Dave 说的一样,this 生来局部,而且一直都保持局部态。=>箭头函数并不会绑定一个 this 变量,它的作用域会如同寻常所做的一样一层层地去往上查找。
不仅仅是this
如果你贸贸然地同意了“箭头函数就是常规function的语法糖”这样的观点,那是不正确的,因为事实并非如此——箭头函数里并不按常规支持 var self = this 或者 .bind(this) 这样的糖果。
那些错误的解释都是典型的“给对了答案却讲错了原因”,就像你在高中代数课的测试上明明写对了答案,但老师仍会画圈圈告诉你用错方法了——如何解得答案才是最重要的!
另外,关于“=>箭头函数不绑定自身的 this,而允许局部作用域的方案来沿袭处理之”的正确描述,也解释了箭头函数的另一个情况——它们在函数内部不走寻常路的孩子不仅仅是 this。
事实上 =>箭头函数并不绑定 this,arguments,super(ES6),抑或 new.target(ES6)。
这是真的,对于上述的四个(未来可能有更多)地方,箭头函数不会绑定那些局部变量,所有涉及它们的引用,都会沿袭向上查找外层作用域链的方案来处理。
思考下这段代码:
复制代码
function foo() {
setTimeout( () => {
console.log("args:", arguments);
},100);
}
foo( 2, 4, 6, 8 );
// args: [2, 4, 6, 8]
复制代码
这段代码中,=>箭头函数并没有绑定 arguments,所以它会以 foo() 的 arguments 来取而代之,而 super 和 new.target 也是一样的情况。
总结
不要不经思考就轻易接受那些不准确的答案,不用满足于那些通过错误形式获取到的正确答案。
这关系到了事物是怎样作业的,以及你使用了怎样的心智模型(mental model),你会使用这种心智模型去分析、描述和调试其它的行为,如果你在一开始的时候就偏离了轨道,那么在之后你也只会一直停留在错误的轨道上。
我后悔当初没有更仔细地聆听 Dave 的观点,也好希望当初自己木有发表过关于=>箭头函数的错误言论。我会在今后思考、提笔、传道JS的时候更加严格地确保其正确性,也会让自己更加小心谨慎。
----------------------------------------------以下给出2个例子----------------------------
function a(){
this.a = 1;
setTimeout(()=>{
setTimeout(()=>{
console.log(this.a)
})
})
}
--------------------------------------------------------------------------------------------------
function a(){
this.a = 1;
setTimeout(functiion(){
setTimeout(()=>{
console.log(this.a)
})
})
}
---------------------------------------------------------------------------
这里要说的是,普通匿名函数也是函数,它也会函数提升的,还有就是沿着作用域链往上找,找到this就停止了。。。。。
转的es6 =>函数的更多相关文章
- ES6函数扩展
前面的话 函数是所有编程语言的重要组成部分,在ES6出现前,JS的函数语法一直没有太大的变化,从而遗留了很多问题和的做法,导致实现一些基本的功能经常要编写很多代码.ES6大力度地更新了函数特性,在ES ...
- 深入理解javascript函数系列第四篇——ES6函数扩展
× 目录 [1]参数默认值 [2]rest参数 [3]扩展运算符[4]箭头函数 前面的话 ES6标准关于函数扩展部分,主要涉及以下四个方面:参数默认值.rest参数.扩展运算符和箭头函数 参数默认值 ...
- ES6函数剩余参数(Rest Parameters)
我们知道JS函数内部有个arguments对象,可以拿到全部实参.现在ES6给我们带来了一个新的对象,可以拿到除开始参数外的参数,即剩余参数(废话好多 O(∩_∩)O~). 这个新的对象和argume ...
- ES6函数默认参数(Default Parameters)
语言更新时每一个新增的特性都是从千百万开发者需求里提取过来的,规范采用后能减少程序员的痛苦,带来便捷. 我们经常会这么写 function calc(x, y) { x = x || 0; y = y ...
- es6函数的rest参数和拓展运算符(...)的解析
es6的新特性对函数的功能新增加了rest参数和...的拓展运算符.这是两个什么东西呢? 先来看一个问题:如何获取一个函数除了定义的参数之外的其他参数?传统的做法是借助函数的arguments关键字来 ...
- ES6函数的拓展
ES里面现在支持在函数的参数直接给参数赋一个默认值,ES6支持拓展运算符(...)三个英文的点,这个形式如function(...a)这个里面...a可以接受若干的值,这个拓展运算符也可以把若干的值转 ...
- ES6 函数的扩展1
1. 函数参数的默认值 基本用法 在ES6之前,不能直接为函数的参数指定默认值,为了避免这个问题,通常需要先判断一下参数y是否被赋值,如果没有,再等于默认值. ES6允许为函数的参数设置默认值,即直接 ...
- ES6 函数的扩展3
箭头函数 基本用法 ES6允许使用"箭头"(=>)定义函数 var f = v => v; 上面的箭头函数等同于: var f = function(v) { retu ...
- ES6 函数的扩展2
8.2 rest参数 ES6引入rest参数(形式为"-变量名"),用于获取函数的多余参数,这样就不需要使用arguments对象了. arguments对象并没有数组的方法,re ...
- ES6 函数的扩展(1)
1. 函数参数的默认值 基本用法 在ES6之前,不能直接为函数的参数指定默认值,为了避免这个问题,通常需要先判断一下参数y是否被赋值,如果没有,再等于默认值. ES6允许为函数的参数设置默认值,即直接 ...
随机推荐
- Spring事务管理之声明式事务管理:基于TransactionProxyFactoryBean的方式
© 版权声明:本文为博主原创文章,转载请注明出处 案例 - 利用Spring的声明式事务(TransactionProxyFactoryBean)管理模拟转账过程 数据库准备 -- 创建表 CREAT ...
- Linux基础ls命令
ls 命令是linux下最常用的命令,通过ls 命令不仅可以查看linux文件夹包含的文件而且可以查看文件权限(包括目录.文件夹.文件权限)查看目录信息等等.ls 命令在日常的linux操作中用的 ...
- CSS基础2——选择器
前面说过样式规则.也知道了样式规则语法形式为:选择器+声明块 如:div{ color:black:padding:10px; } div即表示选择器(此处是元素选择器),花括号里的内容就是声明块 ...
- CentOS: Make Command not Found and linux xinetd 服务不能启动
在centos 安装编译器 yum -y install gcc automake autoconf libtool make linux xinetd 服务不能启动: [root@capaa xin ...
- FILE 创建
public class CreateDelFileUtils implements Serializable{ /** * */ private static final long serialVe ...
- Java多线程中的竞争条件、锁以及同步的概念
竞争条件 1.竞争条件: 在java多线程中,当两个或以上的线程对同一个数据进行操作的时候,可能会产生“竞争条件”的现象.这种现象产生的根本原因是因为多个线程在对同一个数据进行操作,此时对该数据的操作 ...
- python selenium - SSL处理(https)
在实际的自动化测试实践中,因为越来越多的站点接入https,使得我们原有的python selenium2自动化测试代码进行测试时,浏览器总是报安全问题,即便在浏览器选项中将被测网址加入信任网址也没用 ...
- Live555 中的客户端openRTSP 保存H264文件
http://amitapba.blog.163.com/blog/static/20361020720140189239762/ http://amitapba.blog.163.com/blog/ ...
- python高级-------python2.7教程学习【廖雪峰版】(四)
2017年6月9日17:57:55 任务: 看完高级部分 笔记:1.掌握了Python的数据类型.语句和函数,基本上就可以编写出很多有用的程序了.2.在Python中,代码不是越多越好,而是越少越好. ...
- 自定义tabpageindicator,可以自定义tab是三角形还是矩形,但是tab不具有滑动的功能
我是不会滴,但是看了一些大神写的,我修改了一下,大家可以参照参照 一,自定义Mytabpageindicator,直接贴代码了,具体的在代码中有注释 package com.wangy.mytabpa ...