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

資訊專欄INFORMATION COLUMN

面試官問:能否模擬實現(xiàn)JS的new操作符

shenhualong / 1651人閱讀

摘要:接下來繼續(xù)看升級版例子例子軒轅軒轅軒轅是瀏覽器實現(xiàn)的查看原型方案。模擬實現(xiàn)知道了這些現(xiàn)象,我們就可以模擬實現(xiàn)操作符。

前言

用過Vuejs的同學(xué)都知道,需要用new操作符來實例化。

new Vue({
    el: "#app",
    mounted(){},
});

那么面試官可能會問是否想過new到底做了什么,怎么模擬實現(xiàn)呢。

附上之前寫文章寫過的一段話:已經(jīng)有很多模擬實現(xiàn)new操作符的文章,為什么自己還要寫一遍呢。學(xué)習(xí)就好比是座大山,人們沿著不同的路登山,分享著自己看到的風(fēng)景。你不一定能看到別人看到的風(fēng)景,體會到別人的心情。只有自己去登山,才能看到不一樣的風(fēng)景,體會才更加深刻。
new 做了什么

先看簡單例子1

// 例子1
function Student(){
}
var student = new Student();
console.log(student); // {}
// student 是一個對象。
console.log(Object.prototype.toString.call(student)); // [object Object]
// 我們知道平時聲明對象也可以用new Object(); 只是看起來更復(fù)雜
// 順便提一下 `new Object`(不推薦)和Object()也是一樣的效果
// 可以猜測內(nèi)部做了一次判斷,用new調(diào)用
/** if (!(this instanceof Object)) {
*    return new Object();
*  }
*/
var obj = new Object();
console.log(obj) // {}
console.log(Object.prototype.toString.call(student)); // [object Object]

typeof Student === "function" // true
typeof Object === "function" // true

從這里例子中,我們可以看出:一個函數(shù)用new操作符來調(diào)用后,生成了一個全新的對象。而且StudentObject都是函數(shù),只不過Student是我們自定義的,ObjectJS本身就內(nèi)置的。
再來看下控制臺輸出圖,感興趣的讀者可以在控制臺試試。

new Object() 生成的對象不同的是new Student()生成的對象中間還嵌套了一層__proto__,它的constructorStudent這個函數(shù)。

// 也就是說:
student.constructor === Student;
Student.prototype.constructor === Student;
小結(jié)1:從這個簡單例子來看,new操作符做了兩件事:

創(chuàng)建了一個全新的對象。

這個對象會被執(zhí)行[[Prototype]](也就是__proto__)鏈接。

接下來我們再來看升級版的例子2

// 例子2
function Student(name){
    console.log("賦值前-this", this); // {}
    this.name = name;
    console.log("賦值后-this", this); // {name: "軒轅Rowboat"}
}
var student = new Student("軒轅Rowboat");
console.log(student); // {name: "軒轅Rowboat"}

由此可以看出:這里Student函數(shù)中的this指向new Student()生成的對象student。

小結(jié)2:從這個例子來看,new操作符又做了一件事:

生成的新對象會綁定到函數(shù)調(diào)用的this。

接下來繼續(xù)看升級版例子3

// 例子3
function Student(name){
    this.name = name;
    // this.doSth();
}
Student.prototype.doSth = function() {
    console.log(this.name);
};
var student1 = new Student("軒轅");
var student2 = new Student("Rowboat");
console.log(student1, student1.doSth()); // {name: "軒轅"} "軒轅"
console.log(student2, student2.doSth()); // {name: "Rowboat"} "Rowboat"
student1.__proto__ === Student.prototype; // true
student2.__proto__ === Student.prototype; // true
// __proto__ 是瀏覽器實現(xiàn)的查看原型方案。
// 用ES5 則是:
Object.getPrototypeOf(student1) === Student.prototype; // true
Object.getPrototypeOf(student2) === Student.prototype; // true


關(guān)于JS的原型關(guān)系筆者之前看到這張圖,覺得很不錯,分享給大家。

小結(jié)3:這個例子3再一次驗證了小結(jié)1中的第2點。

也就是這個對象會被執(zhí)行[[Prototype]](也就是__proto__)鏈接。并且通過new Student()創(chuàng)建的每個對象將最終被[[Prototype]]鏈接到這個Student.protytype對象上。

