日韩无码专区无码一级三级片|91人人爱网站中日韩无码电影|厨房大战丰满熟妇|AV高清无码在线免费观看|另类AV日韩少妇熟女|中文日本大黄一级黄色片|色情在线视频免费|亚洲成人特黄a片|黄片wwwav色图欧美|欧亚乱色一区二区三区

RELATEED CONSULTING
相關(guān)咨詢
選擇下列產(chǎn)品馬上在線溝通
服務(wù)時(shí)間:8:30-17:00
你可能遇到了下面的問題
關(guān)閉右側(cè)工具欄

新聞中心

這里有您想知道的互聯(lián)網(wǎng)營(yíng)銷解決方案
詳解JS中new調(diào)用函數(shù)原理

JavaScript 中經(jīng)常使用構(gòu)造函數(shù)創(chuàng)建對(duì)象(通過(guò) new 操作符調(diào)用一個(gè)函數(shù)),那在使用 new 調(diào)用一個(gè)函數(shù)的時(shí)候到底發(fā)生了什么?先看幾個(gè)例子,再解釋背后發(fā)生了什么。

一、看三個(gè)例子

1.1 無(wú) return 語(yǔ)句

構(gòu)造函數(shù)***沒有 return 語(yǔ)句,這也是使用構(gòu)造函數(shù)時(shí)默認(rèn)情況,***會(huì)返回一個(gè)新對(duì)象,如下:

 
 
 
  1. function Foo(age) {  
  2.   this.age = age;  
  3. }   
  4.  
  5. var o = new Foo(111);  
  6. console.log(o); 

這是常見的使用構(gòu)造函數(shù)創(chuàng)建對(duì)象的過(guò)程,打印出來(lái)的是 {age: 111}。

1.2 return 對(duì)象類型數(shù)據(jù)

構(gòu)造函數(shù)*** return 對(duì)象類型數(shù)據(jù):

 
 
 
  1. function Foo(age) { 
  2.   this.age = age; 
  3.   return { type: "我是顯式返回的" }; 
  4.  
  5. var o = new Foo(222); 
  6. console.log(o); 

打印出來(lái)的是 {type: '我是顯式返回的'},也就是說(shuō),return 之前的工作都白做了,***返回 return 后面的對(duì)象。

1.3 return 基本類型數(shù)據(jù)

那是不是只要構(gòu)造函數(shù)體內(nèi)***有 return,返回都是 return 后面的數(shù)據(jù)呢?

我們看下返回基本類型數(shù)據(jù)的情況:

 
 
 
  1. function Foo(age) {  
  2.   this.age = age;  
  3.  
  4.   return 1;  
  5. }  
  6.  
  7. var o = new Foo(333);  
  8. console.log(o); 

打印出來(lái)的是 {age: 333},和沒有 return 時(shí)效果一樣。跟預(yù)期不一樣,背后你原理看下面分析。

二、背后原理

2.1 非箭頭函數(shù)的情況

當(dāng)使用 new 操作符創(chuàng)建對(duì)象是,ES5 官方文檔在 函數(shù)定義 一節(jié)中做了如下定義 13.2.2 [[Construct]]

 
 
 
  1. When the[[Construct]]internal method for a Function object F is called with a possibly empty list of arguments, the following steps are taken:  
  2.  
  3.     Let obj be a newly created native ECMAScript object.  
  4.     Set all the internal methods of obj as specified in 8.12.  
  5.     Set the[[Class]]internal property of obj to Object.  
  6.     Set the[[Extensible]]internal property of obj to true.  
  7.     Let proto be the value of calling the[[Get]]internal property of F with argument "prototype".  
  8.     If Type(proto) is Object, set the[[Prototype]]internal property of obj to proto.  
  9.     If Type(proto) is not Object, set the[[Prototype]]internal property of obj to the standard built-in Object prototype object as described in 15.2.4.  
  10.     Let result be the result of calling the[[Call]]internal property of F, providing obj as the this value and providing the argument list passed into[[Construct]]as args.  
  11.     If Type(result) is Object then return result.  
  12.     Return obj. 

看第 8、9 步:

    8)調(diào)用函數(shù) F,將其返回值賦給 result;其中,F(xiàn) 執(zhí)行時(shí)的實(shí)參為傳遞給 [[Construct]](即 F 本身) 的參數(shù),F(xiàn) 內(nèi)部 this 指向 obj;

    9)如果 result 是 Object 類型,返回 result;

這也就解釋了如果構(gòu)造函數(shù)顯式返回對(duì)象類型,則直接返回這個(gè)對(duì)象,而不是返回最開始創(chuàng)建的對(duì)象。

***在看第 10 步:

    10)如果 F 返回的不是對(duì)象類型(第 9 步不成立),則返回創(chuàng)建的對(duì)象 obj。

如果構(gòu)造函數(shù)沒有顯式返回對(duì)象類型(顯式返回基本數(shù)據(jù)類型或者直接不返回),則返回最開始創(chuàng)建的對(duì)象。

2.2 箭頭函數(shù)的情況

那如果構(gòu)造函數(shù)是箭頭函數(shù)怎么辦?

箭頭函數(shù)中沒有 [[Construct]]方法,不能使用 new 調(diào)用,會(huì)報(bào)錯(cuò)。

