1. 程式人生 > >好程式設計師web前端分享詳細瞭解JavaScript函式

好程式設計師web前端分享詳細瞭解JavaScript函式

好程式設計師web前端分享詳細瞭解JavaScript函式,如果你曾經接觸過JavaScript程式設計,你一定不會陌生如何定義並且呼叫一個函式。但是你知道在JavaScript中有多少種定義函式的方法嗎?如果想要在Test262中編寫和維護這些方法的測試,那可真是一個很大的挑戰,尤其當一些新特性和現有函式語法相關,或者擴充套件了函式的API時。但是,想要斷言新提出或被提案的語法、API有效時,測試所有既存變式又是非常必要的。 下面會針對JavaScript中已經存在的函式定義方式進行一個概述。本文不包含Class宣告和表示式,因為這些方式建立的物件是“不可呼叫的”,本文旨在那些可生成“可呼叫”物件的函式定義方式。也就是說,我們不會研究那些複雜的引數列表(包含預設引數、結構賦值或者尾後逗號),因為那足夠另起文章介紹了。

 

以前的方式

 

函式宣告以及函式表示式

 

最為出名以及應用最廣的同樣也是這些舊方式:函式宣告和函式表示式。前者設計(1995)和出現在第一版的規範(1997)(pdf)中。後者則是出現在第三版中(1999)(pdf)。仔細研究,你會從它們當中提取出三種不同的方式。

 

// 函式宣告

function BindingIdentifier() {}

 

// 命名函式表示式

// (BindingIdentifier在函式外部是訪問不到的)

(function BindingIdentifier() {});

 

// 匿名函式表示式

(function() {});

值得注意的是,匿名函式表示式仍然可能有名字,Mike Pennisi在什麼是函式名稱?中有深度解釋。

 

Function建構函式

 

當研究一門語言的"function API"的時候,也就到了這門語言的底層。在這門語言的設計之初,函式宣告方式可以被理解為是Function建構函式API的最直接實現。Function建構函式提供了一種定義函式的方式:通過指明Function的引數,其中最後一個引數就是函式的函式體(必須要說明的是,這是一種動態程式碼方式,可能存在安全問題)。在大多數情況下,這種方式是不合適的,所以用的人很少,但是在第一版的ECMAScript中,這種方式就出現了。

 

new Function('x', 'y', 'return x ** y;');

新的方式

 

自從ES2015釋出以來,幾種新的定義函式方式被引入進來,這些方式的變式更是非常繁多。

 

另類匿名函式

 

這是一種新式的匿名函式。如果你曾經接觸過ES的模組化,那麼你很有可能已經接觸過這種定義函式的方式了。儘管這種方式看起來和匿名函式的定義方式很像,但是他確實有自己的名字:default

 

// 另類匿名函式宣告

export default function() {}

順便一提,這個名字並不是專屬的標識,並沒有進行繫結。

 

方法定義

 

下面這些方式定義的函式表示式、匿名函式或者命名函式,都是某個物件的屬性。注意這些並不是新的語法,只是應用上面提及的那些語法,寫在了某個物件的初始化器中。這種方式最早引入在ES3中。

 

let object = {

  propertyName: function() {},

};

let object = {

  // (BindingIdentifier不能再函式外部呼叫)

  propertyName: function BindingIdentifier() {},

};

下面是存取器屬性,引入在ES5。

 

let object = {

  get propertyName() {},

  set propertyName(value) {},

};

在ES2015中,JavaScript中提供了一種定義方法的簡潔語法,不管是直接命名的方式還是計算屬性名的方式,都可以使用,而且,存取器同樣適用。

 

let object = {

  propertyName() {},

  ["computedName"]() {},

  get ["computedAccessorName"]() {},

  set ["computedAccessorName"](value) {},

};

你也可以把這些定義屬性或者方法的新方式應用在建立類時。

 

// 類宣告

class C {

  methodName() {}

  ["computedName"]() {}

  get ["computedAccessorName"]() {}

  set ["computedAccessorName"](value) {}

}

 

// 類表示式

let C = class {

  methodName() {}

  ["computedName"]() {}

  get ["computedAccessorName"]() {}

  set ["computedAccessorName"](value) {}

};

...在定義靜態方法時,同樣可以使用。

 

// 類宣告

class C {

  static methodName() {}

  static ["computedName"]() {}

  static get ["computedAccessorName"]() {}

  static set ["computedAccessorName"](value) {}

}

 

// 類表示式

let C = class {

  static methodName() {}

  static ["computedName"]() {}

  static get ["computedAccessorName"]() {}

  static set ["computedAccessorName"](value) {}

};

箭頭函式

 

箭頭函式首次出現在ES2015中,儘管起初飽受爭議,但是現在已經被廣泛應用了。箭頭函式的定義根據是否簡寫有兩種不同的語法:賦值表示式(在箭頭後面沒有花括號)和函式體(當函式包含零個或者多個表示式時)。語法規定,當函式只有一個引數時,可以不用小括號括起來,但是當沒有引數或者多餘一個引數時,就必須用小括號括起來了。(這種語法就決定了箭頭函式會有多種定義形式)

 

