国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

詳解 JS 中 new 調用函數原理

付永剛 / 2837人閱讀

摘要:中經常使用構造函數創建對象通過操作符調用一個函數,那在使用調用一個函數的時候到底發生了什么先看幾個例子,再解釋背后發生了什么。其中就是指構造函數本身。

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

1)看三個例子 1.1 無 return 語句

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

function Foo(age) {
  this.age = age;
}

var o = new Foo(111);
console.log(o);

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

1.2 return 對象類型數據

構造函數最后 return 對象類型數據:

function Foo(age) {
  this.age = age;

  return { type: "我是顯式返回的" };
}

var o = new Foo(222);
console.log(o);

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

1.3 return 基本類型數據

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

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

function Foo(age) {
  this.age = age;

  return 1;
}

var o = new Foo(333);
console.log(o);

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

2)背后原理 2.1 非箭頭函數的情況

當使用 new 操作符創建對象是,ES5 官方文檔在 函數定義 一節中做了如下定義 13.2.2 [[Construct]]

When the [[Construct]] internal method for a Function object F is called with a possibly empty list of arguments, the following steps are taken:

Let obj be a newly created native ECMAScript object.

Set all the internal methods of obj as specified in 8.12.

Set the [[Class]] internal property of obj to Object.

Set the [[Extensible]] internal property of obj to true.

Let proto be the value of calling the [[Get]] internal property of F with argument "prototype".

If Type(proto) is Object, set the [[Prototype]] internal property of obj to proto.

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.

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.

If Type(result) is Object then return result.

Return obj.

看第 8、9 步:

8)調用函數 F,將其返回值賦給 result;其中,F 執行時的實參為傳遞給 [[Construct]](即 F 本身) 的參數,F 內部 this 指向 obj
9)如果 resultObject 類型,返回 result

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

最后在看第 10 步:

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

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

2.2 箭頭函數的情況

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

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

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

相關規范在 ES6 的官方文檔 中有提,但自從 ES6 以來的官方文檔巨難懂,在此不做表述。
3)new 調用函數完整過程 3.1 中文描述及相關代碼分析

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

1)創建 ECMAScript 原生對象 obj
2)給 obj 設置原生對象的內部屬性;(和原型屬性不同,內部屬性表示為 [[PropertyName]],兩個方括號包裹屬性名,并且屬性名大寫,比如常見 [[Prototype]][[Constructor]]
3)設置 obj 的內部屬性 [[Class]]Object
4)設置 obj 的內部屬性 [[Extensible]]true
5)將 proto 的值設置為 Fprototype 屬性值;
6)如果 proto 是對象類型,則設置 obj 的內部屬性 [[Prototype]] 值為 proto;(進行原型鏈關聯,實現繼承的關鍵
7)如果 proto 是不對象類型,則設置 obj 的內部屬性 [[Prototype]] 值為內建構造函數 Objectprototype 值;(函數 prototype 屬性可以被改寫,如果改成非對象類型,obj[[Prototype]] 就指向 Object 的原型對象)
8)9)10)見上節分析。(決定返回什么)

對于第 7 步的情況,見下面代碼:

function Foo(name) {
  this.name = name;
}

var o1 = new Foo("xiaoming");
console.log(o1.__proto__ === Foo.prototype); // true

// 重寫構造函數原型屬性為非對象類型,實例內部 [[Prototype]] 屬性指向 Object 原型對象
// 因為實例是一個對象類型的數據,默認會繼承內建對象的原型,
// 如果構造函數的原型不滿足形成原型鏈的要求,那就跳過直接和內建對象原型關聯
Foo.prototype = 1;
var o2 = new Foo("xiaohong");
console.log(o2.__proto__ === Foo.prototype); // false
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)幾點說明 4.1 判斷是否是 Object 類型

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

由上可知,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 的情況。因為實例創建之后重寫構造函數原型,實例指向的原型已經不是構造函數的新的原型了,見下面代碼:

const Foo = function() {};

const o = new Foo();

o instanceof Foo; // true

// 重寫 Foo 原型
Foo.prototype = {};
o instanceof Foo; // false
參考資料

What values can a constructor return to avoid returning this?
[[Construct]] internal method

文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。

轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/95783.html

相關文章

  • JavaScript深入淺出

    摘要:理解的函數基礎要搞好深入淺出原型使用原型模型,雖然這經常被當作缺點提及,但是只要善于運用,其實基于原型的繼承模型比傳統的類繼承還要強大。中文指南基本操作指南二繼續熟悉的幾對方法,包括,,。商業轉載請聯系作者獲得授權,非商業轉載請注明出處。 怎樣使用 this 因為本人屬于偽前端,因此文中只看懂了 8 成左右,希望能夠給大家帶來幫助....(據說是阿里的前端妹子寫的) this 的值到底...

    blair 評論0 收藏0
  • Nodejs高性能原理(下) --- 事件循環詳解

    摘要:如果一個即時定時器是被一個正在執行的回調排入隊列的,則該定時器直到下一次事件循環迭代才會被觸發。參數描述在事件循環的當前回合結束時要調用的函數。事件輪詢隨后的調用,會在任何事件包括定時器之前運行。 系列文章 Nodejs高性能原理(上) --- 異步非阻塞事件驅動模型Nodejs高性能原理(下) --- 事件循環詳解 前言 終于開始我nodejs的博客生涯了,先從基本的原理講起.以前寫...

    newsning 評論0 收藏0
  • 詳解js的繼承(一)

    摘要:構造函數,實例構造函數,是用來創建對象的函數,本質上也是函數。這里剛好解釋一下時,說到的,可以通過實例的訪問構造函數,但是本質上是原型對象的屬性。 前言 最近在學vue,到周末終于有空寫一些東西了(想想又能騙贊,就有點小激動!)。在javascript基礎中,除了閉包之外,繼承也是一個難點。因為考慮到篇幅較長,所以打算分成兩個部分來寫。同樣基于《javascript高級程序設計》,做一...

    Object 評論0 收藏0
  • three.js 入門詳解(二)

    摘要:首先,下載并在的中使用然后,我們需要準備一個模型,在函數中,創建變量,用于導入模型導入模型的時候,接受兩個參數,第一個表示模型路徑,第二個表示完成導入后的回調函數,一般我們需要在這個回調函數中將導入的模型添加到場景中。 9. 動畫 在本章之前,所有畫面都是靜止的,本章將介紹如果使用Three.js進行動態畫面的渲染。此外,將會介紹一個Three.js作者寫的另外一個庫,用來觀測每秒幀數...

    G9YH 評論0 收藏0

發表評論

0條評論

付永剛

|高級講師

TA的文章

閱讀更多
最新活動
閱讀需要支付1元查看
<