細(xì)心的同學(xué)可能會發(fā)現(xiàn)這三個例子中的函數(shù)都沒有返回值。那么有返回值會是怎樣的情形呢。
那么接下來請看例子4

// 例子4
function Student(name){
    this.name = name;
    // Null(空) null
    // Undefined(未定義) undefined
    // Number(數(shù)字) 1
    // String(字符串)"1"
    // Boolean(布爾) true
    // Symbol(符號)(第六版新增) symbol
    
    // Object(對象) {}
        // Function(函數(shù)) function(){}
        // Array(數(shù)組) []
        // Date(日期) new Date()
        // RegExp(正則表達(dá)式)/a/
        // Error (錯誤) new Error() 
    // return /a/;
}
var student = new Student("軒轅Rowboat");
console.log(student); {name: "軒轅Rowboat"}

筆者測試這七種類型后MDN JavaScript類型,得出的結(jié)果是:前面六種基本類型都會正常返回{name: "軒轅Rowboat"},后面的Object(包含Functoin, Array, Date, RegExg, Error)都會直接返回這些值。

由此得出 小結(jié)4:

如果函數(shù)沒有返回對象類型Object(包含Functoin, Array, Date, RegExg, Error),那么new表達(dá)式中的函數(shù)調(diào)用會自動返回這個新的對象。

結(jié)合這些小結(jié),整理在一起就是:

創(chuàng)建了一個全新的對象。

這個對象會被執(zhí)行[[Prototype]](也就是__proto__)鏈接。

生成的新對象會綁定到函數(shù)調(diào)用的this

通過new創(chuàng)建的每個對象將最終被[[Prototype]]鏈接到這個函數(shù)的prototype對象上。

如果函數(shù)沒有返回對象類型Object(包含Functoin, Array, Date, RegExg, Error),那么new表達(dá)式中的函數(shù)調(diào)用會自動返回這個新的對象。

new 模擬實現(xiàn)

知道了這些現(xiàn)象,我們就可以模擬實現(xiàn)new操作符。直接貼出代碼和注釋

/**
 * 模擬實現(xiàn) new 操作符
 * @param  {Function} ctor [構(gòu)造函數(shù)]
 * @return {Object|Function|Regex|Date|Error}      [返回結(jié)果]
 */
function newOperator(ctor){
    if(typeof ctor !== "function"){
      throw "newOperator function the first param must be a function";
    }
    // ES6 new.target 是指向構(gòu)造函數(shù)
    newOperator.target = ctor;
    // 1.創(chuàng)建一個全新的對象,
    // 2.并且執(zhí)行[[Prototype]]鏈接
    // 4.通過`new`創(chuàng)建的每個對象將最終被`[[Prototype]]`鏈接到這個函數(shù)的`prototype`對象上。
    var newObj = Object.create(ctor.prototype);
    // ES5 arguments轉(zhuǎn)成數(shù)組 當(dāng)然也可以用ES6 [...arguments], Aarry.from(arguments);
    // 除去ctor構(gòu)造函數(shù)的其余參數(shù)
    var argsArr = [].slice.call(arguments, 1);
    // 3.生成的新對象會綁定到函數(shù)調(diào)用的`this`。
    // 獲取到ctor函數(shù)返回結(jié)果
    var ctorReturnResult = ctor.apply(newObj, argsArr);
    // 小結(jié)4 中這些類型中合并起來只有Object和Function兩種類型 typeof null 也是"object"所以要不等于null,排除null
    var isObject = typeof ctorReturnResult === "object" && ctorReturnResult !== null;
    var isFunction = typeof ctorReturnResult === "function";
    if(isObject || isFunction){
        return ctorReturnResult;
    }
    // 5.如果函數(shù)沒有返回對象類型`Object`(包含`Functoin`, `Array`, `Date`, `RegExg`, `Error`),那么`new`表達(dá)式中的函數(shù)調(diào)用會自動返回這個新的對象。
    return newObj;
}

最后用模擬實現(xiàn)的newOperator函數(shù)驗證下之前的例子3

