昨晚看了一篇模擬實現 js new 的文章,今天覆盤一下javascript
function a(){ this.b = 'bb'; } a.prototype.c = 'cc'; var aa = new a();
new 其實作了三件事情,首先它確定是建立了一個對象java
2.將 a 的prototype屬性對象經過引用傳遞賦值給 aa.__proto__ ,至關於:aa.__proto__ = a.prototypees6
進一步證明一下:app
第三件事:用對象 aa 調用函數 a,從而使 a 內部的 this 指向 aa,即:函數
a.apply(aa)this
這樣 aa 就有了屬性 bprototype
這樣咱們就用上面的三步「生產」出了一個和 new 效果同樣的對象 bb;3d
以上就是 new 的基本原理了,但還有一些小細節 :code
1. 函數a 若是有參數對象
2. 函數 a 若是有返回值
1 : 比較簡單,修改第三步爲 a.apply(bb , [arg1, arg2, ...]) 就能夠了
2 : 分兩種狀況:
a.返回值類型爲基本類型: string number null undefined boolean symbol
b.返回值爲對象 即,typeof 等於 'object' 或 'function' ,這裏麪包含了 Array、Date、RegExp、Error 等。。。
狀況 a 是咱們上面講的普通狀況,
可是當咱們 new 一個返回值爲對象的函數時,js 不會執行上面的那些操做,而是執行函數並返回函數的發回值 即:
new a(); 和 a(); 的效果是同樣的:
因此若是要本身模擬一個 new 函數能夠這樣寫:
function newOperator(ctor){ if(typeof ctor !== 'function'){ throw 'newOperator function the first param must be a function'; } //es6 new.target 指向構造函數(這個沒有細究) newOperator.target = ctor; //這裏能夠經過 Object.create 將第一二步合成一步 var newObj = Object.create(ctor.prototype); var argsArr = [].slice.call(arguments); argsArr.shift(); var ctorReturnResult = ctor.apply(newObj, argsArr); if(typeof ctorReturnResult === 'object' && ctorReturnResult !== null){ return ctorReturnResult; } if(typeof ctorReturnResult === 'function'){ return ctorReturnResult; } return newObj; }
固然 js 也賦予了 prototype __proto__ 這些特殊屬性一些特殊做用,
好比 能夠用 aa.c 來訪問 aa.__proto__.c 前提是 aa 沒有 c 這個自有屬性,而且不能經過 aa.c 來修改 aa.__proto__.c 即:
aa.c = 'ss' 是不能改變 aa.__proto__.c 的值
__________________________________________________________
因此,清楚了 __proto__ 是一個對象引用,而且瞭解了它的特殊做用 js 的原型鏈 面向對象 也就明白八成了吧~~!