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

資訊專欄INFORMATION COLUMN

javascript中Function、ArrowFunction和GeneratorFunctio

cyixlq / 2909人閱讀

摘要:等價(jià)與注意如果構(gòu)造函數(shù)有自己的返回,那么情況有所不同。,定義了的屬性,默認(rèn)是聲明的函數(shù)名,匿名函數(shù)是。匿名函數(shù)表達(dá)式和函數(shù)聲明都不會(huì)創(chuàng)建匿名作用域。

ECMAScript規(guī)范中對(duì)Function的文檔描述,我認(rèn)為是ECMAScript規(guī)范中最復(fù)雜也是最不好理解的一部分,它涉及到了各方面。光對(duì)Function就分了Function Definitions、Arrow Function Definitions、Method Definitions、Generator Function Definitions、Class Definitions、Async Function Definitions、Async Arrow Function Definitions這幾塊。我準(zhǔn)備花三章來(lái)介紹Function。這篇文章主要是理解ArrowFunction和GeneratorFunction,當(dāng)然還包括最基本最普通的Function Definitions。

Function

在了解Function Definitions之前我們需要知道函數(shù)對(duì)象(Function Object)。我們都知道Function本質(zhì)上也是一個(gè)對(duì)象,所以普通對(duì)象有的方法Function對(duì)象都有,此外Function對(duì)象還有自己的內(nèi)部方法。所有Function對(duì)象都有一個(gè)[[Call]]的內(nèi)部方法,有了這個(gè)方法Function對(duì)象才能被用作函數(shù)調(diào)用,即你***()時(shí)內(nèi)部調(diào)用就是[[Call]]方法,當(dāng)然不是所有有[[Call]]方法的Function對(duì)象都可以進(jìn)行***()調(diào)用,常見(jiàn)的Map、Set等方法雖然有[[Call]]方法,但是你不能進(jìn)行Map()和Set(),這時(shí)候就用到了Function對(duì)象的另一個(gè)內(nèi)部方法[[Construct]],當(dāng)Function作為構(gòu)造函數(shù)調(diào)用時(shí),就會(huì)使用[[Construct]]方法。

注意:不是所有Function對(duì)象都有[[Construct]]方法。只有當(dāng)Function作為構(gòu)造函數(shù)調(diào)用時(shí),才會(huì)有[[Construct]]方法,比如ArrowFunction和GeneratorFunction只有[[Call]]方法沒(méi)有[[Construct]]方法。

[[Call]]

先說(shuō)[[Call]]方法,看到這個(gè)名字很容易讓人想起Function.prototype中的call方法,沒(méi)錯(cuò)Function.prototype.call以及Function.prototype.apply都是顯示的調(diào)用了[[Call]]方法,之所以說(shuō)顯示調(diào)用是相比于***()調(diào)用,call和apply要簡(jiǎn)單直接的多。[[Call]]方法接受兩個(gè)參數(shù),一個(gè)是thisArgument,另一個(gè)是argumentsList,thisArgument即表示了function中的this對(duì)象,argumentsList代表了function中的參數(shù)列表,看!和Function.prototype.apply的調(diào)用方式是如此的相似。

function foo(){}

foo(1,2)     //當(dāng)執(zhí)行foo()方法時(shí),實(shí)際上內(nèi)部是如下調(diào)用

foo.[[Call]](undefined,? 1, 2 ?)   //? ?表示ECMAScript的List規(guī)范類型

//注意,如果你是隱式調(diào)用function,那么thisArgument是undefined,不是常說(shuō)的全局對(duì)象window,
//只是在[[Call]]內(nèi)部執(zhí)行時(shí)檢測(cè)到如果thisArgument是undefined或null,
//且在非嚴(yán)格模式下才會(huì)變成全局對(duì)象,即foo(1,2)你可以認(rèn)為等價(jià)與下面的:

foo.call(null,1,2)
foo.apply(undefined,[1,2])
//-------------------
var a={
   foo:function(){}
}

