免费视频淫片aa毛片_日韩高清在线亚洲专区vr_日韩大片免费观看视频播放_亚洲欧美国产精品完整版

打開APP
userphoto
未登錄

開通VIP,暢享免費電子書等14項超值服

開通VIP
JavaScript中的函數(shù)表達式

在JavaScript中,函數(shù)是個非常重要的對象,函數(shù)通常有三種表現(xiàn)形式:函數(shù)聲明,函數(shù)表達式和函數(shù)構(gòu)造器創(chuàng)建的函數(shù)。

本文中主要看看函數(shù)表達式及其相關(guān)的知識點。

函數(shù)表達式

首先,看看函數(shù)表達式的表現(xiàn)形式,函數(shù)表達式(Function Expression, FE)有下面四個特點:

  • 在代碼中須出現(xiàn)在表達式的位置
  • 有可選的函數(shù)名稱
  • 不會影響變量對象(VO)
  • 在代碼執(zhí)行階段創(chuàng)建

下面就通過一些例子來看看函數(shù)表達式的這四個特點。

FE特點分析

例子一:在下面代碼中,"add"是一個函數(shù)對象,"sub"是一個普通JavaScript變量,但是被賦值了一個函數(shù)表達式" function (a, b){ return a - b; } ":

function add(a, b){    return a + b;}var sub = function (a, b){    return a - b;}console.log(add(1, 3));// 4console.log(sub(5, 1));// 4

通過這個例子,可以直觀的看到函數(shù)表達式的前兩個特點:

  • 在代碼中須出現(xiàn)在表達式的位置
    • function (a, b){ return a - b; } "出現(xiàn)在了JavaScript語句中的表達式位置
  • 有可選的函數(shù)名稱
    • function (a, b){ return a - b; } "這個函數(shù)表達式?jīng)]有函數(shù)名稱,是個匿名函數(shù)表達式

 

例子二:為了解釋函數(shù)表達式另外兩個特點,繼續(xù)看看下面的例子。

console.log(add(1, 3));// 4console.log(sub);// undefinedconsole.log(sub(5, 1));// Uncaught TypeError: sub is not a function(…)function add(a, b){    return a + b;}var sub = function (a, b){    return a - b;}

在這個例子中,調(diào)整了代碼的執(zhí)行順序,這次函數(shù)"add"執(zhí)行正常,但是對函數(shù)表達式的執(zhí)行失敗了。

對于這個例子,可以參考"JavaScript的執(zhí)行上下文"一文中的內(nèi)容,當代碼開始執(zhí)行的時候,可以得到下圖所示的Global VO。

在Global VO中,對"add"函數(shù)表現(xiàn)為JavaScript的"Hoisting"效果,所以即使在"add"定義之前依然可以使用;

但是對于"sub"這個變量,根據(jù)"Execution Context"的初始化過程,"sub"會被初始化為"undefined",只有執(zhí)行到" var sub = function (a, b){ return a - b; } "語句的時候,VO中的"sub"才會被賦值。

通過上面這個例子,可以看到了函數(shù)表達式的第四個特點

  • 在代碼執(zhí)行階段創(chuàng)建

 

例子三:對上面的例子進一步改動,這次給函數(shù)表達式加上了一個名字"_sub",也就是說,這里使用的是一個命名函數(shù)表達式

var sub = function _sub(a, b){    console.log(typeof _sub);    return a - b;}console.log(sub(5, 1));// function// 4console.log(typeof _sub)// undefinedconsole.log(_sub(5, 1));// Uncaught ReferenceError: _sub is not defined(…)

根據(jù)這段代碼的運行結(jié)果,可以看到"_sub"這個函數(shù)名,只能在"_sub"這個函數(shù)內(nèi)部使用;當在函數(shù)外部訪問"_sub"的時候,就是得到"Uncaught ReferenceError: _sub is not defined(…)"錯誤。

所以通過這個可以看到函數(shù)表達式的第三個特點:

  • 不會影響變量對象(VO)

 

FE的函數(shù)名

到了這里,肯定會有一個問題,"_sub"不在VO中,那在哪里?

其實對于命名函數(shù)表達式,JavaScript解釋器額外的做了一些事情:

  1. 當解釋器在代碼執(zhí)行階段遇到命名函數(shù)表達式時,在函數(shù)表達式創(chuàng)建之前,解釋器創(chuàng)建一個特定的輔助對象,并添加到當前作用域鏈的最前端
  2. 然后當解釋器創(chuàng)建了函數(shù)表達式,在創(chuàng)建階段,函數(shù)獲取了[[Scope]] 屬性(當前函數(shù)上下文的作用域鏈)
  3. 此后,函數(shù)表達式的函數(shù)名添加到特定對象上作為唯一的屬性;這個屬性的值是引用到函數(shù)表達式上
  4. 最后一步是從父作用域鏈中移除那個特定的對象

下面是表示這一過程的偽代碼:

specialObject = {}; Scope = specialObject + Scope; _sub = new FunctionExpression;_sub.[[Scope]] = Scope;specialObject. _sub = _sub; // {DontDelete}, {ReadOnly}  delete Scope[0]; // 從作用域鏈中刪除特殊對象specialObject

函數(shù)遞歸

這一小節(jié)可能有些鉆牛角尖,但是這里想演示遞歸調(diào)用可能出現(xiàn)的問題,以及通過命名函數(shù)表達式以更安全的方式執(zhí)行遞歸。

