ES6新增了很多新特性,箭頭函式、簡化函式是我們接觸的最多的特性了,但是它們與傳統的Javascript函式(本文稱之為普通函式)有些不同
一、箭頭函式
- 沒有this、super、arguments和new.target繫結
- 不能通過new關鍵字呼叫
- 沒有原型
- 不可以改變this的繫結
- 不支援arguments物件
- 不支援重複的命名引數
- 不支援詞法名稱識別符號
1. 沒有this、super、arguments和new.target繫結
箭頭函式中的this、super、arguments及new.target這些值由外圍最近一層非箭頭函式決定,它本身沒有這些繫結,下面將用一些例子進行說明:
1.1、沒有this繫結
var myObject = {
age:30,
run:()=>{
console.log('張三今年'+this.age+'歲');
}
}
myObject.run(); // 非嚴格模式下,列印出:張三今年undefined歲
var myObject2 = {
age:30,
run:function(){
setTimeout(()=>{
console.log('張三今年'+this.age+'歲')
},0)
}
}
myObject2.run(); // 張三今年30歲
複製程式碼
上面第一個例子,直接在物件中定義了一個箭頭函式方法,結果為undefiend,通過查詢我們會發現,此時在非嚴格模式下的this指向了全域性物件(window),第二個例子,我們在物件中定義了一個function函式,然後在函式裡面使用了箭頭函式,此時得到的結果是正常的,這說明箭頭函式本身並沒有this,this繫結由外層非箭頭函式決定的,示例2等價於下面程式碼:
var myObject2 = {
age:30,
run:function(){
var that = this;
setTimeout(function(){
console.log('張三今年'+that.age+'歲');
},0)
}
}
myObject2.run(); // 張三今年30歲
複製程式碼
1.2、沒有super
var foo = {
run:()=>{
console.log(super.name);
}
}
var person = {
name:'張三'
}
Object.setPrototypeOf(foo,person);
foo.run(); // Uncaught SyntaxError: 'super' keyword unexpected here
複製程式碼
1.3、沒有arguments物件
var person = ()=>{
console.log(arguments[0]);
}
person(30); // Uncaught ReferenceError: arguments is not defined
複製程式碼
1.4、沒有new.target元屬性
var person = ()=>{
console.log(new.target);
}
person(); // Uncaught SyntaxError: new.target expression is not allowed here
複製程式碼
2、不能通過new關鍵字呼叫
箭頭函式沒有[[Construct]]方法,所以不能被用作建構函式,如果通過new關鍵字呼叫箭頭函式,程式會丟擲錯誤。
var Person = (age)=>{
this.age = age;
}
var obj = new Person(30); // Uncaught TypeError: Person is not a constructor
複製程式碼
3、沒有原型
由於不可以通過new關鍵字呼叫箭頭函式,因而沒有構建原型的需求,所以箭頭函式不存在prototype這個屬性。
var Person = (age)=>{
this.age = age;
}
console.log(Person.prototype); // undefined
複製程式碼
4、不可以改變this的繫結
由於箭頭函式沒有自己的this,所以使用call/bind/apply等方法無法改變this的繫結
var obj = {
age:'唐華'
}
var foo = ()=>{
console.log(this.age);
}
foo.call(obj); // undefined
複製程式碼
5、不支援arguments物件
箭頭函式沒有arguments繫結,所以只能通過命名引數或者不定引數(...)這兩種形式訪問函式的引數。
var foo = ()=>{
console.log(arguments[0]);
}
foo(10); // Uncaught ReferenceError: arguments is not defined
複製程式碼
6、不支援重複的命名引數
無論在嚴格還是非嚴格模式下,箭頭函式都不支援重複的命名引數。
var foo = (name,name)=>{
console.log(name,name);
}
foo(10,20); // Uncaught SyntaxError: Duplicate parameter name not allowed in this context
複製程式碼
7、不支援詞法名稱識別符號
箭頭函式不能定義詞法名稱識別符號,導致函式自我引用(遞迴、事件(解除)繫結)更難操作。
var Foo = {
// Uncaught SyntaxError: Malformed arrow function parameter list
bar:bar()=> {
console.log('箭頭函式');
},
baz: function baz() {
console.log('普通函式');
}
};
複製程式碼
二、簡寫函式
- super繫結
- 不支援詞法名稱識別符號
1、super繫結
super關鍵字用於訪問和呼叫一個物件的父物件上的函式。
class Person{
constructor(){
this.age = '30'
}
run(){
console.log(this.age)
}
}
class Foo extends Person{
constructor(){
super();
this.age = '40';
}
sayName(){
super.run();
}
}
var obj = new Foo();
obj.sayName();
複製程式碼
上面的例子使用extends實現繼承,在子類的constructor中必須呼叫super方法,因為子類沒有自己的 this 物件,需要繼承父類的this物件,子類中的super就代表了父類的建構函式,呼叫super(...)後子類中的this指向的是子類的例項,即super內部的this指的是Foo,相當於:Person.prototype.constructor.call(this)。
注意:super在靜態方法之中指向父類,在普通方法之中指向父類的原型物件
2、不支援詞法名稱識別符號
簡寫函式不能像普通函式一樣定義詞法名稱識別符號,導致函式自我引用(遞迴、事件(解除)繫結)更難操作。
var Foo = {
bar(){
console.log('簡寫函式');
},
baz: function baz() {
console.log('普通函式');
}
};
複製程式碼
三、普通函式
- 沒有super繫結
普通函式並沒有super繫結,只有簡寫函式才有。
var foo = {
name:'tanghua'
}
var bar = {
run:function(){
console.log(super.name);
}
}
Object.setPrototypeOf(bar,foo);
bar.run(); // Uncaught SyntaxError: 'super' keyword unexpected here
複製程式碼
上面的示例呼叫super關鍵字會丟擲一個錯誤,因為super只能在簡寫函式中呼叫。