成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

深入理解javascript函數(shù)

My_Oh_My / 462人閱讀

摘要:函數(shù)是對(duì)象理解函數(shù)是對(duì)象,是準(zhǔn)確理解函數(shù)的第一步。在中,函數(shù)對(duì)象和其他對(duì)象一樣,均被視為一等公民。當(dāng)函數(shù)執(zhí)行完畢,其執(zhí)行環(huán)境從棧中彈出并銷毀。此時(shí)的函數(shù)充當(dāng)構(gòu)造器的角色。調(diào)用函數(shù)對(duì)象的方法并將結(jié)果賦給。

函數(shù)是javascript中最重要的內(nèi)容,也是其相對(duì)其他語言來說在設(shè)計(jì)上比較有意思的地方。javascript許多高級(jí)特性也或多或少和函數(shù)相關(guān)。本文將以函數(shù)為中心,對(duì)函數(shù)的各個(gè)關(guān)鍵知識(shí)點(diǎn)做簡要介紹。

函數(shù)是對(duì)象

理解函數(shù)是對(duì)象,是準(zhǔn)確理解函數(shù)的第一步。下面的代碼就創(chuàng)建了一個(gè)函數(shù)對(duì)象。

var sum = new Function("num1", "num2", "return num1 + num2;");

每個(gè)函數(shù)都是Function類型的實(shí)例。Function構(gòu)造函數(shù)可以接受多個(gè)參數(shù),最后一個(gè)參數(shù)是函數(shù)體,其他參數(shù)均為函數(shù)的形參。由于其書寫的不優(yōu)雅和兩次解析導(dǎo)致的性能問題,這種方式不經(jīng)常被采用,但是這種寫法對(duì)于理解函數(shù)就是對(duì)象是非常有幫助的。一般地,我們都用字面的方式來創(chuàng)建函數(shù)。

var sum = function(num1, num2){
    return num1 + num2;
}
//或者
function sum(num1, num2){
    return num1 + num2;
}

以上兩種定義函數(shù)的方法分別叫做函數(shù)表達(dá)式和函數(shù)聲明,兩者的效果是等價(jià)的,區(qū)別在于解析器向執(zhí)行環(huán)境加載數(shù)據(jù)時(shí)對(duì)兩者的處理不一樣。解析器會(huì)率先讀取函數(shù)聲明來創(chuàng)建函數(shù)對(duì)象,保證其在任何代碼執(zhí)行之前可用;對(duì)于函數(shù)表達(dá)式,則必須等到解析器執(zhí)行到對(duì)應(yīng)的代碼行,函數(shù)對(duì)象才被創(chuàng)建。

在javascript中,函數(shù)對(duì)象和其他對(duì)象一樣,均被視為一等公民。所以函數(shù)可以被引用、可以作為參數(shù)被傳遞或作為返回值返回,這使得函數(shù)的使用非常的靈活。

函數(shù)的執(zhí)行

函數(shù)對(duì)象代表了一個(gè)過程,和大多數(shù)語言一樣通過函數(shù)調(diào)用表達(dá)式可以調(diào)用這個(gè)過程。但是javascript的函數(shù)對(duì)象還提供了另外兩種調(diào)用方式,call和apply方法。call和apply方法的第一個(gè)參數(shù)用于指定執(zhí)行環(huán)境中this的綁定,后面的參數(shù)用于指定函數(shù)的實(shí)際參數(shù)。call和apply的唯一區(qū)別是實(shí)參的形式不一樣,call是用逗號(hào)分割,apply則是以數(shù)組傳遞。例如:

//函數(shù)調(diào)用表達(dá)式
sum(1, 2);
//call方法
sum.call(this, 1, 2);
//apply方法
sum.apply(this, [1, 2]);

不管用哪種調(diào)用方式,最終都是通過函數(shù)對(duì)象的[[Call]]方法實(shí)際調(diào)用這個(gè)過程。[[Call]]方法是javascript引擎內(nèi)部使用的一個(gè)方法,程序不能直接訪問它。[[Call]]方法接受兩個(gè)參數(shù),第一個(gè)參數(shù)指定this的綁定值,第二個(gè)參數(shù)指定函數(shù)的參數(shù)列表。為了表達(dá)方便,后面我們將[[Call]]方法的第一個(gè)參數(shù)稱作thisArg。函數(shù)對(duì)象的call方法和apply方法可以顯示指定thisArg,函數(shù)表達(dá)式則是隱式指定這個(gè)參數(shù)的。例如:

