咱们先来回顾下箭头函数的基本语法。
ES6 增长了箭头函数:html
var f = v => v; // 等同于 var f = function (v) { return v; };
若是箭头函数不须要参数或须要多个参数,就使用一个圆括号表明参数部分。react
var f = () => 5; // 等同于 var f = function () { return 5 }; var sum = (num1, num2) => num1 + num2; // 等同于 var sum = function(num1, num2) { return num1 + num2; };
因为大括号被解释为代码块,因此若是箭头函数直接返回一个对象,必须在对象外面加上括号,不然会报错。git
// 报错 let getTempItem = id => { id: id, name: "Temp" }; // 不报错 let getTempItem = id => ({ id: id, name: "Temp" });
下面是一种特殊状况,虽然能够运行,但会获得错误的结果。github
let foo = () => { a: 1 }; foo() // undefined
上面代码中,原始意图是返回一个对象{ a: 1 },可是因为引擎认为大括号是代码块,因此执行了一行语句a: 1。这时,a能够被解释为语句的标签,所以实际执行的语句是1;,而后函数就结束了,没有返回值。ajax
关于做用域json
箭头函数内定义的变量及其做用域 // 常规写法 var greeting = () => {let now = new Date(); return ("Good" + ((now.getHours() > 17) ? " evening." : " day."));} greeting(); //"Good day." console.log(now); // ReferenceError: now is not defined 标准的let做用域 // 参数括号内定义的变量是局部变量(默认参数) var greeting = (now=new Date()) => "Good" + (now.getHours() > 17 ? " evening." : " day."); greeting(); //"Good day." console.log(now); // ReferenceError: now is not defined // 对比:函数体内{}不使用var定义的变量是全局变量 var greeting = () => {now = new Date(); return ("Good" + ((now.getHours() > 17) ? " evening." : " day."));} greeting(); //"Good day." console.log(now); // Fri Dec 22 2017 10:01:00 GMT+0800 (中国标准时间) // 对比:函数体内{} 用var定义的变量是局部变量 var greeting = () => {var now = new Date(); return ("Good" + ((now.getHours() > 17) ? " evening." : " day."));} greeting(); //"Good day." console.log(now); // ReferenceError: now is not defined
箭头函数没有 this,因此须要经过查找做用域链来肯定 this 的值。
这就意味着若是箭头函数被非箭头函数包含,this 绑定的就是最近一层非箭头函数的 this。app
function foo() { setTimeout(() => { console.log('id:', this.id); }, 100); } var id = 21; foo.call({ id: 42 }); // id: 42
上面代码中,setTimeout
的参数是一个箭头函数,这个箭头函数的定义生效是在foo
函数生成时,而它的真正执行要等到 100
毫秒后。若是是普通函数,执行时this
应该指向全局对象window
,这时应该输出21
。可是,箭头函数致使this老是指向函数定义生效时所在的对象(本例是{id: 42}
),因此输出的是42
。
箭头函数可让setTimeout
里面的this
,绑定定义时所在的做用域,而不是指向运行时所在的做用域。函数
因此,箭头函数转成 ES5 的代码以下。性能
// ES6 function foo() { setTimeout(() => { console.log('id:', this.id); }, 100); } // ES5 function foo() { var _this = this; setTimeout(function () { console.log('id:', _this.id); }, 100); }
call()、apply()、bind()
方法修改里面的this(function() { return [ (() => this.x).bind({ x: 'inner' })() // 无效的bind,最终this仍是指向外层 ]; }).call({ x: 'outer' }); // ['outer']
上面代码中,箭头函数没有本身的this
,因此bind
方法无效,内部的this
指向外部的this
。学习
箭头函数没有本身的 arguments
对象,这不必定是件坏事,由于箭头函数能够访问外围函数的 arguments
对象:
function constant() { return () => arguments[0] } var result = constant(1); console.log(result()); // 1
那若是咱们就是要访问箭头函数的参数呢?
你能够经过命名参数或者 rest 参数的形式访问参数:
let nums = (...nums) => nums;
JavaScript
函数有两个内部方法:[[Call]]
和 [[Construct]]
。
当经过new
调用函数时,执行[Construct]]
方法,建立一个实例对象,而后再执行函数体,将 this 绑定到实例上。
当直接调用的时候,执行[[Call]]
方法,直接执行函数体。
箭头函数并无[[Construct]]
方法,不能被用做构造函数,若是经过 new 的方式调用,会报错。
var Foo = () => {}; var foo = new Foo(); // TypeError: Foo is not a constructor
因为不能使用new
调用箭头函数,因此也没有构建原型的需求,因而箭头函数也不存在prototype
这个属性。
var Foo = () => {}; console.log(Foo.prototype); // undefined
第一个场合是定义函数的方法,且该方法内部包括this。
const cat = { lives: 9, jumps: () => { this.lives--; } }
上面代码中,cat.jumps()
方法是一个箭头函数,这是错误的。调用cat.jumps()
时,若是是普通函数,该方法内部的this
指向cat
;若是写成上面那样的箭头函数,使得this
指向全局对象,所以不会获得预期结果。
第二个场合是须要动态this的时候,也不该使用箭头函数。
var button = document.getElementById('press'); button.addEventListener('click', () => { this.classList.toggle('on'); });
上面代码运行时,点击按钮会报错,由于button
的监听函数是一个箭头函数,致使里面的this
就是全局对象。若是改为普通函数,this
就会动态指向被点击的按钮对象。
下面这个是咱们开发常常遇到的。咱们通常会经过this赋值给一个变量,而后再经过变量访问。
class Test { constructor() { this.birth = 10; } submit(){ let self = this; $.ajax({ type: "POST", dataType: "json", url: "xxxxx" ,//url data: "xxxxx", success: function (result) { console.log(self.birth);//10 }, error : function() {} }); } } let test = new Test(); test.submit();//undefined
这里咱们就能够经过箭头函数来解决
... success: (result)=> { console.log(this.birth);//10 }, ...
箭头函数在react
中的运用场景
class Foo extends Component { constructor(props) { super(props); } handleClick() { console.log('Click happened', this); this.setState({a: 1}); } render() { return <button onClick={this.handleClick}>Click Me</button>; } }
在react中咱们这样直接调用方法是有问题的,在handleClick
函数中的this是有问题,咱们平时须要这么作
class Foo extends Component { constructor(props) { super(props); this.handleClick = this.handleClick.bind(this); } handleClick() { console.log('Click happened', this); this.setState({a: 1}); } render() { return <button onClick={this.handleClick}>Click Me</button>; } }
这里经过this.handleClick.bind(this)
给函数绑定this
。可是这样写起来有些麻烦,有没有简单的方法呢?这时候咱们的箭头函数就出场了
class Foo extends Component { // Note: this syntax is experimental and not standardized yet. handleClick = () => { console.log('Click happened', this); this.setState({a: 1}); } render() { return <button onClick={this.handleClick}>Click Me</button>; } }
箭头函数中 this 的值是继承自 外围做用域,很好的解决了这个问题。
除此以外咱们还能够用箭头函数传参(这个不是必须的),并且会有性能问题。更多信息请查看
const A = 65 // ASCII character code class Alphabet extends React.Component { constructor(props) { super(props); this.handleClick = this.handleClick.bind(this); this.state = { justClicked: null, letters: Array.from({length: 26}, (_, i) => String.fromCharCode(A + i)). }; } handleClick(letter) { this.setState({ justClicked: letter }); } render() { return ( <div> Just clicked: {this.state.justClicked} <ul> {this.state.letters.map(letter => <li key={letter} onClick={() => this.handleClick(letter)}> {letter} </li> )} </ul> </div> ) } }
最后
更多系列文章请看
若是有错误或者不严谨的地方,请务必给予指正,十分感谢。若是喜欢或者有所启发,欢迎 star对做者也是一种鼓励。