// 例子3 多加一個參數(shù)
function Student(name, age){
    this.name = name;
    this.age = age;
    // this.doSth();
    // return Error();
}
Student.prototype.doSth = function() {
    console.log(this.name);
};
var student1 = newOperator(Student, "軒轅", 18);
var student2 = newOperator(Student, "Rowboat", 18);
// var student1 = new Student("軒轅");
// var student2 = new Student("Rowboat");
console.log(student1, student1.doSth()); // {name: "軒轅"} "軒轅"
console.log(student2, student2.doSth()); // {name: "Rowboat"} "Rowboat"

student1.__proto__ === Student.prototype; // true
student2.__proto__ === Student.prototype; // true
// __proto__ 是瀏覽器實現(xiàn)的查看原型方案。
// 用ES5 則是:
Object.getPrototypeOf(student1) === Student.prototype; // true
Object.getPrototypeOf(student2) === Student.prototype; // true

可以看出,很符合new操作符。讀者發(fā)現(xiàn)有不妥或可改善之處,歡迎指出。
回顧這個模擬new函數(shù)newOperator實現(xiàn),最大的功臣當(dāng)屬于Object.create()這個ES5提供的API。

Object.create() 用法舉例

筆者之前整理的一篇文章中也有講過,可以翻看JavaScript 對象所有API解析

MDN Object.create()

Object.create(proto, [propertiesObject])
方法創(chuàng)建一個新對象,使用現(xiàn)有的對象來提供新創(chuàng)建的對象的__proto__。
它接收兩個參數(shù),不過第二個可選參數(shù)是屬性描述符(不常用,默認(rèn)是undefined)。

var anotherObject = {
    name: "軒轅Rowboat"
};
var myObject = Object.create(anotherObject, {
    age: {
        value:18,
    },
});
// 獲得它的原型
Object.getPrototypeOf(anotherObject) === Object.prototype; // true 說明anotherObject的原型是Object.prototype
Object.getPrototypeOf(myObject); // {name: "軒轅Rowboat"} // 說明myObject的原型是{name: "軒轅Rowboat"}
myObject.hasOwnProperty("name"); // false; 說明name是原型上的。
myObject.hasOwnProperty("age"); // true 說明age是自身的
myObject.name; // "軒轅Rowboat"
myObject.age; // 18;

對于不支持ES5的瀏覽器,MDN上提供了ployfill方案。

if (typeof Object.create !== "function") {
    Object.create = function (proto, propertiesObject) {
        if (typeof proto !== "object" && typeof proto !== "function") {
            throw new TypeError("Object prototype may only be an Object: " + proto);
        } else if (proto === null) {
            throw new Error("This browser"s implementation of Object.create is a shim and doesn"t support "null" as the first argument.");
        }

        if (typeof propertiesObject != "undefined") throw new Error("This browser"s implementation of Object.create is a shim and doesn"t support a second argument.");

        function F() {}
        F.prototype = proto;

        return new F();
    };
}

到此,文章就基本寫完了。感謝讀者看到這里。

最后總結(jié)一下:

1.new做了什么:

創(chuàng)建了一個全新的對象。

這個對象會被執(zhí)行[[Prototype]](也就是__proto__)鏈接。

生成的新對象會綁定到函數(shù)調(diào)用的this。

通過new創(chuàng)建的每個對象將最終被[[Prototype]]鏈接到這個函數(shù)的prototype對象上。

如果函數(shù)沒有返回對象類型Object(包含Functoin, Array, Date, RegExg, Error),那么new表達(dá)式中的函數(shù)調(diào)用會自動返回這個新的對象。

2.怎么模擬實現(xiàn):

// 去除了注釋
function newOperator(ctor){
    if(typeof ctor !== "function"){
      throw "newOperator function the first param must be a function";
    }
    newOperator.target = ctor;
    var newObj = Object.create(ctor.prototype);
    var argsArr = [].slice.call(arguments, 1);
    var ctorReturnResult = ctor.apply(newObj, argsArr);
    var isObject = typeof ctorReturnResult === "object" && ctorReturnResult !== null;
    var isFunction = typeof ctorReturnResult === "function";
    if(isObject || isFunction){
        return ctorReturnResult;
    }
    return newObj;
}