a.foo(1,2)   
//等價(jià)與==>   foo.[[Call]](a,? 1, 2 ?)
//等價(jià)與==>   foo.call(a,1,2)
//等價(jià)與==>   foo.apply(a,[1,2])

這里有個(gè)建議,以后你遇到this指向問(wèn)題的時(shí)候,你把function轉(zhuǎn)成call或者apply模式,你就能清楚的明白this指向什么。

[[Construct]]

[[Construct]]內(nèi)部方法主要有new關(guān)鍵字調(diào)用Function時(shí)才會(huì)執(zhí)行[[Construct]]方法。[[Construct]]方法主要接受兩個(gè)參數(shù)一個(gè)是argumentsList, 還有一個(gè)是newTarget。newTarget正常調(diào)用下指向調(diào)用的function對(duì)象。比如foo(),newTarget就是foo,你可以在函數(shù)內(nèi)部用new.target訪問(wèn)到。構(gòu)造函數(shù)中的this對(duì)象與newTarget有關(guān),如果newTarget.prototype存在,且是Object對(duì)象,則this就是ObjectCreate(newTarget.prototype),ObjectCreate是Object.create內(nèi)部調(diào)用的方法,如果newTarget.prototype不存在或者不是Object對(duì)象,this相當(dāng)于ObjectCreate(Object.prototype)。

function Foo(){}

var fooInstance = new Foo(1,2)
//等價(jià)與==>  var fooInstance = Foo.[[Construct]](? 1, 2 ?,Foo);

fooInstance instanceof Foo   //true

Object.create(Foo.prototype) instanceof Foo    //true

//注意如果構(gòu)造函數(shù)有自己的return返回,那么情況有所不同。
//返回的是Object,則構(gòu)造函數(shù)的實(shí)例就是返回的對(duì)象
//返回的不是Object,相當(dāng)于默認(rèn)沒(méi)有返回

function Foo(){ return {a:1}}

var fooInstance = new Foo(1,2)

fooInstance instanceof Foo   //false,注意不是true,fooInstance不是Foo的實(shí)例

Object.create(Foo.prototype) instanceof Foo    //true

//只要Foo.prototype存在且是對(duì)象,那么Object.create(Foo.prototype)永遠(yuǎn)是Foo的一個(gè)實(shí)例
Function Definitions

Function Definitions包含了FunctionDeclaration和FunctionExpression,有一些早期錯(cuò)誤檢測(cè)添加到Function Definitions中,其中在function中的let、const和var聲明的變量規(guī)則參考上一篇文章var、let、const聲明的區(qū)別,另外有一些附加的早期錯(cuò)誤:

function中的參數(shù)被認(rèn)為是var聲明,因此:

function foo(a,b){
    let a = 1;     //SyntaxError,重復(fù)聲明a
}
foo();

如果函數(shù)體是嚴(yán)格模式而參數(shù)列表不是簡(jiǎn)單參數(shù)列表,則語(yǔ)法錯(cuò)誤:

//不是簡(jiǎn)單參數(shù)指的是包含解構(gòu)賦值
function foo(a=1,...c){
    "use strict"      //SyntaxError
}

//如果"use strict"在函數(shù)體外定義則沒(méi)有錯(cuò)誤
"use strict" 
function foo(a=1,...c){}    //ok

函數(shù)體以及函數(shù)參數(shù)不能直接出現(xiàn)super

function foo(super){}   //SyntaxError

function foo(){ super();} //SyntaxError
FunctionDeclaration

FunctionDeclaration分為帶變量名的函數(shù)聲明以及匿名函數(shù)聲明,匿名函數(shù)聲明只能在export中可用,其它任何地方使用匿名函數(shù)聲明都報(bào)錯(cuò)。
在進(jìn)行評(píng)估腳本和函數(shù)的時(shí)候會(huì)對(duì)包含在其中的函數(shù)聲明進(jìn)行InstantiateFunctionObject方法,即初始化函數(shù)對(duì)象。注:該方法是在執(zhí)行腳本和函數(shù)代碼之前進(jìn)行的。
InstantiateFunctionObject方法簡(jiǎn)單來(lái)說(shuō)做了三步:1.FunctionCreate 2.makeConstructor 3. SetFunctionName。分開(kāi)說(shuō)

