首頁 >web前端 >前端問答 >es6中箭頭函數和普通函數的差別是什麼

es6中箭頭函數和普通函數的差別是什麼

青灯夜游
青灯夜游原創
2022-03-08 12:11:014097瀏覽

區別:1、箭頭函數的定義要比普通函數定義簡潔、清晰得多,很快捷;2、箭頭函數不會創建自己的this,而普通函數會;3、箭頭函數不能作為建構函式使用,而箭頭函式能作為建構函式使用;4、箭頭函式沒有自己的arguments,而箭頭函式有。

es6中箭頭函數和普通函數的差別是什麼

本教學操作環境:windows7系統、ECMAScript 6版、Dell G3電腦。

箭頭函數是前端面試環節的高頻考點,箭頭函數是ES6的API,相信很多人都知道,因為它的語法比一般的函數更簡潔,所以深受大家的喜愛。

一、基本語法

ES6中允許使用箭頭=>來定義箭頭函數,具體語法,我們來看一個簡單的例子:

// 箭头函数
let fun = (name) => {
    // 函数体
    return `Hello ${name} !`;
};

// 等同于
let fun = function (name) {
    // 函数体
    return `Hello ${name} !`;
};

可以看出,定義箭頭函在數語法上比普通函數簡潔得多。箭頭函數省去了function關鍵字,採用箭頭=>定義函數。函數的參數放在=>前面的括號中,函數體跟在=>後面的花括號中。

關於箭頭函數的參數:

如果箭頭函數沒有參數,直接寫一個空括號即可。

如果箭頭函數的參數只有一個,也可以省去包裹參數的括號。

若箭頭函數有多個參數,將參數依序以逗號(,)分隔,包裹在括號中即可。

// 没有参数
let fun1 = () => {
    console.log(111);
};

// 只有一个参数,可以省去参数括号
let fun2 = name => {
    console.log(`Hello ${name} !`)
};

// 有多个参数
let fun3 = (val1, val2, val3) => {
    return [val1, val2, val3];
};

關於箭頭函數的函數體:

如果箭頭函數的函數體只有一句程式碼,就是簡單回傳某個變數或傳回一個簡單的JS表達式,可以省去函數體的大括號{ }。

let f = val => val;
// 等同于
let f = function (val) { return val };

let sum = (num1, num2) => num1 + num2;
// 等同于
let sum = function(num1, num2) {
  return num1 + num2;
};

如果箭頭函數的函數體只有一句程式碼,就是回傳一個對象,可以像下面這樣寫:

// 用小括号包裹要返回的对象,不报错
let getTempItem = id => ({ id: id, name: "Temp" });

// 但绝不能这样写,会报错。
// 因为对象的大括号会被解释为函数体的大括号
let getTempItem = id => { id: id, name: "Temp" };

如果箭頭函數的函數體只有一條語句且不需要傳回值(最常見是呼叫一個函數),可以在這條語句前面加上一個void關鍵字

let fn = () => void doesNotReturn();

箭頭函數最常見的用處就是簡化回呼函數。

// 例子一
// 正常函数写法
[1,2,3].map(function (x) {
  return x * x;
});

// 箭头函数写法
[1,2,3].map(x => x * x);

// 例子二
// 正常函数写法
var result = [2, 5, 1, 4, 3].sort(function (a, b) {
  return a - b;
});

// 箭头函数写法
var result = [2, 5, 1, 4, 3].sort((a, b) => a - b);

二、箭頭函數與普通函數的差異

#1、語法更簡潔、清晰

從上面的基本語法範例可以看出,箭頭函數的定義比普通函數定義簡潔、清晰得多,而且很快捷。

2、箭頭函數不會創建自己的this(重要!!深入理解!!)

我們先來看看MDN上對箭頭函數 this的解釋。

箭頭函數不會創建自己的this,所以它沒有自己的this,它只會從自己的作用域鏈的上一層繼承this

箭頭函數沒有自己的this,它會捕捉自己在定義時(注意,是定義時,不是呼叫時)所處的外層執行環境的this,並繼承這個this值。所以,箭頭函數中this的指向在它被定義的時候就已經確定了,之後永遠不會改變。

來看個例子:

var id = 'Global';

function fun1() {
    // setTimeout中使用普通函数
    setTimeout(function(){
        console.log(this.id);
    }, 2000);
}

function fun2() {
    // setTimeout中使用箭头函数
    setTimeout(() => {
        console.log(this.id);
    }, 2000)
}

fun1.call({id: 'Obj'});     // 'Global'

