接著上一篇,我們繼續來研究如何手寫。
一、手寫new
1.new運算子都做了什麼
- 新建一個物件。
- 執行prototype連線。
- 將建構函式的作用域賦給新物件。
- 繫結this指向,執行建構函式中的程式碼。
- 返回這個物件。
2.簡單實現
function myNew(context) {
// 新建一個物件
var res = new Object();
// 獲取傳遞的引數,第一個引數代表傳入的建構函式,也就是這個即將建立的這個例項的建構函式,擷取掉
const args = [...arguments].slice(1);
// 將建立的res的this繫結到傳進來的這個建構函式context
context.apply(res, args);
return res;
}
function Hdove(name) {
this.name = name;
}
var example = myNew(Hdove, 'LJ');
console.log(example); // {name: "LJ"}
複製程式碼
3.繼續改造
來,我們先看一下真實的new操作符
function Hdove(name) {
this.name = name;
}
Hdove.prototype.age = 25;
Hdove.prototype.sayName = function() {
console.log(this.name);
};
var obj = new Hdove('LJ');
console.log(obj.name); // LJ
console.log(obj.age); // 25
obj.sayName(); // LJ
複製程式碼
繼續修改我們的程式碼
function myNew(context) {
var res = new Object();
// 判斷建構函式上有沒有原型,有的話進行新增
if(context.prototype) {
res.__proto__ = context.prototype
}
const args = [...arguments].slice(1);
context.apply(res, args);
return res;
}
function Hdove(name) {
this.name = name;
}
Hdove.prototype.age = 25;
Hdove.prototype.sayName = function() {
console.log(this.name);
};
var example = myNew(Hdove, 'LJ');
console.log(example);
通過下圖我們可以看出原型已經成功繫結了,完美
複製程式碼
距離成功還有一步,我們加足馬力
4.改造升級
我們繼續看一下原生的new 操作符
1.返回一個物件
function Hdove(name) {
this.name = name;
return {
name: 'return出來的'
}
}
var obj = new Hdove('LJ');
console.log(obj); // {name: "return出來的"}
2.返回基本型別
function Hdove(name) {
this.name = name;
return '123';
}
var obj = new Hdove('LJ');
console.log(obj); // {name: "LJ"}
3.返回一個方法
function Hdove(name) {
this.name = name;
return function() {
console.log(123);
};
}
var obj = new Hdove('LJ');
console.log(obj); // function () { window.runnerWindow.proxyConsole.log(123); }
複製程式碼
有沒有發現神奇的事情發生了,當我們在建構函式中返回一個物件型別A的時候,這個時候我們使用new操作符,實際上返回的就是這個A,反之,返回的是我們新建的這個物件,開始實現!
function myNew(context) {
var res = new Object();
// 判斷建構函式上有沒有原型,有的話進行新增
if(context.prototype) {
res.__proto__ = context.prototype
}
const args = [...arguments].slice(1);
const ret = context.apply(res, args);
// 判斷ret 是不是object或者function,因為null也屬於object,所以要單獨排除
if((typeof ret === 'object' || typeof ret === 'function') && ret !== null) {
return ret;
}
return res;
}
function Hdove1(name) {
this.name = name;
}
function Hdove2(name) {
this.name = name;
return {
name: 'return出來的資料'
}
}
var example1 = myNew(Hdove1, 'LJ');
var example2 = myNew(Hdove2, 'LJ');
console.log(example1); // { name: LJ }
console.log(example2); // { name: return出來的資料 }
複製程式碼
5.完整版
function myNew(context) {
var res = new Object();
if(context.prototype) {
res.__proto__ = context.prototype
}
const args = [...arguments].slice(1);
const ret = context.apply(res, args);
if((typeof ret === 'object' || typeof ret === 'function') && ret !== null) {
return ret;
}
return res;
}
複製程式碼
6.推薦閱讀
- 都2020年了,你應該知道如何手寫Call、Apply、Bind了吧
- 仿網易雲音樂webApp
- 最近在研究Taro,然後基於Taro + TS + Hook + MongoDB + KeystoneJS 寫了一個影像識別的小玩意,歡迎圍觀