FunctionCreate創(chuàng)建了一個(gè)Function對(duì)象F,包括初始化內(nèi)部插槽的值,比如上面提到的[[Call]],[[Construct]]方法的定義,原型對(duì)象[[Prototype]]的值,這里指的是Function.prototype,F(xiàn)的length屬性,指function的參數(shù)個(gè)數(shù)。

makeConstructor(F),這句話不是指創(chuàng)建構(gòu)造器,這里指定義了F的prototype屬性的值,以及prototype中constructor的值,普通函數(shù)prototype相當(dāng)于object.create(Object.prototype),constructor===F。

SetFunctionName,定義了F的name屬性,默認(rèn)是聲明的函數(shù)名,匿名函數(shù)是default。

function foo(a,b){};

foo.__proto__ === Function.prototype;
foo.length === 2;
foo.prototype.__proto__ === Object.prototype;
foo.prototype.constructor === foo;
foo.name === "foo";
FunctionExpression

FunctionExpression也分為兩類,有變量名的函數(shù)表達(dá)式和匿名函數(shù)表達(dá)式。函數(shù)表達(dá)式在執(zhí)行時(shí)也會(huì)創(chuàng)建Function對(duì)象,步驟和函數(shù)聲明相似。其中匿名函數(shù)表達(dá)式不會(huì)定義屬性name,即不會(huì)執(zhí)行第三步中的SetFunctionName。有變量名的函數(shù)表達(dá)式與函數(shù)聲明以及匿名函數(shù)表達(dá)式的區(qū)別在于作用域鏈,我們都知道一旦函數(shù)表達(dá)式中定義了變量名,我們就可以在函數(shù)體內(nèi)通過(guò)該變量名調(diào)用函數(shù)自身??蓡?wèn)題來(lái)了,該函數(shù)變量名是定義在哪里呢?函數(shù)外還是在函數(shù)內(nèi)呢?

var func = function foo(){};
foo();              //Uncaught ReferenceError: foo is not defined
//顯然沒(méi)有在函數(shù)外定義函數(shù)表達(dá)式的變量名,那么是定義在函數(shù)內(nèi)的?

//我提到過(guò)在全局作用域和函數(shù)作用域中,var、function聲明的變量,let和const不能重復(fù)聲明。
var func = function foo(){
    let foo = 1;   //ok,可見(jiàn)函數(shù)表達(dá)式的變量名也不是在函數(shù)內(nèi)聲明的。
};
foo();

看到這可能有人會(huì)認(rèn)為函數(shù)表達(dá)式的變量名可能允許let和const進(jìn)行覆蓋。其實(shí)不是,有變量名的函數(shù)表達(dá)式在創(chuàng)建Function對(duì)象的時(shí)候,創(chuàng)建了一個(gè)匿名作用域,在該作用域中定義了函數(shù)表達(dá)式的變量名。按上面這個(gè)例子,foo函數(shù)的外部作用域并不是全局作用域,而是一個(gè)匿名作用域,匿名作用域的外部作用域才是真正的全局作用域。匿名函數(shù)表達(dá)式和函數(shù)聲明都不會(huì)創(chuàng)建匿名作用域。

ArrowFunction