// 零引數, 賦值表示式

(() => 2 ** 2);

 

// 一個引數, 可以省略小括號, 賦值表示式

(x => x ** 2);

 

// 一個引數, 可以省略小括號, 函式體

(x => { return x ** 2; });

 

// 多個引數, 賦值表示式

((x, y) => x ** y);

上面的最後一種形式中,引數是用引數列表來表示的,因為它們用小括號括了起來。類似於用小括號來標識引數列表的語法,還有其他形式,諸如({ x }) => x。 如果引數不用小括號括起來,那麼只能給引數起一個獨一的識別符號名稱,以在箭頭函式中使用。當箭頭函式被定義為非同步函式或者Generator函式時,這個識別符號名稱還可以加上await 或者 yield的字首,但那也已經是在不用括號情形中,考慮足夠深遠的了。 箭頭函式可以並且也經常出現在初始化器或者物件屬性的定義中,但是這種情況大部分使用的是上面介紹的賦值表示式形式,舉例如下:

 

let foo = x => x ** 2;

 

let object = {

  propertyName: x => x ** 2

};

Generators

 

Generator函式的語法是在其他定義函式的方式上加點東西,但箭頭函式和存取器方法除外。你可以使用和之前函式宣告,函式表示式,函式定義甚至是建構函式等相似的方式。所有方法列舉如下:

 

// Generator 宣告

function *BindingIdentifer() {}

 

// 另類匿名 Generator 宣告

export default function *() {}

 

// Generator 表示式

// (BindingIdentifier只能在函式內部呼叫)

(function *BindingIdentifier() {});

 

// 匿名 Generator 表示式

(function *() {});

 

// 方法定義

let object = {

  *methodName() {},

  *["computedName"]() {},

};

 

// 在類宣告中定義方法

class C {

  *methodName() {}

  *["computedName"]() {}

}

 

// 在類宣告中定義靜態方法

class C {

  static *methodName() {}

  static *["computedName"]() {}

}

 

// 在類表示式中定義方法

let C = class {

  *methodName() {}

  *["computedName"]() {}

};

 

// 在類表示式中定義靜態方法

let C = class {

  static *methodName() {}

  static *["computedName"]() {}

};

ES2017

 

非同步函式

 

經過幾年的發展,非同步函式將會發布ES2017——第八版EcmaScript語言規範——規範會在2017年6月在正式釋出。但其實,很多開發者早已經開始使用非同步函數了,這還要歸功於Babel的支援。 非同步函式語法提供了一個乾淨的、統一的方式來描述非同步操作。當被呼叫時,非同步函式會返回一個Promise物件。當非同步執行結束後,這個Promise物件即會被相應執行。當函式中含有await表示式時,非同步函式就會暫停執行,這時,await表示式結果就會作為非同步函式的返回值。 非同步函式的語法並沒有太多的不同,只是在我們熟知的那些方式前面加上一個字首:

 

//  非同步函式宣告

async function BindingIdentifier() { /**/ }

 

// 另類匿名非同步函式宣告

export default async function() { /**/ }

 

// 命名非同步函式表示式

// (BindingIdentifier只能在函式內部呼叫)

(async function BindingIdentifier() {});

 

// 匿名非同步函式表示式

(async function() {});

 

// 非同步方法

let object = {

  async methodName() {},

  async ["computedName"]() {},

};

 

// 類宣告中的非同步方法

class C {

  async methodName() {}

  async ["computedName"]() {}

}

 

// 類宣告中的靜態非同步方法

class C {

  static async methodName() {}

  static async ["computedName"]() {}

}

 

// 類表示式中的非同步方法

let C = class {

  async methodName() {}

  async ["computedName"]() {}

};

 

// 類表示式中的靜態非同步方法

let C = class {

  static async methodName() {}

  static async ["computedName"]() {}

};

非同步箭頭函式

 

async 和 await並不是只侷限在常規函式的宣告或者表示式中,它們同樣適用於箭頭函式:

 

// 單一引數,賦值表示式

(async x => x ** 2);

 

// 單一引數,函式體

(async x => { return x ** 2; });

 

// 引數列表,賦值表示式

(async (x, y) => x ** y);

 

// 引數列表,函式體

(async (x, y) => { return x ** y; });

與ES2017結合

 

非同步Generator函式

 

和ES2017結合,async 和 await將會被擴充套件支援非同步函式。這一特性的發展可以追蹤推薦的github倉儲。正如你猜想到的,非同步Generator函式的語法是結合async、await以及已經存在的Generator函式宣告和表示式而來。當非同步Generator函式被呼叫的時候,會返回一個迭代器,這個迭代器的next()方法會返回一個Promise物件來處理迭代器的返回物件,而不是直接返回迭代器的結果物件。 非同步Generator函式已經開始在很多地方使用,你很有可能已經碰到過。

 

// 非同步Generator宣告

async function *BindingIdentifier() { /**/ }

 

