1、基础语法回忆
我们先来回忆下箭头函数的基础语法。
ES6 增加了箭头函数:
var f = v => v;
// 等同于
var f = function (v) {
return v;
};
假如箭头函数不须要参数或须要多个参数,就应用一个圆括号代表参数部份。
var f = () => 5;
// 等同于
var f = function () { return 5 };
var sum = (num1, num2) => num1 + num2;
// 等同于
var sum = function(num1, num2) {
return num1 + num2;
};
由于大括号被解释为代码块,所以假如箭头函数直接返回一个对象,必需在对象表面加上括号,不然会报错。
// 报错
let getTempItem = id => { id: id, name: "Temp" };
// 不报错
let getTempItem = id => ({ id: id, name: "Temp" });
下面是一种特殊情况,虽然能够运转,但会获得毛病的效果。
let foo = () => { a: 1 };
foo() // undefined
上面代码中,原始企图是返回一个对象{ a: 1 },然则由于引擎以为大括号是代码块,所以实行了一行语句a: 1。这时刻,a能够被解释为语句的标签,因而现实实行的语句是1;,然后函数就完毕了,没有返回值。
关于作用域
箭头函数内定义的变量及其作用域
// 通例写法
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
2、关于this
2.1、默许绑定外层this
箭头函数没有 this,所以须要经由过程查找作用域链来肯定 this 的值。
这就意味着假如箭头函数被非箭头函数包含,this 绑定的就是近来一层非箭头函数的 this。
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);
}
2.2、 不能用call()、apply()、bind()
要领修正内里的this
(function() {
return [
(() => this.x).bind({ x: 'inner' })() // 无效的bind,终究this照样指向外层
];
}).call({ x: 'outer' });
// ['outer']
上面代码中,箭头函数没有本身的this
,所以bind
要领无效,内部的this
指向外部的this
。
3、没有 arguments
箭头函数没有本身的 arguments
对象,这不一定是件坏事,由于箭头函数能够接见外围函数的 arguments
对象:
function constant() {
return () => arguments[0]
}
var result = constant(1);
console.log(result()); // 1
那假如我们就是要接见箭头函数的参数呢?
你能够经由过程定名参数或许 rest 参数的情势接见参数:
let nums = (...nums) => nums;
4、 不能经由过程 new 关键字挪用
JavaScript
函数有两个内部要领:[[Call]]
和 [[Construct]]
。
当经由过程new
挪用函数时,实行[Construct]]
要领,建立一个实例对象,然后再实行函数体,将 this 绑定到实例上。
当直接挪用的时刻,实行[[Call]]
要领,直接实行函数体。
箭头函数并没有[[Construct]]
要领,不能被用作组织函数,假如经由过程 new 的体式格局挪用,会报错。
var Foo = () => {};
var foo = new Foo(); // TypeError: Foo is not a constructor
5、没有原型
由于不能应用new
挪用箭头函数,所以也没有构建原型的需求,因而箭头函数也不存在prototype
这个属性。
var Foo = () => {};
console.log(Foo.prototype); // undefined
5、不适用场所
第一个场所是定义函数的要领,且该要领内部包含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
就会动态指向被点击的按钮对象。
6、应用场景
下面这个是我们开辟常常碰到的。我们平常会经由过程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对作者也是一种勉励。