下面看一個求階乘的例子,由于函數(shù)對象也是可以被改變的,所以可能會出現(xiàn)下面的情況引起錯誤。

function factorial(num){    if (num <= 1){        return 1;    } else {        return num * factorial(num-1);    }} console.log(factorial(5))// 120newFunc = factorialfactorial = nullconsole.log(newFunc(5));// Uncaught TypeError: factorial is not a function(…)

這時,可以利用函數(shù)的arguments對象的callee屬性來解決上面的問題,也就是說在函數(shù)中,總是使用"arguments.callee"來遞歸調(diào)用函數(shù)。

function factorial(num){    if (num <= 1){        return 1;    } else {        return num * arguments.callee(num-1);    }}

但是上面的用法也有些問題,當在嚴格模式的時候"arguments.callee"就不能正常的工作了。

比較好的解決辦法就是使用命名函數(shù)表達式,這樣無論"factorial"怎么改變,都不會影響函數(shù)表達式" function f(num){…} "

var factorial = (function f(num){    if (num <= 1){        return 1;    } else {        return num * f(num-1);    }});

代碼模塊化

在JavaScript中,沒有塊作用域,只有函數(shù)作用域,函數(shù)內(nèi)部可以訪問外部的變量和函數(shù),但是函數(shù)內(nèi)部的變量和函數(shù)在函數(shù)外是不能訪問的。

所以,通過函數(shù)(通常直接使用函數(shù)表達式),可以模塊化JavaScript代碼。

創(chuàng)建模塊

為了能夠到達下面的目的,我們可以通過函數(shù)表達式來建立模塊。

  • 創(chuàng)建一個可以重用的代碼模塊
  • 模塊中封裝了使用者不必關(guān)心的內(nèi)容,只暴露提供給使用者的接口
  • 盡量與全局namespace進行隔離,減少對全局namespace的污染

下面看一個簡單的例子:

var Calc = (function(){    var _a, _b;        return{        add: function(){            return _a + _b;        },                sub: function(){            return _a - _b;        },                set: function(a, b){            _a = a;            _b = b;        }    }}());Calc.set(10, 4);console.log(Calc.add());// 14console.log(Calc.sub());// 6

代碼中通過匿名函數(shù)表達式創(chuàng)建了一個"Calc"模塊,這是一種常用的創(chuàng)建模塊的方式:

  • 創(chuàng)建一個匿名函數(shù)表達式,這個函數(shù)表達式中包含了模塊自身的私有變量和函數(shù);
  • 通過執(zhí)行這個函數(shù)表達式可以得到一個對象,對象中包含了模塊想要暴露給用戶的公共接口。

除了返回一個對象的方式,有的模塊也會使用另外一種方式,將包含模塊公共接口的對象作為全局變量的一個屬性。

這樣在代碼的其他地方,就可以直接通過全局變量的這個屬性來使用模塊了。

例如下面的例子:

(function(){    var _a, _b;        var root = this;        var _ = {        add: function(){            return _a + _b;        },                sub: function(){            return _a - _b;        },                set: function(a, b){            _a = a;            _b = b;        }    }        root._ = _;    }.call(this));_.set(10, 4);console.log(_.add());// 14console.log(_.sub());// 6

立即調(diào)用的函數(shù)表達式

在上面兩個例子中,都使用了匿名的函數(shù)表達式,并且都是立即執(zhí)行的。如果去看看JavaScript一些開源庫的代碼,例如JQuery、underscore等等,都會發(fā)現(xiàn)類似的立即執(zhí)行的匿名函數(shù)代碼。

立即調(diào)用的函數(shù)表達式通常表現(xiàn)為下面的形式:

(function () {     /* code */ })();(function () {     /* code */ } ()); 在underscore這個JavaScript庫中,使用的是下面的方式:(function () {     // Establish the root object, `window` in the browser, or `exports` on the server.var root = this;/* code */ } .call(this)); 

在這里,underscore模塊直接對全局變量this進行了緩存,方便模塊內(nèi)部使用。

總結(jié)

本文簡單介紹了JavaScript中的函數(shù)表達式,并通過三個例子解釋了函數(shù)表達式的四個特點。

  • 在代碼中須出現(xiàn)在表達式的位置
  • 有可選的函數(shù)名稱
  • 不會影響變量對象(VO)
  • 在代碼執(zhí)行階段創(chuàng)建

通過函數(shù)表達式可以方便的建立JavaScript模塊,通過模塊可以實現(xiàn)下面的效果:

  • 創(chuàng)建一個可以重用的代碼模塊
  • 模塊中封裝了使用者不必關(guān)心的內(nèi)容,只暴露提供給使用者的接口
  • 盡量與全局namespace進行隔離,減少對全局namespace的污染

 

本站僅提供存儲服務(wù),所有內(nèi)容均由用戶發(fā)布,如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點擊舉報。
打開APP,閱讀全文并永久保存 查看更多類似文章
猜你喜歡
類似文章
前端基礎(chǔ)進階(7):函數(shù)與函數(shù)式編程
「學習筆記」JavaScript基礎(chǔ)
深入理解JavaScript函數(shù)及其模式(一)
ECMAScript中的函數(shù)
05.JS函數(shù)
JS|函數(shù)的返回值
更多類似文章 >>
生活服務(wù)
分享 收藏 導(dǎo)長圖 關(guān)注 下載文章
綁定賬號成功
后續(xù)可登錄賬號暢享VIP特權(quán)!
如果VIP功能使用有故障,
可點擊這里聯(lián)系客服!

聯(lián)系客服