// 另類匿名非同步Generator宣告

export default async function *() {}

 

// 非同步Generator表示式

// (BindingIdentifier只能在函式內部訪問)

(async function *BindingIdentifier() {});

 

// 匿名非同步Generator表示式

(async function *() {});

 

// 匿名非同步Generator方法定義

let object = {

  async *propertyName() {},

  async *["computedName"]() {},

};

 

// 類宣告中非同步Generator原型方法定義

class C {

  async *propertyName() {}

  async *["computedName"]() {}

}

 

// 類表示式中非同步Generator原型方法定義

let C = class {

  async *propertyName() {}

  async *["computedName"]() {}

};

 

// 類宣告中非同步Generator靜態方法定義

class C {

  static async *propertyName() {}

  static async *["computedName"]() {}

}

 

// 類表示式中非同步Generator靜態方法定義

let C = class {

  static async *propertyName() {}

  static async *["computedName"]() {}

相關推薦

程式設計師web前端分享詳細瞭解JavaScript函式

好程式設計師web前端分享詳細瞭解JavaScript函式,如果你曾經接觸過JavaScript程式設計,你一定不會陌生如何定義並

程式設計師web前端分享HTML元素強制不換行

好程式設計師web前端分享HTML元素強制不換行,HTML 中 nowrap是用來強制不換行的     在排版中

程式設計師web前端分享JS檢查瀏覽器型別和版本

好程式設計師web前端分享JS檢查瀏覽器型別和版本,先取得Navigator物件的userAgent屬性的小寫資訊,之後根據正則表

程式設計師web前端分享主流CSS image比較

好程式設計師web前端分享主流CSS image比較在還原設計圖的時候,難免會碰到一些樣式圖片的引用。如何來對這些圖片做優化呢?本

程式設計師web前端分享css常用屬性縮寫

好程式設計師web前端分享css常用屬性縮寫,使用縮寫可以幫助減少你CSS檔案的大小,更加容易閱讀。css縮寫的主要規則如下:  

程式設計師web前端分享想要學習前端需要學那些課程

仔細思考了一下如何回答好這個話題,其實前端是一個涵蓋面非常之廣泛的一個職位,所需知識體系非常龐雜,與傳統語言“想要精一行,必先通一

程式設計師web前端分享如何理解JS的單執行緒

好程式設計師web前端分享如何理解JS單執行緒,JS本質是單執行緒的。也就是說,它並不能像JAVA語言那樣,兩個執行緒併發

程式設計師web前端分享CSS元素型別

好程式設計師web前端教程分享CSS元素型別 學習目標 1、元素型別分類依據和元素型別分類 2、元素型別的轉換 3、i

程式設計師web前端分享CSS屬性組成及作用

好程式設計師web前端分享CSS屬性組成及作用 學習目標 1、css屬性和屬性值的定義 2、css文字屬性

程式設計師web前端分享CSS基礎篇

好程式設計師web前端分享CSS基礎篇 學習目標 1、CSS簡介 2、CSS語法 3、樣式的建立 4、兩種引

程式設計師web前端分享HTML基本結構和基本語法

好程式設計師web前端分享HTML基本結構和基本語法 HTML基本結構和HTML基本語法 HTML基本結構 HTML的基

程式設計師web前端分享HTML基礎篇

好程式設計師web前端分享HTML基礎篇最近遇到很多新手,都會問,如果要學web前端開發,需要學什麼?難不難學啊?多久能入門之類的

程式設計師web前端分享CSS3彈性盒

好程式設計師web前端分享CSS3彈性盒 一、盒模型 box-sizing box-sizing 屬性允許您以特定的方式定

程式設計師web前端帶你瞭解JS的作用域鏈

好程式設計師web前端帶你瞭解JS的作用域鏈,我們都知道js是一個基於物件的語言,系統內建各種物件。   而wind

程式設計師web前端分享常見html5語義化標籤

好程式設計師web前端分享常見html5語義化標籤,我們知道,建立結構清晰的頁面可以建立良好的語義化基礎,也降低了使用css的難度

程式設計師web前端分享CSS學習:HSLA顏色模式

好程式設計師web前端分享CSS學習:HSLA顏色模式 一、理論: 1.HSLA顏色模式 a.HSLA在HSL基礎上增加了不透明

程式設計師Web前端分享一些小知識!

好程式設計師Web前端分享一些小知識!為了幫助正在從事Web前端工作和正在學習Web前端的小夥伴更好的瞭解Web前端技術,今天為大

程式設計師web前端分享web開發概況

  今天介紹一下web開發的大體概況,讓大家能夠從整體對web開發有一個相對全面的瞭解,隨著科學技術的發展,各種移動端(mobil

程式設計師web前端分享JS引擎的執行機制

  好程式設計師web前端分享JS引擎的執行機制,一、JS是單執行緒語言。JS的EventLoop是JS的執行機制。深入瞭解JS的

程式設計師web前端分享函式作用域及遞迴

作用域的生命週期。   var a = 10;   function m1(){  &nb