NOTICE:其中 [[Construct]]就是指構(gòu)造函數(shù)本身。

    相關(guān)規(guī)范在 ES6 的官方文檔 中有提,但自從 ES6 以來(lái)的官方文檔巨難懂,在此不做表述。

三、new 調(diào)用函數(shù)完整過(guò)程

3.1 中文描述及相關(guān)代碼分析

除了箭頭函數(shù)之外的任何函數(shù),都可以使用 new 進(jìn)行調(diào)用,背后發(fā)生了什么,上節(jié)英文講述的很清楚了,再用中文描述如下:

1)創(chuàng)建 ECMAScript 原生對(duì)象 obj;

2)給 obj 設(shè)置原生對(duì)象的內(nèi)部屬性;(和原型屬性不同,內(nèi)部屬性表示為 [[PropertyName]],兩個(gè)方括號(hào)包裹屬性名,并且屬性名大寫,比如常見 [[Prototype]]、[[Constructor]])

3)設(shè)置 obj 的內(nèi)部屬性 [[Class]]為 Object;

4)設(shè)置 obj 的內(nèi)部屬性 [[Extensible]]為 true;

5)將 proto 的值設(shè)置為 F 的 prototype 屬性值;

6)如果 proto 是對(duì)象類型,則設(shè)置 obj 的內(nèi)部屬性 [[Prototype]]值為 proto;(進(jìn)行原型鏈關(guān)聯(lián),實(shí)現(xiàn)繼承的關(guān)鍵)

7)如果 proto 是不對(duì)象類型,則設(shè)置 obj 的內(nèi)部屬性 [[Prototype]]值為內(nèi)建構(gòu)造函數(shù) Object 的 prototype 值;(函數(shù) prototype 屬性可以被改寫,如果改成非對(duì)象類型,obj 的 [[Prototype]]就指向 Object 的原型對(duì)象)

8)9)10)見上節(jié)分析。(決定返回什么)

對(duì)于第 7 步的情況,見下面代碼:

 
 
 
  1. function Foo(name) {  
  2.   this.name = name;  
  3. }  
  4.  
  5. var o1 = new Foo("xiaoming");  
  6. console.log(o1.__proto__ === Foo.prototype); // true  
  7.  
  8.  
  9. // 重寫構(gòu)造函數(shù)原型屬性為非對(duì)象類型,實(shí)例內(nèi)部[[Prototype]]屬性指向 Object 原型對(duì)象  
  10. // 因?yàn)閷?shí)例是一個(gè)對(duì)象類型的數(shù)據(jù),默認(rèn)會(huì)繼承內(nèi)建對(duì)象的原型,  
  11. // 如果構(gòu)造函數(shù)的原型不滿足形成原型鏈的要求,那就跳過(guò)直接和內(nèi)建對(duì)象原型關(guān)聯(lián)  
  12. Foo.prototype = 1;  
  13. var o2 = new Foo("xiaohong");  
  14. console.log(o2.__proto__ === Foo.prototype); // false  
  15. console.log(o2.__proto__ === Object.prototype); // true 

3.2 更簡(jiǎn)潔的語(yǔ)言描述

若執(zhí)行 new Foo(),過(guò)程如下:

1)創(chuàng)建新對(duì)象 o;

2)給新對(duì)象的內(nèi)部屬性賦值,關(guān)鍵是給[[Prototype]]屬性賦值,構(gòu)造原型鏈(如果構(gòu)造函數(shù)的原型是 Object 類型,則指向構(gòu)造函數(shù)的原型;不然指向 Object 對(duì)象的原型);

3)執(zhí)行函數(shù) Foo,執(zhí)行過(guò)程中內(nèi)部 this 指向新創(chuàng)建的對(duì)象 o;

4)如果 Foo 內(nèi)部顯式返回對(duì)象類型數(shù)據(jù),則,返回該數(shù)據(jù),執(zhí)行結(jié)束;不然返回新創(chuàng)建的對(duì)象 o。

四、幾點(diǎn)說(shuō)明

4.1 判斷是否是 Object 類型

關(guān)于一個(gè)數(shù)據(jù)是否是 Object 類型,可以通過(guò) instanceof 操作符進(jìn)行判斷:如果 x instanceof Object 返回 true,則 x 為 Object 類型。

由上可知,null instanceof Object 返回 false,所以 null 不是 Object 類型,盡管typeof null 返回 "Object"。

4.2 instanceof 原理

instanceof 的工作原理是:在表達(dá)式 x instanceof Foo 中,如果 Foo 的原型(即 Foo.prototype)出現(xiàn)在 x 的原型鏈中,則返回 true,不然,返回 false。

因?yàn)楹瘮?shù)的原型可以被改寫,所以會(huì)出現(xiàn)在 x 通過(guò) Foo new 出來(lái)之后完全改寫 Foo 的原型 x instanceof Foo 返回 false 的情況。因?yàn)閷?shí)例創(chuàng)建之后重寫構(gòu)造函數(shù)原型,實(shí)例指向的原型已經(jīng)不是構(gòu)造函數(shù)的新的原型了,見下面代碼:

 
 
 
  1. const Foo = function() {};  
  2. const o = new Foo();  
  3. o instanceof Foo; // true  
  4. // 重寫 Foo 原型  
  5. Foo.prototype = {};  
  6. o instanceof Foo; // false  

新聞名稱:詳解JS中new調(diào)用函數(shù)原理
鏈接地址:http://www.5511xx.com/article/cojsigd.html