new運算子、bind、Object.create實現原理探討
阿新 • • 發佈:2018-12-11
如何手寫new運算子、bind方法、Object.create
一、new 運算子
- 首先我們自己寫new運算子,無法寫成 NEW F()這種方法,因為js不識別呀,所以只能將第一個引數看做建構函式,剩餘是其它傳參,例如
let m = NEW(M,'lihaixing',30);
// 等同於js中的
let m = new M('lihaixing',30);
- 然後就開始吧!
function NEW(){ // 獲取引數 let func = arguments[0]; // 建構函式 let paras = [].slice.call(arguments,1); // 傳入的引數 // 繼承func.prototype的屬性 let o = Object.create(func.prototype); // 繼承建構函式中的屬性 func.call(o,..paras); return o; }
- 測試一下,並和js原生的new對比一下
function M (name, age) {
this.name = name;
this.age = age;
}
M.prototype.sayYear = () => {
console.log('2018');
}
let m = NEW(M, 'haixing', 30);
let mm = new M('haixing', 30);
- 在控制檯中依次輸入m, mm, m.sayYear, mm.sayYear呼叫,結果如下
- 一某一樣有沒有,那就進入下一個環節吧!
二、bind方法手寫
- bind方法其實和call非常一樣,唯一的區別就是,call會將函式綁到物件中,並且呼叫;而bind只是將函式綁到物件中,並不呼叫,也就是:
f.call(obj)
// 等同於
f.bind(obj)();
- 那麼該怎麼寫呢?我們知道bind方法是在綁在函式上的,而在js中,每個函式都是一個new Function(), 也就是和例項物件差不多了,所以我們要想使每個函式都能呼叫bind方法,就應該把它放在Function.prototype中,這樣就是把bind方法寫到了每個函式的原型中。那就開始寫吧!
Function.prototype.BIND = function () { // this指向的就是我們的函式哦 let self = this; // 獲取引數,由於return中的函式也有arguments, 這裡需重新賦值一下 let paras = arguments; return function () { self.call(...paras); // 不要忘記解構 } }
- 然後就測試一下吧, 這裡M還是上一節中的M建構函式
let c = {};
let cc = {};
M.BIND(c, 'haixing', 31)();
M.bind(cc, 'haixing', 31)();
- 結果如下
- 好像也沒啥問題,但是c和cc是一個字面量物件, 那如果c和cc是建構函式生成的例項物件,那會如何呢?繼續上程式碼:
function A (name, age) {
this.name = name;
this.age = age;
}
let d = new A('haixi', 22);
let dd = new A('haixi', 22);
M.BIND(d, 'haixing', 31)();
M.bind(dd, 'haixing', 31)();
- 還是沒問題哈,constructor也是對的, 那我就放心,進入下一環節吧
Object.create怎麼寫?
// 這個要簡單一些,就直接寫了
Object.CREATE= function (obj, properties) {
function F () {}
F.prototype = obj;
let o = new F();
// 注意Object.create可以傳入第二個引數,是一個物件,但格式必須是Object.defineProperties()方法一樣
if (typeof properties === 'object') {
Object.defineProperties(o, properties);
}
return o;
}
let e = Object.create(d, {year: {value: 2019}});
let ee = Object.CREATE(d, {year: {value: 2019}});
- 上圖看執行結果
- 唉? 奇怪哈,為什麼一個顯示A一個顯示F呢,但兩個都是A的例項啊?哪位知道,歡迎留言啊