fun2.call({id: 'Obj'});     // 'Obj'

上面這個例子,函數fun1中的setTimeout中使用普通函數,2秒後函數執行時,這時函數其實是在全域作用域執行的,所以this指向Window對象,this.id就指向全域變數id,所以輸出'Global'。 但是函數fun2中的setTimeout中使用的是箭頭函數,這個箭頭函數的this在定義時就確定了,它繼承了它外層fun2的執行環境中的this,而fun2呼叫時thiscall方法改變到了物件{id: 'Obj'}中,所以輸出'Obj'

再來看另一個例子:

var id = 'GLOBAL';
var obj = {
  id: 'OBJ',
  a: function(){
    console.log(this.id);
  },
  b: () => {
    console.log(this.id);
  }
};

obj.a();    // 'OBJ'
obj.b();    // 'GLOBAL'

上面這個例子,物件obj的方法a使用普通函數定義的,普通函數作為物件的方法呼叫時,this指向它所屬的物件。所以,this.id就是obj.id,所以輸出'OBJ'。 但是方法b是使用箭頭函數定義的,箭頭函數中的this實際上是繼承的它定義時所處的全域執行環境中的this,所以指向Window對象,所以輸出'GLOBAL'。 (這裡要注意,定義物件的大括號{}是無法形成一個單獨的執行環境的,它依舊是處於全域執行環境中!!

3、箭头函数继承而来的this指向永远不变(重要!!深入理解!!)

上面的例子,就完全可以说明箭头函数继承而来的this指向永远不变。对象obj的方法b是使用箭头函数定义的,这个函数中的this永远指向它定义时所处的全局执行环境中的this,即便这个函数是作为对象obj的方法调用,this依旧指向Window对象。

4、.call()/.apply()/.bind()无法改变箭头函数中this的指向

.call()/.apply()/.bind()方法可以用来动态修改函数执行时this的指向,但由于箭头函数的this定义时就已经确定且永远不会改变。所以使用这些方法永远也改变不了箭头函数this的指向,虽然这么做代码不会报错。

var id = 'Global';
// 箭头函数定义在全局作用域
let fun1 = () => {
    console.log(this.id)
};

fun1();     // 'Global'
// this的指向不会改变,永远指向Window对象
fun1.call({id: 'Obj'});     // 'Global'
fun1.apply({id: 'Obj'});    // 'Global'
fun1.bind({id: 'Obj'})();   // 'Global'

5、箭头函数不能作为构造函数使用

我们先了解一下构造函数的new都做了些什么?简单来说,分为四步: ① JS内部首先会先生成一个对象; ② 再把函数中的this指向该对象; ③ 然后执行构造函数中的语句; ④ 最终返回该对象实例。

但是!!因为箭头函数没有自己的this,它的this其实是继承了外层执行环境中的this,且this指向永远不会随在哪里调用、被谁调用而改变,所以箭头函数不能作为构造函数使用,或者说构造函数不能定义成箭头函数,否则用new调用时会报错!

let Fun = (name, age) => {
    this.name = name;
    this.age = age;
};

// 报错
let p = new Fun('cao', 24);

6、箭头函数没有自己的arguments

箭头函数没有自己的arguments对象。在箭头函数中访问arguments实际上获得的是外层局部(函数)执行环境中的值。

// 例子一
let fun = (val) => {
    console.log(val);   // 111
    // 下面一行会报错
    // Uncaught ReferenceError: arguments is not defined
    // 因为外层全局环境没有arguments对象
    console.log(arguments); 
};
fun(111);

// 例子二
function outer(val1, val2) {
    let argOut = arguments;
    console.log(argOut);    // ①
    let fun = () => {
        let argIn = arguments;
        console.log(argIn);     // ②
        console.log(argOut === argIn);  // ③
    };
    fun();
}
outer(111, 222);

上面例子二,①②③处的输出结果如下:

es6中箭頭函數和普通函數的差別是什麼

很明显,普通函数outer内部的箭头函数fun中的arguments对象,其实是沿作用域链向上访问的外层outer函数的arguments对象。

可以在箭头函数中使用rest参数代替arguments对象,来访问箭头函数的参数列表!!

7、箭头函数没有原型prototype

let sayHi = () => {
    console.log('Hello World !')
};
console.log(sayHi.prototype); // undefined

8、箭头函数不能用作Generator函数,不能使用yeild关键字

【相关推荐:javascript视频教程web前端

以上是es6中箭頭函數和普通函數的差別是什麼的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn