面試官問:能否模擬實現JS的new操作符(高頻考點)

可以點擊上方的話題JS基礎系列,查看往期文章
這篇文章寫于2018年11月05日new模擬實現Object.create是面試高頻考點,之前發布在掘金有近2萬人閱讀,現在發布到公眾號聲明原創。

1. 前言

這是面試官問系列的第一篇,旨在幫助讀者提升JS基礎知識,包含new、call、apply、this、繼承相關知識。
面試官問系列文章如下:感興趣的讀者可以點擊閱讀。
1.面試官問:能否模擬實現JS的new操作符
2.面試官問:能否模擬實現JS的bind方法
3.面試官問:能否模擬實現JS的call和apply方法
4.面試官問:JS的this指向
5.面試官問:JS的繼承

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

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

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

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

2. new 做了什么

先看簡單例子1

//?例子1
function?Student(){
}
var?student?=?new?Student();
console.log(student);?//?{}
// student 是一個對象。
console.log(Object.prototype.toString.call(student));?//?[object?Object]
//?我們知道平時聲明對象也可以用new?Object();?只是看起來更復雜
//?順便提一下?`new?Object`(不推薦)和Object()也是一樣的效果
//?可以猜測內部做了一次判斷,用new調用
/**?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

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

例子1 控制臺輸出圖

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

//?也就是說:
student.constructor?===?Student;
Student.prototype.constructor?===?Student;

2.1 小結1:從這個簡單例子來看,new操作符做了兩件事:

  1. 創建了一個全新的對象。

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

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

//?例子2
function?Student(name){console.log('賦值前-this',?this);?//?{}this.name?=?name;console.log('賦值后-this',?this);?//?{name:?'若川'}
}
var?student?=?new?Student('若川');
console.log(student);?//?{name:?'若川'}

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

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

  1. 生成的新對象會綁定到函數調用的this

接下來繼續看升級版例子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('川');
console.log(student1,?student1.doSth());?//?{name:?'若'}?'若'
console.log(student2,?student2.doSth());?//?{name:?'川'}?'川'
student1.__proto__?===?Student.prototype;?//?true
student2.__proto__?===?Student.prototype;?//?true
//?__proto__?是瀏覽器實現的查看原型方案。
//?用ES5 則是:
Object.getPrototypeOf(student1)?===?Student.prototype;?//?true
Object.getPrototypeOf(student2)?===?Student.prototype;?//?true

例子3 控制臺輸出圖

關于JS的原型關系我之前看到這張圖,覺得很不錯,分享給大家。

2.3 小結3:這個例子3再一次驗證了小結1中的第2點。也就是這個對象會被執行[[Prototype]](也就是__proto__)鏈接。并且通過new Student()創建的每個對象將最終被[[Prototype]]鏈接到這個Student.protytype對象上。

細心的同學可能會發現這三個例子中的函數都沒有返回值。那么有返回值會是怎樣的情形呢。那么接下來請看例子4

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

我測試這七種類型后MDN JavaScript類型,得出的結果是:前面六種基本類型都會正常返回{name: '若川'},后面的Object(包含Functoin, Array, Date, RegExg, Error)都會直接返回這些值。

2.4 由此得出 小結4:

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

結合這些小結,整理在一起就是:

  1. 創建了一個全新的對象。

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

  3. 生成的新對象會綁定到函數調用的this

  4. 通過new創建的每個對象將最終被[[Prototype]]鏈接到這個函數的prototype對象上。

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

3. new 模擬實現

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

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

最后用模擬實現的newOperator函數驗證下之前的例子3

//?例子3?多加一個參數
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,?'川',?18);
//?var?student1?=?new?Student('若');
//?var?student2?=?new?Student('川');
console.log(student1,?student1.doSth());?//?{name:?'若'}?'若'
console.log(student2,?student2.doSth());?//?{name:?'川'}?'川'student1.__proto__?===?Student.prototype;?//?true
student2.__proto__?===?Student.prototype;?//?true
//?__proto__?是瀏覽器實現的查看原型方案。
//?用ES5 則是:
Object.getPrototypeOf(student1)?===?Student.prototype;?//?true
Object.getPrototypeOf(student2)?===?Student.prototype;?//?true

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

4. Object.create() 用法舉例

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

MDN Object.create()

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

var?anotherObject?=?{name:?'若川'
};
var?myObject?=?Object.create(anotherObject,?{age:?{value:18,},
});
//?獲得它的原型
Object.getPrototypeOf(anotherObject)?===?Object.prototype;?//?true?說明anotherObject的原型是Object.prototype
Object.getPrototypeOf(myObject);?//?{name:?"若川"}?//?說明myObject的原型是{name:?"若川"}
myObject.hasOwnProperty('name');?// false;?說明name是原型上的。
myObject.hasOwnProperty('age');?//?true?說明age是自身的
myObject.name;?//?'若川'
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();};
}

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

5. 最后總結一下:

  1. new做了什么:

  1. 創建了一個全新的對象。

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

  3. 生成的新對象會綁定到函數調用的this

  4. 通過new創建的每個對象將最終被[[Prototype]]鏈接到這個函數的prototype對象上。

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

  1. 怎么模擬實現

//?去除了注釋
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;
}

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

推薦閱讀

我在阿里招前端,我該怎么幫你?(現在還可以加模擬面試群)
如何拿下阿里巴巴 P6 的前端 Offer
如何準備阿里P6/P7前端面試--項目經歷準備篇
大廠面試官常問的亮點,該如何做出?
如何從初級到專家(P4-P7)打破成長瓶頸和有效突破
若川知乎問答:2年前端經驗,做的項目沒什么技術含量,怎么辦?
若川知乎高贊:有哪些必看的 JS庫?

末尾

你好,我是若川,江湖人稱菜如若川,歷時一年只寫了一個學習源碼整體架構系列~(點擊藍字了解我)

  1. 關注若川視野,回復"pdf" 領取優質前端書籍pdf,回復"1",可加群長期交流學習

  2. 我的博客地址:https://lxchuan12.gitee.io?歡迎收藏

  3. 覺得文章不錯,可以點個在看呀^_^另外歡迎留言交流~

精選前端好文,伴你不斷成長

我是若川歡迎關注!可點擊

小提醒:若川視野公眾號面試、源碼等文章合集在菜單欄中間【源碼精選】按鈕,歡迎點擊閱讀,也可以星標我的公眾號,便于查找

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/276328.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/276328.shtml
英文地址,請注明出處:http://en.pswp.cn/news/276328.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

Linux環境下設置IPDNSGateway

轉載鏈接:http://www.myhack58.com/Article/sort099/sort0102/2011/29291.htm 在Linux中不管你是做服務器還是只是平常使用,上網肯定都是最重要和不可缺少的一個因素之一,所以就涉及到它的ip gateway dns等network配置和使用。但是設置Linux…

跟我一起學WCF(2)——利用.NET Remoting技術開發分布式應用

一、引言 上一篇博文分享了消息隊列(MSMQ)技術來實現分布式應用,在這篇博文繼續分享下.NET平臺下另一種分布式技術——.NET Remoting。 二、.NET Remoting 介紹 2.1 .NET Remoting簡介 .NET REmoting與MSMQ不同,它不支持離線可得&…

二叉樹的建立與遍歷_51、二叉樹遍歷-重建二叉樹JZ4

題目描述輸入某二叉樹的前序遍歷和中序遍歷的結果,請重建出該二叉樹。假設輸入的前序遍歷和中序遍歷的結果中都不含重復的數字。例如輸入前序遍歷序列{1,2,4,7,3,5,6,8}和中序遍歷序列{4,7,2,1,5,3,8,6},則重建二叉樹并返回。思路回顧三種經典的遍歷&…

越來越覺得現在的工作很枯燥

很不想這么說,但又不想欺騙自己,真的是很枯燥,不過這種感覺早在一年在在上一間公司時就很強烈的有過這種感覺了,只不過現在是又一次有感觸罷了。話說說我這種性質的工作枯燥很多人都講過,如果哪個人說不枯燥估計腦袋進…

推薦關注這7個高質量的前端公眾號

拓寬眼界,增加深度,在閱讀的世界里,我們往往能找到不一樣的態度,提升朋友圈質量,從關注這幾個公眾號開始。輕掃一下二維碼就行了,你可以試試,肯定會有意外收獲。大遷世界 簡介:前端小…

MySQL 實用語句集合

MySQL 實用語句集合 參考鏈接[用戶]:http://blog.csdn.net/dmtnewtons_blog/article/details/9136339 參考鏈接[屬性]:http://stackoverflow.com/questions/15821532/get-current-auto-increment-value-for-any-table 參考鏈接[索引]:htt…

python對象序列化或持久化的方法

http://blog.csdn.net/chen_lovelotus/article/details/7233293 一、Python對象持久化方法 目前為止,據我所知,在python中對象持久化有以下幾種方法: 1. 使用(dbhash/bsddb, dbm, gdbm, dumbdbm 等)以及它們的"管理器"(…

Windows Live Writer 在win2003 的安裝方法

下載Windows Live Writer整體安裝包,最好是離線安裝包 2.在xp系統上安裝 3.查找C:\Program Files\Common Files\Windows Live\.cache目錄 .cache目錄是隱藏的,目錄下面就是各個安裝文件的msi安裝包 4.拷貝相應的msi文件,到Windows 2003安裝就…

decode 大于比較 小于_6 燃氣輸配系統6.3 壓力不大于1.6Mpa的室外燃氣管道城鎮燃氣設計規范 GB500282006(2020修訂版)...

6.3 壓力不大于1.6Mpa的室外燃氣管道6.3.1中壓和低壓燃氣管道宜采用聚乙烯管、機械接口球墨鑄鐵管、鋼管或鋼骨架聚乙烯塑料復合管,并應符合下列要求: 1 聚乙烯燃氣管應符合現行的國家標準《燃氣用埋地聚乙烯管材》GB15558.1 和《燃氣用埋地聚乙烯管件…

若川的2017年度總結,一如既往

可以點擊上方的標簽若川的故事、年度總結,查看往期文章有讀者反饋說看我年度總結系列比我源碼系列更有啟發。所以打算把2016-2018的年度總結發布到公眾號聲明原創,希望對大家有所啟發。(雖然我的每一年都過得非常普通...)若川的20…

MIME協議及源郵件格式分析

轉載鏈接:http://wenku.baidu.com/view/7246de671ed9ad51f01df277.html 電子郵件也許是一個Internet上的流行最廣泛的應用。也是我們現在的大多數網絡辦公流程的基礎。各種郵件服務器很多,但都大都遵循以1982年出版的RFC822--《ARPA網絡文本信息格式標準(STANDARD F…

溝通:用故事產生共鳴

《溝通:用故事產生共鳴》(全彩) 基本信息作者: Nancy Duarte(南希.杜瓦特)譯者: 馮海洋出版社:電子工業出版社ISBN:9787121195914上架時間:2013-4-1出版日期:2013 年3月開本:12開頁碼&#xff1…

合工大五套卷_2020合工大超越數一五套卷第一套感想

合工大的卷子確實不錯,題目給我的感覺是題干包裝的看起來就很難,但是寫起來還是一樣的套路。計算上要難一些,需要細心點選擇題:1.可去間斷點的定義和泰勒公式2.這個題我用排除法寫的,可微的話連續和偏導存在都成立了,然…

DotNet關鍵知識點——WPF篇(一)(范德成編輯批注版)

1. Journal 的使用 Journal 用于在 XAML 瀏覽器應用程序(XBAP)中維護歷史訪問頁。刪除前一訪問頁只需調當前 NavigationService 對象的 RemoveBackEntry() 即可;而增加一個訪問頁則復雜得多: 1) 實現一個 CustomContentState 的派…

若川的2018年度總結,平淡無奇

可以點擊上方的標簽若川的故事、年度總結,查看往期文章偷偷告訴你,公眾號內回復【報告】,可以獲取你自己的github 2020 年度報告昨晚在我的6個微信群里都發了紅包,以這樣的方式跨過了2020年。運營公眾號真的挺難的,比如…

Simple TCP Server Client Socket C

轉載鏈接&#xff1a;http://blog.163.com/caipeipei_love126/blog/static/2596603220101118433940/ tcpserver.c #include<stdlib.h> #include<stdio.h> #include<errno.h> #include<string.h> #include<netdb.h> #include<sys/types.h>…

基于dnn的車牌識別_自然場景中文文字識別,身份證火車票都能識別

圖像處理中OCR(Optical Character Recognition光學字符識別)場景非常多&#xff0c;也給大家的工作生活帶來了很多便利&#xff0c;比如車牌識別就能管理停車場車輛的出入&#xff0c;快遞時只需給一個帶有快遞信息的圖就能自動解析上傳發件信息和收件信息&#xff0c;再比如我…

年末的大廠前端面試總結(20屆雙非二本)-終入字節

關注若川視野, 回復"pdf" 領取資料&#xff0c;回復"1"&#xff0c;可加群長期交流學習自我介紹雙非二本,軟件工程,自學前端,今年畢業。喜歡編程,古風,日語和英語。常以冷月心之名混跡前端江湖,也曾在混跡網文圈時用冷月心做筆名簽約掌閱,作品《清起風云》…

面試題(轉的)

第一組   1.燒一根不均勻的繩&#xff0c;從頭燒到尾總共需要1個小時。現在有若干條材質相同的繩子&#xff0c;問如何用燒繩的方法來計時一個小時十五分鐘呢?  2.你有一桶果凍&#xff0c;其中有黃色、綠色、紅色三種&#xff0c;閉上眼睛抓取同種顏色的兩個。抓取多少個…