亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

深入聊一聊JS中new的原理與實(shí)現(xiàn)

 更新時(shí)間:2021年11月03日 10:02:53   作者:JaylenL  
這篇文章主要給大家介紹了關(guān)于JS中new的原理與實(shí)現(xiàn)的相關(guān)資料,本文通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下

定義

new 運(yùn)算符創(chuàng)建一個(gè)用戶定義的對(duì)象類(lèi)型的實(shí)例或具有構(gòu)造函數(shù)的內(nèi)置對(duì)象的實(shí)例。

使用new [constructor]的方式來(lái)創(chuàng)建一個(gè)對(duì)象實(shí)例,但構(gòu)造函數(shù)的差異會(huì)導(dǎo)致創(chuàng)建的實(shí)例不同。

構(gòu)造函數(shù)體不同

構(gòu)造函數(shù)也是函數(shù),其唯一的區(qū)別就是調(diào)用方式不同,任何函數(shù)只要使用 new 操作符調(diào)用就是構(gòu)造函數(shù),而不使用 new 操作符調(diào)用的函數(shù)就是普通函數(shù)。

因此構(gòu)造函數(shù)也可以帶有返回值,但是這會(huì)導(dǎo)致new的結(jié)果不同。

無(wú)返回值

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

let obj = new Person("Jalenl");
console.log(obj);

顯然,打印的是{name:'Jalenl'}

返回對(duì)象

function Person(age) {
  this.age = age;
  return { name: "Jalenl" };
}

let obj = new Person(18);
console.log(obj);

打印的是{name:'Jalenl'},也就是說(shuō)return之前的定義都被覆蓋了。這里return的是一個(gè)對(duì)象,那返回的是個(gè)基本類(lèi)型呢?

返回非對(duì)象

function Person(age) {
  this.age = age;
  return 1;
}

let obj = new Person(18);
console.log(obj);

返回{age:21},這么說(shuō)return失效了,跟沒(méi)有return一樣的結(jié)果,那如果沒(méi)有this綁定內(nèi)部屬性,再返回基本數(shù)據(jù)類(lèi)型呢?

沒(méi)有屬性綁定+返回非對(duì)象

function Person(){
    return 1
}
new Person()

返回的是一個(gè)空對(duì)象{},意料之中。

綜上,只有構(gòu)造函數(shù)return返回的是一個(gè)對(duì)象類(lèi)型時(shí),才能改變初始結(jié)果。

構(gòu)造函數(shù)類(lèi)型不同

構(gòu)造函數(shù)為普通函數(shù)

ECMA-262 3rd. Edition Specification中的說(shuō)明了對(duì)象實(shí)例的創(chuàng)建過(guò)程:

13.2.2 [[Construct]]
When the [[Construct]] property for a Function object F is called, the following steps are taken:

  1. Create a new native ECMAScript object.
  2. Set the [[Class]] property of Result(1) to "Object".
  3. Get the value of the prototype property of F.
  4. If Result(3) is an object, set the [[Prototype]] property of Result(1) to Result(3).
  5. If Result(3) is not an object, set the [[Prototype]] property of Result(1) to the original Object prototype object as described in 15.2.3.1.
  6. Invoke the [[Call]] property of F, providing Result(1) as the this value and providing the argument list passed into [[Construct]] as the argument values.
  7. If Type(Result(6)) is Object then return Result(6).
  8. Return Result(1).

總結(jié)下來(lái)就是:

  1. 在內(nèi)存中創(chuàng)建一個(gè)新對(duì)象。
  2. 這個(gè)新對(duì)象內(nèi)部的[[Prototype]]特性被賦值為構(gòu)造函數(shù)的 prototype 屬性。
  3. 構(gòu)造函數(shù)內(nèi)部的 this 被賦值為這個(gè)新對(duì)象(即 this 指向新對(duì)象)。
  4. 執(zhí)行構(gòu)造函數(shù)內(nèi)部的代碼(給新對(duì)象添加屬性)。
  5. 如果構(gòu)造函數(shù)返回對(duì)象,則返回該對(duì)象;否則,返回剛創(chuàng)建的新對(duì)象(空對(duì)象)。