ArrowFunction(箭頭函數(shù))是ES6新增的一種新語(yǔ)法,主要是用來(lái)簡(jiǎn)化function的寫(xiě)法,更準(zhǔn)確的說(shuō)是簡(jiǎn)化匿名函數(shù)表達(dá)式的一種寫(xiě)法。因此匿名函數(shù)表達(dá)式的規(guī)則也適用于ArrowFunction,不過(guò)兩者還是有區(qū)別的,ArrowFunction中沒(méi)有規(guī)定不能直接出現(xiàn)super,也就是說(shuō)在ArrowFunction中可以用super方法,其次ArrowFunction內(nèi)部沒(méi)有[[Construct]]方法,因此不能作為構(gòu)造器調(diào)用,所以在創(chuàng)建Function對(duì)象時(shí)不執(zhí)行makeConstructor方法。最重要一點(diǎn)就是ArrowFunction沒(méi)有本地的this對(duì)象。
我們上面提道所有Function對(duì)象都有[[Call]]內(nèi)部方法,接受this對(duì)象和參數(shù)列表兩個(gè)字段。此外Function對(duì)象還有一個(gè)[[ThisMode]]內(nèi)部屬性,用來(lái)判斷是ArrowFunction還是非ArrowFunction,如果是ArrowFunction,那么不管[[Call]]中傳來(lái)的this是什么都會(huì)被丟棄。此外arguments, super和new.target和this也是一樣的。我在以前的文章中稍微提到過(guò)ArrowFunction中的this對(duì)象,我在這重新講一下:

var name = "outer arrow";
var obj = {
    name:"inner arrow",
    arrow: () => {
        console.log(this.name)
    }
}
obj.arrow();         //outer arrow,不是inner arrow

我們?cè)贏rrowFunction遇到this對(duì)象時(shí),你不要把this看成是ArrowFunction的一部分,你從ArrowFunction中拿出this放到ArrowFunction的外部,觀察外部的this對(duì)象是什么,外部的this對(duì)象就是ArrowFunction的this對(duì)象。此外還要清楚不管是call還是apply都是對(duì)ArrowFunction無(wú)效的,它們最終調(diào)用的都是[[Call]]內(nèi)部方法,當(dāng)然bind也是無(wú)效的。

我們看一下ArrowFunction中的super應(yīng)用,還是改編了MDN中的例子:

var obj1 = {
  method() {
    console.log("method 1");
  }
}

var obj2 = {
  method() {
     console.log("method 2");
     return ()=>{super.method();}
  }
}

Object.setPrototypeOf(obj2, obj1);
var arrow = obj2.method()         //method 2
arrow();          //method 1

注意:method1和method2其實(shí)就是Method Definitions。

如果單看arrow這個(gè)函數(shù),它本身是不可能有super的,因?yàn)闆](méi)有任何繼承關(guān)系,只是一個(gè)單一的ArrowFunction,但是你放在obj2中就有了意義,Object.setPrototypeOf(obj2, obj1);這句話把obj1變?yōu)閛bj2的原型對(duì)象,obj2繼承了obj1的屬性和方法,obj2的super對(duì)象就是obj1,因此ArrowFunction中的super參照this可知,該super是obj1。

總的一句話概括ArrowFunction中的this,arguments, super和new.target都是通過(guò)原型鏈來(lái)查找的,不是動(dòng)態(tài)創(chuàng)建的。

GeneratorFunction

關(guān)于GeneratorFunction我不準(zhǔn)備講怎么用它,我只談一下它的工作原理。說(shuō)實(shí)話GeneratorFunction用到的情況實(shí)在太少了,我自己在做項(xiàng)目的時(shí)候基本不會(huì)用到GeneratorFunction,但這不妨礙我們學(xué)習(xí)GeneratorFunction。
GeneratorFunction也是Function的一種,F(xiàn)unction的規(guī)則也適用于GeneratorFunction,此外在GeneratorFunction的參數(shù)中不能出現(xiàn)yield表達(dá)式。
GeneratorFunction與普通的Function一樣,都會(huì)創(chuàng)建Function對(duì)象,但是區(qū)別也在這里,上面提到了Function的[[Prototype]]原型值是Function.prototype,但是GeneratorFunction不同,它的[[Prototype]]原型值是%Generator%,此外Function的prototype屬性是ObjectCreate(Object.prototype),但是GeneratorFunction的卻是ObjectCreate(%GeneratorPrototype%)而且prototype中沒(méi)有constructor屬性,不能作為構(gòu)造器調(diào)用。