讀者發(fā)現(xiàn)有不妥或可改善之處,歡迎指出。另外覺得寫得不錯,可以點個贊,也是對筆者的一種支持。

關(guān)于

作者:常以軒轅Rowboat若川為名混跡于江湖。前端路上 | PPT愛好者 | 所知甚少,唯善學(xué)。
個人博客
segmentfault前端視野專欄,開通了前端視野專欄,歡迎關(guān)注
掘金專欄,歡迎關(guān)注
知乎前端視野專欄,開通了前端視野專欄,歡迎關(guān)注
github,歡迎follow~

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

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

相關(guān)文章

  • 面試官問能否模擬實現(xiàn)JSbind方法

    摘要:點擊那么面試官可能會問是否想過到底做了什么,怎么模擬實現(xiàn)呢。另外前不久寫過一篇文章面試官問能否模擬實現(xiàn)的操作符。所以相當(dāng)于調(diào)用時,的返回值函數(shù)內(nèi)部要模擬實現(xiàn)實現(xiàn)的操作。文章中的例子和測試代碼放在中模擬實現(xiàn)。 前言 用過React的同學(xué)都知道,經(jīng)常會使用bind來綁定this。 import React, { Component } from react; class TodoItem ...

    Julylovin 評論0 收藏0
  • 面試官問能否模擬實現(xiàn)JScall和apply方法

    摘要:之前寫過兩篇面試官問能否模擬實現(xiàn)的操作符和面試官問能否模擬實現(xiàn)的方法其中模擬方法時是使用的和修改指向。但面試官可能問能否不用和來實現(xiàn)呢。使用模擬實現(xiàn)的瀏覽器環(huán)境非嚴(yán)格模式方法的屬性是。 之前寫過兩篇《面試官問:能否模擬實現(xiàn)JS的new操作符》和《面試官問:能否模擬實現(xiàn)JS的bind方法》 其中模擬bind方法時是使用的call和apply修改this指向。但面試官可能問:能否不用cal...

    wuyangnju 評論0 收藏0
  • 面試官問JSthis指向

    摘要:之前寫過一篇文章面試官問能否模擬實現(xiàn)的和方法就是利用對象上的函數(shù)指向這個對象,來模擬實現(xiàn)和的。雖然實際使用時不會顯示返回,但面試官會問到。非嚴(yán)格模式下,和,指向全局對象 前言 面試官出很多考題,基本都會變著方式來考察this指向,看候選人對JS基礎(chǔ)知識是否扎實。讀者可以先拉到底部看總結(jié),再谷歌(或各技術(shù)平臺)搜索幾篇類似文章,看筆者寫的文章和別人有什么不同(歡迎在評論區(qū)評論不同之處),...

    warnerwu 評論0 收藏0
  • 學(xué)習(xí) underscore 源碼整體架構(gòu),打造屬于自己函數(shù)式編程類庫

    摘要:譯立即執(zhí)行函數(shù)表達(dá)式處理支持瀏覽器環(huán)境微信小程序。學(xué)習(xí)整體架構(gòu),利于打造屬于自己的函數(shù)式編程類庫。下一篇文章可能是學(xué)習(xí)的源碼整體架構(gòu)。也可以加微信,注明來源,拉您進前端視野交流群。 前言 上一篇文章寫了jQuery整體架構(gòu),學(xué)習(xí) jQuery 源碼整體架構(gòu),打造屬于自己的 js 類庫 雖然看過挺多underscore.js分析類的文章,但總感覺少點什么。這也許就是紙上得來終覺淺,絕知此...

    junnplus 評論0 收藏0
  • 面試官問JS繼承

    摘要:用過的讀者知道,經(jīng)常用繼承。部分源碼使用點擊這里查看源碼面試官可以順著這個問繼承的相關(guān)問題,比如的繼承用如何實現(xiàn)。主要就是三點子類構(gòu)造函數(shù)的指向父類構(gòu)造器,繼承父類的靜態(tài)方法子類構(gòu)造函數(shù)的的指向父類構(gòu)造器的,繼承父類的方法。 用過React的讀者知道,經(jīng)常用extends繼承React.Component。 // 部分源碼 function Component(props, conte...

    stonezhu 評論0 收藏0

發(fā)表評論

0條評論

閱讀需要支付1元查看
<