javascript
面试官问:能否模拟实现JS的new操作符(高频考点)
可以點擊上方的話題JS基礎(chǔ)系列,查看往期文章
這篇文章寫于2018年11月05日,new模擬實現(xiàn),Object.create是面試高頻考點,之前發(fā)布在掘金有近2萬人閱讀,現(xiàn)在發(fā)布到公眾號聲明原創(chuàng)。
1. 前言
這是面試官問系列的第一篇,旨在幫助讀者提升JS基礎(chǔ)知識,包含new、call、apply、this、繼承相關(guān)知識。
面試官問系列文章如下:感興趣的讀者可以點擊閱讀。
1.面試官問:能否模擬實現(xiàn)JS的new操作符
2.面試官問:能否模擬實現(xiàn)JS的bind方法
3.面試官問:能否模擬實現(xiàn)JS的call和apply方法
4.面試官問:JS的this指向
5.面試官問:JS的繼承
用過Vuejs的同學都知道,需要用new操作符來實例化。
new?Vue({el:?'#app',mounted(){}, });那么面試官可能會問是否想過new到底做了什么,怎么模擬實現(xiàn)呢。
附上之前寫文章寫過的一段話:已經(jīng)有很多模擬實現(xiàn)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();?只是看起來更復(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)用后,生成了一個全新的對象。而且Student和Object都是函數(shù),只不過Student是我們自定義的,Object是JS本身就內(nèi)置的。再來看下控制臺輸出圖,感興趣的讀者可以在控制臺試試。
例子1 控制臺輸出圖與new Object() 生成的對象不同的是new Student()生成的對象中間還嵌套了一層__proto__,它的constructor是Student這個函數(shù)。
//?也就是說: student.constructor?===?Student; Student.prototype.constructor?===?Student;2.1 小結(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:?'若川'} } var?student?=?new?Student('若川'); console.log(student);?//?{name:?'若川'}由此可以看出:這里Student函數(shù)中的this指向new Student()生成的對象student。
2.2 小結(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('川'); console.log(student1,?student1.doSth());?//?{name:?'若'}?'若' console.log(student2,?student2.doSth());?//?{name:?'川'}?'川' 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例子3 控制臺輸出圖
關(guān)于JS的原型關(guān)系我之前看到這張圖,覺得很不錯,分享給大家。
2.3 小結(jié)3:這個例子3再一次驗證了小結(jié)1中的第2點。也就是這個對象會被執(zhí)行[[Prototype]](也就是__proto__)鏈接。并且通過new Student()創(chuàng)建的每個對象將最終被[[Prototype]]鏈接到這個Student.protytype對象上。
細心的同學可能會發(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(正則表達式)/a///?Error?(錯誤)?new?Error()//?return?/a/; } var?student?=?new?Student('若川'); console.log(student);?{name:?'若川'}我測試這七種類型后MDN JavaScript類型,得出的結(jié)果是:前面六種基本類型都會正常返回{name: '若川'},后面的Object(包含F(xiàn)unctoin, Array, Date, RegExg, Error)都會直接返回這些值。
2.4 由此得出 小結(jié)4:
如果函數(shù)沒有返回對象類型Object(包含F(xiàn)unctoin, Array, Date, RegExg, Error),那么new表達式中的函數(shù)調(diào)用會自動返回這個新的對象。
結(jié)合這些小結(jié),整理在一起就是:
創(chuàng)建了一個全新的對象。
這個對象會被執(zhí)行[[Prototype]](也就是__proto__)鏈接。
生成的新對象會綁定到函數(shù)調(diào)用的this。
通過new創(chuàng)建的每個對象將最終被[[Prototype]]鏈接到這個函數(shù)的prototype對象上。
如果函數(shù)沒有返回對象類型Object(包含F(xiàn)unctoin, Array, Date, RegExg, Error),那么new表達式中的函數(shù)調(diào)用會自動返回這個新的對象。
3. 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ù)組?當然也可以用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,排除nullvar?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`表達式中的函數(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,?'川',?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__?是瀏覽器實現(xiàn)的查看原型方案。 //?用ES5 則是: Object.getPrototypeOf(student1)?===?Student.prototype;?//?true Object.getPrototypeOf(student2)?===?Student.prototype;?//?true可以看出,很符合new操作符。讀者發(fā)現(xiàn)有不妥或可改善之處,歡迎指出。回顧這個模擬new函數(shù)newOperator實現(xiàn),最大的功臣當屬于Object.create()這個ES5提供的API。
4. Object.create() 用法舉例
我之前整理的一篇文章中也有講過,可以翻看JavaScript 對象所有API解析
MDN Object.create()
Object.create(proto, [propertiesObject])方法創(chuàng)建一個新對象,使用現(xiàn)有的對象來提供新創(chuàng)建的對象的__proto__。它接收兩個參數(shù),不過第二個可選參數(shù)是屬性描述符(不常用,默認是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. 最后總結(jié)一下:
new做了什么:
創(chuàng)建了一個全新的對象。
這個對象會被執(zhí)行[[Prototype]](也就是__proto__)鏈接。
生成的新對象會綁定到函數(shù)調(diào)用的this。
通過new創(chuàng)建的每個對象將最終被[[Prototype]]鏈接到這個函數(shù)的prototype對象上。
如果函數(shù)沒有返回對象類型Object(包含F(xiàn)unctoin, Array, Date, RegExg, Error),那么new表達式中的函數(shù)調(diào)用會自動返回這個新的對象。
怎么模擬實現(xiàn)
讀者發(fā)現(xiàn)有不妥或可改善之處,歡迎指出。另外覺得寫得不錯,可以點個贊,也是對我的一種支持。
推薦閱讀
我在阿里招前端,我該怎么幫你?(現(xiàn)在還可以加模擬面試群)
如何拿下阿里巴巴 P6 的前端 Offer
如何準備阿里P6/P7前端面試--項目經(jīng)歷準備篇
大廠面試官常問的亮點,該如何做出?
如何從初級到專家(P4-P7)打破成長瓶頸和有效突破
若川知乎問答:2年前端經(jīng)驗,做的項目沒什么技術(shù)含量,怎么辦?
若川知乎高贊:有哪些必看的 JS庫?
末尾
你好,我是若川,江湖人稱菜如若川,歷時一年只寫了一個學習源碼整體架構(gòu)系列~(點擊藍字了解我)
關(guān)注若川視野,回復(fù)"pdf" 領(lǐng)取優(yōu)質(zhì)前端書籍pdf,回復(fù)"1",可加群長期交流學習
我的博客地址:https://lxchuan12.gitee.io?歡迎收藏
覺得文章不錯,可以點個在看呀^_^另外歡迎留言交流~
精選前端好文,伴你不斷成長
我是若川歡迎關(guān)注!可點擊
小提醒:若川視野公眾號面試、源碼等文章合集在菜單欄中間【源碼精選】按鈕,歡迎點擊閱讀,也可以星標我的公眾號,便于查找
總結(jié)
以上是生活随笔為你收集整理的面试官问:能否模拟实现JS的new操作符(高频考点)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: DEA博弈交叉效率matlab,基于DE
- 下一篇: HTML5期末大作业:家乡介绍网站设计—