摘要:在需要動態上下文的地方不能使用箭頭函數,使用構造函數創建對象時不能使用箭頭函數等等。
作者:扉扉 (滬江web前端開發工程師)
本文原創翻譯,有不當的地方歡迎指出。轉載請指明出處。
看到你每天使用的編程語言在不斷進化是一件令人開心的事情 。從錯誤中學習,找到更好的實現方式,創造新的語法特性,語言就這樣一步一步地實現了版本更新。
這正是近幾年Javascript身上發生的事情 ,ECMAScript6 引入了: 箭頭函數,類以及其它特性,真的太棒了!
其中一個非常好用的箭頭函數,有許多文件介紹了了這個漂亮的語法糖,還具有透明上下文的作用(原文為 context transparency), 如果你對于ES6還不熟悉,請先閱讀箭頭函數的一些入門文章。
凡事都有兩面性,新的特性往往也會帶來新的困擾, 比如對箭頭函數的誤用。
這篇文章通過實際使用場景帶你了解在一些特定情況下到底是應該使用傳統的函數,還是該使用更簡潔的箭頭函數。
1.在對象上定義方法在javascript中,方法可以做為一個對象的屬性,當調用這個方法時, this 指向這個方法所屬的對象;
1a. 對象字面量既然箭頭函數只是一個語法糖,那我們來嘗試一下使用箭頭函數做為一個對象的方法會發生什么:
var calculate = { array: [1, 2, 3], sum: () => { console.log(this === window); // => true return this.array.reduce((result, item) => result + item); } }; console.log(this === window); // => true // Throws"TypeError: Cannot read property "reduce" of undefined" calculate.sum();
calculate.sum使用箭頭函數來定義,但是調用 calculate.sum() 時出現了異常。因為當執行sum的時候上下文仍然是window,這是因為箭頭函數已經綁定了window做為上下文。
執行this.array 等同于 window.array ,當然是 undefined
解決辦法就是不要在對象的方法上使用箭頭函數短語法,這樣this關鍵字會在調用時決定,而不是早早綁定在閉合的上下文中, 讓我們看一下具體代碼:
var calculate = { array: [1, 2, 3], sum() { console.log(this === calculate); // => true return this.array.reduce((result, item) => result + item); } }; calculate.sum(); // => 6
對象原型
同樣的規則也適用于給對象prototype原型上定義方法:
function MyCat(name) { this.catName = name; } MyCat.prototype.sayCatName = () => { console.log(this === window); // => true returnthis.catName; }; var cat = new MyCat("Mew"); cat.sayCatName(); // => undefined
使用傳統方式即可正常工作:
function MyCat(name) { this.catName = name; } MyCat.prototype.sayCatName = function() { console.log(this === cat); // => true returnthis.catName; }; var cat = new MyCat("Mew"); cat.sayCatName(); // => "Mew"2.動態上下文中的回調函數
this是js中非常強大的特點,他讓函數可以根據其調用方式動態的改變上下文,然后箭頭函數直接在聲明時就綁定了this對象,所以不再是動態的。
在客戶端,在dom元素上綁定事件監聽函數是非常普遍的行為,在dom事件被觸發時,回調函數中的this指向該dom,可當我們使用箭頭函數時:
button.addEventListener("click", () => { console.log(this === window); // => true this.innerHTML = "Clicked button"; });
因為這個回調的箭頭函數是在全局上下文中被定義的,所以他的this是window。所以當this是由目標對象決定時,我們應該使用函數表達式:
button.addEventListener("click", function() { console.log(this === button); // => true this.innerHTML = "Clicked button"; });3.調用構造函數
當函數做為構造函數執行時 new MyFunction(),this指向新創建的對象實例:
this instanceOf MyFunction === true
需要注意的是,構造函數不能使用箭頭函數,如果這樣做會拋出異常。
因為使用箭頭函數后this會指定閉合的當前上下文,而當函數做為構造器的時候,this又會指向生成的實例, 這個造成歧義。
var Message = (text) => { this.text = text; }; // Throws "TypeError: Message is not a constructor" var helloMessage = new Message("Hello World!");
我們都知道使用函數表達式即可正常:
var Message = function(text) { this.text = text; }; var helloMessage = new Message("Hello World!"); console.log(helloMessage.text); // => "Hello World!"4.超短的語法
箭頭函數可以讓語句寫的非常的簡潔,參數只有一個時可以省略(),函數體只有一句話可以省略{},如果返回值是一個表達式還甚至還可以省略return!
我的大學老師曾給我們布置了一道有趣的作業: 使用C語言來編寫一個計算字符串長度的函數,函數要盡可能的短,這是一個很好的方法去學習一門新的語言。
不過在真實生活中,代碼要被其它開發者閱讀,超短的語法有時會讓你的同事陷入難以理解中。上代碼:
let double = multiply(2); double(3); // => 6 multiply(2, 3); // =>6
這個函數的作用就是當只有一個參數 a 時,返回接受一個參數 b 返回 a * b 的函數,接收兩個參數時直接返回乘積,這個函數可以很好的工作并且看起很簡潔,但是從第一眼看去并不是很好理解。
為了讓這個函數更好的讓人理解,我們可以為這個箭頭函數加一對花括號,并加上 return 語句,或者直接使用函數表達式:
function multiply(a, b){ if (b === undefined) { return function(b){ return a * b; } } return a * b; } letdouble = multiply(2); double(3); // => 6 multiply(2, 3);// => 6
怎么樣是不是好理解多了?
如何平衡簡潔與易理解也是使用箭頭函數需要注意的地方。
5.總結毫無疑問,箭頭函數是一個很棒的特性。以前我們使用bind()函數或者需要固定上下文的地方現在使用箭頭函數會讓代碼更加簡潔。
但有一些情況下,使用箭頭函數也有一些不便利。在需要動態上下文的地方不能使用箭頭函數,使用構造函數創建對象時不能使用箭頭函數等等。除去文中列舉不適合使用的情況下,盡情地使用箭頭函數吧。
原文地址:https://rainsoft.io/when-not-...
iKcamp原創新書《移動Web前端高效開發實戰》已在亞馬遜、京東、當當開售。
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/85113.html
摘要:前端日報精選如何優雅的編寫代碼深入理解內部機制專題之函數組合年月個有趣的和庫最經典的前端面試題之一,你能答出什么幺蛾子中文翻譯深入理解響應式原理掘金譯與和交互掘金箭頭函數使用禁忌技術棧耕耘助力美團點評前端進階之路前端模塊 2017-09-01 前端日報 精選 如何優雅的編寫 JavaScript 代碼深入理解 Node.js Stream 內部機制JavaScript專題之函數組合20...
摘要:因為箭頭函數沒有構造方法。因為不能一個箭頭函數,所以也沒必要有了。的值在這個箭頭函數的整個生命周期里面都不變。你必須通過命名參數和剩余參數去獲取箭頭函數的參數。非箭頭函數在非嚴格模式下面可以有重名參數。 例行聲明:接下來的文字內容全部來自 Understanding ECMAScript 6,作者是Nicholas C.Zakas,也就是大名鼎鼎的Professional JavaSc...
摘要:一旦聲明,常量的值不能被改變。頂層對象的屬性頂層對象,瀏覽器中指的是對象,在中指的是對象。中新增了兩個命令和,命令用于暴露出模塊對外的接口,而則用于輸入某一模塊。 1.聲明變量的關鍵字:const 和 let JavaScript ES6中引入了另外兩個聲明變量的關鍵字:const和let。在ES6中,我們將很少能看到var了。 const關鍵字 const聲明一個只讀的常量。一旦聲明...
摘要:回顧我們先來回顧下箭頭函數的基本語法。主要區別包括沒有箭頭函數沒有,所以需要通過查找作用域鏈來確定的值。箭頭函數并沒有方法,不能被用作構造函數,如果通過的方式調用,會報錯。 回顧 我們先來回顧下箭頭函數的基本語法。 ES6 增加了箭頭函數: let func = value => value; 相當于: let func = function (value) { return ...
閱讀 1644·2021-11-24 09:39
閱讀 3083·2021-11-22 15:24
閱讀 3091·2021-10-26 09:51
閱讀 3276·2021-10-19 11:46
閱讀 2891·2019-08-30 15:44
閱讀 2217·2019-08-29 15:30
閱讀 2537·2019-08-29 15:05
閱讀 773·2019-08-29 10:55