var foo = function(){
    console.log(this);
};
var obj = {name:"object"};
foo();
obj.foo = foo;
obj.foo();

代碼在瀏覽器的執(zhí)行結(jié)果如下:

Window {top: Window, window: Window, location: Location...}
Object {name: "object", foo: function}

從執(zhí)行結(jié)果可以看出,obj.foo()這種調(diào)用方法,隱式將調(diào)用它的對(duì)象obj作為了thisArg。但是為什么foo()這種調(diào)用方式this的綁定值是window這個(gè)全局對(duì)象?難道foo()這種調(diào)用方式將全局對(duì)象默認(rèn)指定為thisArg?其實(shí)不是這樣的。thisArg并不是和this關(guān)鍵字的綁定一一對(duì)應(yīng)的,其中有一個(gè)轉(zhuǎn)換過程。如下:
1.如果thisArg為undefined或者null,則this的綁定為全局對(duì)象。
2.如果thisArg不是Object類型,則將thisArg強(qiáng)制轉(zhuǎn)型為Object類型并綁定到this。
3.否則this的綁定就為thisArg。
其實(shí)foo()這種調(diào)用方式thisArg的值為undefined,通過以上的轉(zhuǎn)換過程將this綁定為全局對(duì)象。

執(zhí)行環(huán)境與閉包

前面提到過執(zhí)行環(huán)境(Execution Context)這個(gè)概念,簡單來說執(zhí)行環(huán)境就是函數(shù)在執(zhí)行時(shí)所依賴的一個(gè)數(shù)據(jù)環(huán)境,它決定了函數(shù)的行為。程序執(zhí)行流每次進(jìn)入函數(shù)代碼時(shí)都會(huì)創(chuàng)建一個(gè)新的執(zhí)行環(huán)境。活動(dòng)的執(zhí)行環(huán)境在邏輯上形成了一個(gè)棧的結(jié)構(gòu)。當(dāng)函數(shù)執(zhí)行完畢,其執(zhí)行環(huán)境從棧中彈出并銷毀。

每個(gè)執(zhí)行環(huán)境都包含一個(gè)重要的組件:詞法環(huán)境(Lexical Environment)。詞法環(huán)境定義了javascript程序標(biāo)識(shí)符到變量或函數(shù)的關(guān)聯(lián)關(guān)系。詞法環(huán)境包含了環(huán)境記錄(Environment Record)和一個(gè)到外層詞法環(huán)境的引用(如果有的話,否則為null)。環(huán)境記錄記錄了當(dāng)前作用域下的變量或函數(shù)的綁定情況。有兩種類型的環(huán)境記錄,聲明式環(huán)境記錄(Declarative Environment Records)和對(duì)象環(huán)境記錄(Object Environment Records)。聲明式環(huán)境記錄包含了當(dāng)前作用域下標(biāo)識(shí)符到變量聲明和函數(shù)聲明的綁定。對(duì)象環(huán)境記錄是一個(gè)和特定對(duì)象綁定的環(huán)境記錄,用于臨時(shí)改變標(biāo)識(shí)符的解析情況,比如在with子句中。

函數(shù)對(duì)象都有一個(gè)[[Scope]]屬性,函數(shù)對(duì)象在創(chuàng)建時(shí)會(huì)將當(dāng)前執(zhí)行環(huán)境的詞法環(huán)境的值賦予給[[Scope]]屬性。這個(gè)屬性是引擎的內(nèi)部屬性,程序無法訪問到它。當(dāng)程序流進(jìn)入到函數(shù)時(shí),javascript引擎會(huì)創(chuàng)建新的執(zhí)行環(huán)境,同時(shí)也創(chuàng)建對(duì)應(yīng)的詞法環(huán)境。引擎會(huì)將當(dāng)前作用域聲明的變量和函數(shù)綁定到詞法環(huán)境,同時(shí)將[[Scope]]屬性的引用也添加到詞法環(huán)境。程序在進(jìn)行標(biāo)識(shí)符解析的時(shí)候,會(huì)優(yōu)先從當(dāng)前的詞法環(huán)境中搜索,搜索失敗則向外層詞法環(huán)境搜索,如果到最外層的全局環(huán)境還沒搜索到則會(huì)拋出異常。

嵌套定義的函數(shù)會(huì)形成javascript中一個(gè)有趣的特性:閉包。閉包的形成是由于內(nèi)層函數(shù)引用了外層函數(shù)在創(chuàng)建它時(shí)的詞法環(huán)境。即使外層函數(shù)已經(jīng)返回,執(zhí)行環(huán)境已經(jīng)銷毀,但是內(nèi)層函數(shù)依然能夠通過詞法環(huán)境的引用訪問外層函數(shù)中定義的變量或函數(shù)。

with和catch子句

with子句和catch子句都能臨時(shí)改變當(dāng)前的詞法環(huán)境。他們的方式是有些區(qū)別的。先看with子句。

function foo(){
    var background = "#ccc";
    with(document){
        body.style.background = background;
    }
}

當(dāng)執(zhí)行流進(jìn)入foo時(shí),這時(shí)會(huì)創(chuàng)建一個(gè)聲明式詞法環(huán)境。執(zhí)行流進(jìn)入with子句的時(shí)候,引擎會(huì)創(chuàng)建一個(gè)對(duì)象環(huán)境記錄。此時(shí)with子句中的標(biāo)識(shí)符解析都會(huì)先從document這個(gè)對(duì)象中查找。當(dāng)with子句執(zhí)行完之后,對(duì)象環(huán)境記錄銷毀。

try{
//do something
}catch(e){
//handel error
}

catch子句也能臨時(shí)改變當(dāng)前的詞法環(huán)境。和with子句不一樣的是,它會(huì)創(chuàng)建一個(gè)聲明式詞法環(huán)境,將catch子句中的參數(shù)綁定到這個(gè)詞法環(huán)境。

構(gòu)造器與原型繼承

函數(shù)對(duì)象還有個(gè)非常重要的內(nèi)部方法[[Construct]],當(dāng)我們將new操作符應(yīng)用到函數(shù)對(duì)象時(shí)就調(diào)用了[[Construct]]方法。此時(shí)的函數(shù)充當(dāng)構(gòu)造器的角色。下面的代碼就通過[[Construct]]創(chuàng)建了一個(gè)對(duì)象。

var Dog = function(){
}
var dog = new Dog();

[[Construct]]方法的執(zhí)行過程如下。
1.創(chuàng)建一個(gè)空對(duì)象obj。
2.設(shè)置obj的內(nèi)部屬性[[Class]]為Object。
3.設(shè)置obj的內(nèi)部屬性[[Extensible]]為true。
4.設(shè)置obj的[[Prototype]]屬性:如果函數(shù)對(duì)象prototype的值為對(duì)象則直接賦給obj,否則賦予Object的prototype值。
5.調(diào)用函數(shù)對(duì)象的[[Call]]方法并將結(jié)果賦給result。
6.如果result為對(duì)象則返回result,否則返回obj。

每個(gè)javascript對(duì)象都有一個(gè)[[Prototype]]的內(nèi)部屬性,[[Prototype]]的值為一個(gè)對(duì)象,叫做原型對(duì)象。當(dāng)程序在訪問javascript對(duì)象的某個(gè)屬性時(shí),首先會(huì)在當(dāng)前對(duì)象中搜索,搜索失敗則到原型鏈中搜索,直到搜索到相應(yīng)值,否則就為undefined。javascript的這種特性叫做原型繼承。[[Construct]]方法的第四步是實(shí)現(xiàn)原型繼承的關(guān)鍵,它指定了javascript對(duì)象的[[Prototype]]屬性。

var Dog = function(){
}
var animal = {};
Dog.prototype = animal;
var dog = new Dog();

上面代碼創(chuàng)建出來的dog對(duì)象的原型就為animal,它“繼承”了animal對(duì)象的屬性。原型繼承是另外一種面向?qū)ο蟮哪P?,相?duì)于“類”的繼承模型來說,原型繼承更加符合我們的現(xiàn)實(shí)世界的模型。原型繼承在javascript也是有非常廣的用途。

結(jié)語

函數(shù)這條線將javascript許多核心內(nèi)容串起來了,個(gè)人覺得這也是javascript最有意思的地方。本文主要是根據(jù)Ecma-262第五版規(guī)范中相關(guān)內(nèi)容進(jìn)行的總結(jié)和整理,由于能力有限,如有理解上的錯(cuò)誤,望批評(píng)指出。

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/78932.html

