成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

詳解JS中new調用函數原理

開發 前端
JavaScript 中經常使用構造函數創建對象(通過 new 操作符調用一個函數),那在使用 new 調用一個函數的時候到底發生了什么?先看幾個例子,再解釋背后發生了什么。

[[235817]]

JavaScript 中經常使用構造函數創建對象(通過 new 操作符調用一個函數),那在使用 new 調用一個函數的時候到底發生了什么?先看幾個例子,再解釋背后發生了什么。

一、看三個例子

1.1 無 return 語句

構造函數***沒有 return 語句,這也是使用構造函數時默認情況,***會返回一個新對象,如下:

 

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

這是常見的使用構造函數創建對象的過程,打印出來的是 {age: 111}。

1.2 return 對象類型數據

構造函數*** return 對象類型數據:

 

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

打印出來的是 {type: '我是顯式返回的'},也就是說,return 之前的工作都白做了,***返回 return 后面的對象。

1.3 return 基本類型數據

那是不是只要構造函數體內***有 return,返回都是 return 后面的數據呢?

我們看下返回基本類型數據的情況:

 

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

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

二、背后原理

2.1 非箭頭函數的情況

當使用 new 操作符創建對象是,ES5 官方文檔在 函數定義 一節中做了如下定義 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)調用函數 F,將其返回值賦給 result;其中,F 執行時的實參為傳遞給 [[Construct]](即 F 本身) 的參數,F 內部 this 指向 obj;

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

這也就解釋了如果構造函數顯式返回對象類型,則直接返回這個對象,而不是返回最開始創建的對象。

***在看第 10 步:

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

如果構造函數沒有顯式返回對象類型(顯式返回基本數據類型或者直接不返回),則返回最開始創建的對象。

2.2 箭頭函數的情況

那如果構造函數是箭頭函數怎么辦?

箭頭函數中沒有 [[Construct]] 方法,不能使用 new 調用,會報錯。

NOTICE:其中 [[Construct]] 就是指構造函數本身。

    相關規范在 ES6 的官方文檔 中有提,但自從 ES6 以來的官方文檔巨難懂,在此不做表述。

三、new 調用函數完整過程

3.1 中文描述及相關代碼分析

除了箭頭函數之外的任何函數,都可以使用 new 進行調用,背后發生了什么,上節英文講述的很清楚了,再用中文描述如下:

1)創建 ECMAScript 原生對象 obj;

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

3)設置 obj 的內部屬性 [[Class]] 為 Object;

4)設置 obj 的內部屬性 [[Extensible]] 為 true;

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

6)如果 proto 是對象類型,則設置 obj 的內部屬性 [[Prototype]] 值為 proto;(進行原型鏈關聯,實現繼承的關鍵)

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

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

對于第 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. // 重寫構造函數原型屬性為非對象類型,實例內部 [[Prototype]] 屬性指向 Object 原型對象  
  10. // 因為實例是一個對象類型的數據,默認會繼承內建對象的原型,  
  11. // 如果構造函數的原型不滿足形成原型鏈的要求,那就跳過直接和內建對象原型關聯  
  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 更簡潔的語言描述

若執行 new Foo(),過程如下:

1)創建新對象 o;

2)給新對象的內部屬性賦值,關鍵是給[[Prototype]]屬性賦值,構造原型鏈(如果構造函數的原型是 Object 類型,則指向構造函數的原型;不然指向 Object 對象的原型);

3)執行函數 Foo,執行過程中內部 this 指向新創建的對象 o;

4)如果 Foo 內部顯式返回對象類型數據,則,返回該數據,執行結束;不然返回新創建的對象 o。

四、幾點說明

4.1 判斷是否是 Object 類型

關于一個數據是否是 Object 類型,可以通過 instanceof 操作符進行判斷:如果 x instanceof Object 返回 true,則 x 為 Object 類型。

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

4.2 instanceof 原理

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

因為函數的原型可以被改寫,所以會出現在 x 通過 Foo new 出來之后完全改寫 Foo 的原型 x instanceof Foo 返回 false 的情況。因為實例創建之后重寫構造函數原型,實例指向的原型已經不是構造函數的新的原型了,見下面代碼:

 

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

 

責任編輯:龐桂玉 來源: segmentfault
相關推薦

2015-07-10 10:34:57

JSPatchJS調用

2015-07-10 10:40:29

JSPatchOCJS

2011-08-22 17:13:00

LuaC++函數

2017-03-12 19:51:38

js實用跨域

2011-06-28 13:12:07

Qt 調用 DLL DLL

2009-07-03 17:33:06

JSP中調用JavaB

2023-10-23 19:27:21

Go函數

2010-09-08 14:03:41

SQL函數CONVERT

2023-05-31 11:57:38

js函數計算高度

2021-09-06 13:12:05

前端JavaScript編程

2016-09-26 17:15:51

2017-01-13 15:45:05

Linuxfork函數詳解

2010-09-06 14:58:42

SQL函數

2010-09-09 11:12:49

SQL函數DATALENGTH

2010-10-09 10:30:03

JS event

2023-10-27 11:27:14

Go函數

2022-06-09 08:17:30

Python__new__

2010-09-10 16:02:13

SQLCHARINDEX函數

2012-04-16 13:47:37

JavaMatlab

2017-07-27 15:52:10

函數調用堆棧結構
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 欧美 日本 国产 | 国产中文原创 | 91午夜在线 | 成人毛片视频免费 | 国产在线视频三区 | 一级片视频免费观看 | www.日日操 | 国产清纯白嫩初高生在线播放视频 | 欧美日批 | 91大神在线看 | 在线国产一区二区三区 | 亚洲欧美精品国产一级在线 | 日韩精品免费 | h肉视频 | 夜夜艹 | 久久久无码精品亚洲日韩按摩 | 精品福利视频一区二区三区 | 精品视频一区在线 | 免费国产网站 | 日韩av成人| 欧美一级欧美一级在线播放 | 日韩av电影在线观看 | 极品久久 | 色av一区二区三区 | 久久精品免费观看 | 国产乱码精品一区二区三区忘忧草 | 国产在线视频在线观看 | 亚洲成人一区二区三区 | 免费毛片网| 一级片在线视频 | 久久久高清 | av在线免费观看网站 | 日韩成人在线电影 | 成人福利网 | 国内精品伊人久久久久网站 | 亚洲国产成人av好男人在线观看 | 91一区二区| 国产精品久久久久久久白浊 | 毛片视频网站 | 欧美精品一区二区免费视频 | 成人日韩 |