第五步就已經(jīng)說(shuō)明了構(gòu)造函數(shù)不同導(dǎo)致new結(jié)果不同的原因。

以下摘自MDN的解釋?zhuān)?/p>

當(dāng)代碼 new Foo(…) 執(zhí)行時(shí),會(huì)發(fā)生以下事情:

  1. 一個(gè)繼承自 Foo.prototype 的新對(duì)象被創(chuàng)建。
  2. 使用指定的參數(shù)調(diào)用構(gòu)造函數(shù) Foo,并將 this 綁定到新創(chuàng)建的對(duì)象。new Foo 等同于 new Foo(),也就是沒(méi)有指定參數(shù)列表,F(xiàn)oo 不帶任何參數(shù)調(diào)用的情況。
  3. 由構(gòu)造函數(shù)返回的對(duì)象就是 new 表達(dá)式的結(jié)果。如果構(gòu)造函數(shù)沒(méi)有顯式返回一個(gè)對(duì)象,則使用步驟1創(chuàng)建的對(duì)象。(一般情況下,構(gòu)造函數(shù)不返回值,但是用戶可以選擇主動(dòng)返回對(duì)象,來(lái)覆蓋正常的對(duì)象創(chuàng)建步驟)

構(gòu)造函數(shù)為箭頭函數(shù)

普通函數(shù)創(chuàng)建時(shí),引擎會(huì)按照特定的規(guī)則為這個(gè)函數(shù)創(chuàng)建一個(gè)prototype屬性(指向原型對(duì)象)。默認(rèn)情況下,所有原型對(duì)象自動(dòng)獲得一個(gè)名為 constructor 的屬性,指回與之關(guān)聯(lián)的構(gòu)造函數(shù)。

function Person(){
    this.age = 18;
}
Person.prototype
/**
{
    constructor: ƒ Foo()
    __proto__: Object
}
**/

創(chuàng)建箭頭函數(shù)時(shí),引擎不會(huì)為其創(chuàng)建prototype屬性,箭頭函數(shù)沒(méi)有constructor供new調(diào)用,因此使用new調(diào)用箭頭函數(shù)會(huì)報(bào)錯(cuò)!

const Person = ()=>{}
new Person()//TypeError: Foo is not a constructor

手寫(xiě)new

綜上,熟悉了new的工作原理后,我們可以自己實(shí)現(xiàn)一個(gè)低配版的new,實(shí)現(xiàn)的關(guān)鍵是:

  1. 讓實(shí)例可以訪問(wèn)到私有屬性;
  2. 讓實(shí)例可以訪問(wèn)構(gòu)造函數(shù)原型(constructor.prototype)所在原型鏈上的屬性;
  3. 構(gòu)造函數(shù)返回的最后結(jié)果是引用數(shù)據(jù)類(lèi)型。
function _new(constructor, ...args) {
    // 構(gòu)造函數(shù)類(lèi)型合法判斷
    if(typeof constructor !== 'function') {
      throw new Error('constructor must be a function');
    }
    // 新建空對(duì)象實(shí)例
    let obj = new Object();
    // 將構(gòu)造函數(shù)的原型綁定到新創(chuàng)的對(duì)象實(shí)例上
    obj.__proto__ = Object.create(constructor.prototype);
    // 調(diào)用構(gòu)造函數(shù)并判斷返回值
    let res = constructor.apply(obj,  args);
    let isObject = typeof res === 'object' && res !== null;
    let isFunction = typeof res === 'function';
    // 如果有返回值且返回值是對(duì)象類(lèi)型,那么就將它作為返回值,否則就返回之前新建的對(duì)象
    return isObject || isFunction ? res : obj;
};

這個(gè)低配版new實(shí)現(xiàn)可以用來(lái)創(chuàng)建自定義類(lèi)的實(shí)例,但不支持內(nèi)置對(duì)象,畢竟new屬于操作符,底層實(shí)現(xiàn)更加復(fù)雜。

總結(jié)

到此這篇關(guān)于JS中new的原理與實(shí)現(xiàn)的文章就介紹到這了,更多相關(guān)JS中new原理與實(shí)現(xiàn)內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

最新評(píng)論