相關(guān)文章

  • 深入理解JavaScript

    摘要:深入之繼承的多種方式和優(yōu)缺點(diǎn)深入系列第十五篇,講解各種繼承方式和優(yōu)缺點(diǎn)。對(duì)于解釋型語言例如來說,通過詞法分析語法分析語法樹,就可以開始解釋執(zhí)行了。 JavaScript深入之繼承的多種方式和優(yōu)缺點(diǎn) JavaScript深入系列第十五篇,講解JavaScript各種繼承方式和優(yōu)缺點(diǎn)。 寫在前面 本文講解JavaScript各種繼承方式和優(yōu)缺點(diǎn)。 但是注意: 這篇文章更像是筆記,哎,再讓我...

    myeveryheart 評(píng)論0 收藏0
  • 深入理解javascript中的立即執(zhí)行函數(shù)(function(){…})()

    摘要:要理解立即執(zhí)行函數(shù),需要先理解一些函數(shù)的基本概念。函數(shù)表達(dá)式使用關(guān)鍵字聲明一個(gè)函數(shù),但未給函數(shù)命名,最后將匿名函數(shù)賦予一個(gè)變量,叫函數(shù)表達(dá)式,這是最常見的函數(shù)表達(dá)式語法形式。 javascript和其他編程語言相比比較隨意,所以javascript代碼中充滿各種奇葩的寫法,有時(shí)霧里看花,當(dāng)然,能理解各型各色的寫法也是對(duì)javascript語言特性更進(jìn)一步的深入理解。 ( functio...

    melody_lql 評(píng)論0 收藏0
  • 【進(jìn)階2-2期】JavaScript深入之從作用域鏈理解閉包

    摘要:使用上一篇文章的例子來說明下自由變量進(jìn)階期深入淺出圖解作用域鏈和閉包訪問外部的今天是今天是其中既不是參數(shù),也不是局部變量,所以是自由變量。 (關(guān)注福利,關(guān)注本公眾號(hào)回復(fù)[資料]領(lǐng)取優(yōu)質(zhì)前端視頻,包括Vue、React、Node源碼和實(shí)戰(zhàn)、面試指導(dǎo)) 本周正式開始前端進(jìn)階的第二期,本周的主題是作用域閉包,今天是第7天。 本計(jì)劃一共28期,每期重點(diǎn)攻克一個(gè)面試重難點(diǎn),如果你還不了解本進(jìn)階計(jì)...

    simpleapples 評(píng)論0 收藏0
  • ES6-7

    摘要:的翻譯文檔由的維護(hù)很多人說,阮老師已經(jīng)有一本關(guān)于的書了入門,覺得看看這本書就足夠了。前端的異步解決方案之和異步編程模式在前端開發(fā)過程中,顯得越來越重要。為了讓編程更美好,我們就需要引入來降低異步編程的復(fù)雜性。 JavaScript Promise 迷你書(中文版) 超詳細(xì)介紹promise的gitbook,看完再不會(huì)promise...... 本書的目的是以目前還在制定中的ECMASc...

    mudiyouyou 評(píng)論0 收藏0
  • JavaScript深入淺出

    摘要:理解的函數(shù)基礎(chǔ)要搞好深入淺出原型使用原型模型,雖然這經(jīng)常被當(dāng)作缺點(diǎn)提及,但是只要善于運(yùn)用,其實(shí)基于原型的繼承模型比傳統(tǒng)的類繼承還要強(qiáng)大。中文指南基本操作指南二繼續(xù)熟悉的幾對(duì)方法,包括,,。商業(yè)轉(zhuǎn)載請(qǐng)聯(lián)系作者獲得授權(quán),非商業(yè)轉(zhuǎn)載請(qǐng)注明出處。 怎樣使用 this 因?yàn)楸救藢儆趥吻岸耍虼宋闹兄豢炊?8 成左右,希望能夠給大家?guī)韼椭?...(據(jù)說是阿里的前端妹子寫的) this 的值到底...

    blair 評(píng)論0 收藏0
  • Javascript深入理解this作用域問題以及new/let/var/const對(duì)this作

    摘要:理解作用域高級(jí)程序設(shè)計(jì)中有說到對(duì)象是在運(yùn)行時(shí)基于函數(shù)的執(zhí)行環(huán)境綁定的在全局函數(shù)中,等于,而當(dāng)函數(shù)被作為某個(gè)對(duì)象調(diào)用時(shí),等于那個(gè)對(duì)象。指向與匿名函數(shù)沒有關(guān)系如果函數(shù)獨(dú)立調(diào)用,那么該函數(shù)內(nèi)部的,則指向。 理解this作用域 《javascript高級(jí)程序設(shè)計(jì)》中有說到: this對(duì)象是在運(yùn)行時(shí)基于函數(shù)的執(zhí)行環(huán)境綁定的:在全局函數(shù)中,this等于window,而當(dāng)函數(shù)被作為某個(gè)對(duì)象調(diào)用時(shí),t...

    snowLu 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<