注:Function.prototype也寫(xiě)作%FunctionPrototype%,Object.prototype也寫(xiě)作%ObjectPrototype%。%Generator%和%GeneratorPrototype%沒(méi)有全局名稱,不能直接訪問(wèn)。

執(zhí)行函數(shù)時(shí),內(nèi)部調(diào)用了[[Call]]方法,但是和Function不同的是GeneratorFunction返回的不是函數(shù)的執(zhí)行結(jié)果,而是一個(gè)對(duì)象,這個(gè)對(duì)象是GeneratorFunction的一個(gè)實(shí)例,這跟[[Construct]]方法很像。

function* gen(){}
gen();    //返回的其實(shí)是Object.create(gen.prototype)對(duì)象。

你可以比較gen()和Object.create(gen.prototype)這兩個(gè)對(duì)象,你會(huì)發(fā)現(xiàn)它們很像,只是Object.create(gen.prototype)缺少了Generator對(duì)象的一些內(nèi)部狀態(tài)??梢哉f(shuō)雖然GeneratorFunction沒(méi)有[[Construct]]方法,不能作為構(gòu)造器調(diào)用,但是你可以認(rèn)為GeneratorFunction本身就是一個(gè)構(gòu)造器。

此外在創(chuàng)建GeneratorFunction對(duì)象時(shí),還做了一些其他操作,我們?cè)谝郧暗奈恼轮刑岬搅藞?zhí)行上下文,GeneratorFunction對(duì)象有個(gè)[[GeneratorContext]]內(nèi)部插槽,當(dāng)評(píng)估GeneratorFunction定義的代碼時(shí),GeneratorFunction對(duì)象把當(dāng)前正在運(yùn)行的執(zhí)行上下文存在了[[GeneratorContext]]中,并掛起了該正在運(yùn)行的執(zhí)行上下文,因此對(duì)GeneratorFunction中代碼的評(píng)估被暫停了,從而執(zhí)行其它代碼,當(dāng)你調(diào)用GeneratorFunction對(duì)象的next方法時(shí),他把[[GeneratorContext]]中保存的執(zhí)行上下文取出放到執(zhí)行上下文棧頂部,成為正在運(yùn)行的執(zhí)行上下文,此時(shí)GeneratorFunction中暫定評(píng)估的代碼又重新開(kāi)始執(zhí)行,直到執(zhí)行完畢或者遇到y(tǒng)ield表達(dá)式。當(dāng)遇到y(tǒng)ield表達(dá)式時(shí),它又把正在運(yùn)行的執(zhí)行上下文從棧中移除,暫停對(duì)GeneratorFunction代碼的執(zhí)行,等待下次next方法調(diào)用之后繼續(xù)執(zhí)行。
簡(jiǎn)單來(lái)說(shuō)GeneratorFunction的實(shí)現(xiàn)原理其實(shí)是運(yùn)行的執(zhí)行上下文之間不停來(lái)回切換。

GeneratorFunction基本就提到這里了,最后附上ECMAScript關(guān)于GeneratorFunction的一張關(guān)系圖片:

結(jié)束語(yǔ)

關(guān)于Function的簡(jiǎn)單介紹就暫時(shí)告一段落,在下一篇文章中我會(huì)來(lái)簡(jiǎn)單介紹Promise和AsyncFunction。

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

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

