日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 前端技术 > javascript >内容正文

javascript

面试官问:能否模拟实现JS的new操作符(高频考点)

發布時間:2023/12/9 javascript 39 豆豆
生活随笔 收集整理的這篇文章主要介紹了 面试官问:能否模拟实现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操作符來調用后,生成了一個全新的對象。而且Student和Object都是函數,只不過Student是我們自定義的,Object是JS本身就內置的。再來看下控制臺輸出圖,感興趣的讀者可以在控制臺試試。

例子1 控制臺輸出圖

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

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

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

  • 創建了一個全新的對象。

  • 這個對象會被執行[[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操作符又做了一件事:

  • 生成的新對象會綁定到函數調用的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:

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

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

  • 創建了一個全新的對象。

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

  • 生成的新對象會綁定到函數調用的this。

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

  • 如果函數沒有返回對象類型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. 最后總結一下:

  • new做了什么:

  • 創建了一個全新的對象。

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

  • 生成的新對象會綁定到函數調用的this。

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

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

  • 怎么模擬實現

  • //?去除了注釋 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庫?

    末尾

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

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

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

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

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

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

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

    總結

    以上是生活随笔為你收集整理的面试官问:能否模拟实现JS的new操作符(高频考点)的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。