相關(guān)文章

  • es6之箭頭函數(shù)

    摘要:箭頭函數(shù)沒(méi)有綁定,意味著箭頭函數(shù)內(nèi)部的值只能通過(guò)查找作用域鏈來(lái)確定。無(wú)論此后箭頭函數(shù)在何處執(zhí)行,該對(duì)象都是可用的。 箭頭函數(shù) es6的箭頭函數(shù),顧名思義箭頭函數(shù)是使用一個(gè)箭頭( => )來(lái)定義的函數(shù),這很容易理解但是它有很多行為與傳統(tǒng)的js函數(shù)不同: 沒(méi)有 this 、 super 、 arguments 。 不能被使用 new 調(diào)用: 箭頭函數(shù)沒(méi)有 [[Construct]] 方法...

    songjz 評(píng)論0 收藏0
  • JavaScript的this

    摘要:指向的改變構(gòu)造函數(shù)中的操作符會(huì)調(diào)用函數(shù)的內(nèi)部的方法,創(chuàng)建對(duì)象,之后調(diào)用函數(shù)的方法,把新創(chuàng)建對(duì)象作為值。調(diào)用函數(shù)時(shí)與設(shè)置的值以及箭頭函數(shù)皆為動(dòng)態(tài)的改變指針的方法。這一特性使得箭頭函數(shù)在中的函數(shù)中使用起來(lái)很方便。 原文地址 JavaScript中的this 原理 錯(cuò)誤的this指向 通常所說(shuō)的:如果是全局環(huán)境中,this指向全局對(duì)象,如果是對(duì)象的方法,這this指向這個(gè)對(duì)象。 例子1: ...

    Salamander 評(píng)論0 收藏0
  • 【知識(shí)點(diǎn)】Javascript分號(hào)規(guī)則

    摘要:花點(diǎn)時(shí)間搞清楚中的分號(hào)規(guī)則吧不管你喜歡結(jié)尾帶分號(hào)或省略分號(hào)的模式分號(hào)允許的場(chǎng)景分號(hào)一般允許出現(xiàn)在大部分語(yǔ)句的末尾,比如等栗子僅有一個(gè)分號(hào)可以表示空語(yǔ)句在中合法,比如可解析為三個(gè)空語(yǔ)句空語(yǔ)句可用于輔助產(chǎn)生語(yǔ)法合法的解析結(jié)果,如如果沒(méi)有末尾的 花點(diǎn)時(shí)間搞清楚JS中的分號(hào)規(guī)則吧~~~不管你喜歡結(jié)尾帶分號(hào)或省略分號(hào)的模式 分號(hào)允許的場(chǎng)景 分號(hào)一般允許出現(xiàn)在大部分語(yǔ)句(statement)的末尾...

    kun_jian 評(píng)論0 收藏0
  • ES6對(duì)函數(shù)的改動(dòng)

    摘要:改動(dòng)函數(shù)的改變不算太大,都是一些其他語(yǔ)言早就有的功能,而一直比較欠缺的,比如函數(shù)參數(shù)默認(rèn)值,任意參數(shù)的表示法,最大的變化應(yīng)該是支持箭頭函數(shù)其他語(yǔ)言稱之為表達(dá)式,一種對(duì)匿名函數(shù)的一種簡(jiǎn)寫(xiě)方式,以下來(lái)探討一下函數(shù)在中的一些改變默認(rèn)參數(shù)任意參數(shù)操 ES6 functions改動(dòng) ????ES6函數(shù)的改變不算太大,都是一些其他語(yǔ)言早就有的功能,而Javascript一直比較欠缺的,比如函數(shù)參數(shù)...

    kk_miles 評(píng)論0 收藏0
  • 關(guān)于 this 你想知道的一切都在這里

    摘要:如下在第一個(gè)例子中,被點(diǎn)擊元素是通過(guò),這個(gè)形式參數(shù)來(lái)代替的。它的作用和形式參數(shù)類似,其本質(zhì)上是一個(gè)對(duì)象的引用,它的特殊性在于不需要手動(dòng)傳值,所以使用起來(lái)會(huì)更加簡(jiǎn)單和方便。 無(wú)論在 javascript 的日常使用中還是前端面試過(guò)程中,this 的出鏡率都極高。這無(wú)疑說(shuō)明了,this 的重要性。但是 this 非常靈活,導(dǎo)致很多人覺(jué)得 this 的行為難以理解。本文從為什么要有 this...

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

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

0條評(píng)論

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