寫在前面
在所有的前端面試中常常喜歡考面試者如何手寫一個new操作符宛蚓,作為在準(zhǔn)備秋招的大三黨,我也要考慮這些喇闸。
那么我們先看看new操作符都干了什么事情蒸眠,有哪些操作漾橙?通過下面的代碼來進行思考:
// 新建一個類(構(gòu)造函數(shù))
function Otaku(name, age) {
this.name = name;
this.age = age;
// 自身的屬性
this.habit = 'pk';
}
// 給類的原型上添加屬性和方法
Otaku.prototype.strength = 60;
Otaku.prototype.sayYourName = function () {
console.log('I am ' + this.name);
}
// 實例化一個person對象
const person = new Otaku('喬峰',5000);
person.sayYourName();
console.log(person);//打印出構(gòu)造出來的實例
控制臺打印結(jié)果
解析
從控制臺打印出來的結(jié)果我們可以看出new操作符大概做了一下幾件事情:
- 返回(產(chǎn)生)了一個新的對象
- 訪問到了類Otaku構(gòu)造函數(shù)里的屬性
- 訪問到Otaku原型上的屬性和方法 并且設(shè)置了this的指向(指向新生成的實例對象)
通過上面的分析展示,可以知道new團伙里面一定有Object的參與楞卡,不然對象的產(chǎn)生就有點說不清了霜运。 先來邊寫寫:
// 需要返回一個對象 借助函數(shù)來實現(xiàn)new操作
// 傳入需要的參數(shù): 類 + 屬性
const person = new Otaku('喬峰',5000);
const person1 = objectFactory(Otaku, '鳩摩智', 5000);
// 開始來實現(xiàn)objectFactory 方法
function objectFactory(obj, name, age) {}
// 這種方法將自身寫死了 如此他只能構(gòu)造以obj為原型,并且只有name 和 age 屬性的 obj
// 在js中 函數(shù)因為arguments 使得函數(shù)參數(shù)的寫法異常靈活臀晃,在函數(shù)內(nèi)部可以通過arguments來獲得函數(shù)的參數(shù)
function objectFactory() {
console.log(arguements); //{ '0': [Function: Otaku], '1': '鳩摩智', '2': 5000 }
// 通過arguments類數(shù)組打印出的結(jié)果觉渴,我們可以看到其中包含了構(gòu)造函數(shù)以及我們調(diào)用objectfactory時傳入的其他參數(shù)
// 接下來就是要想如何得到其中這個構(gòu)造函數(shù)和其他的參數(shù)
// 由于arguments是類數(shù)組介劫,沒有直接的方法可以供其使用徽惋,我們可以有以下兩種方法:
// 1. Array.from(arguments).shift(); //轉(zhuǎn)換成數(shù)組 使用數(shù)組的方法shift將第一項彈出
// 2.[].shift().call(arguments); // 通過call() 讓arguments能夠借用shift方法
const Constructor = [].shift.call(arguments);
const args = arguments;
// 新建一個空對象 純潔無邪
let obj = new Object();
// 接下來的想法 給obj這個新生對象的原型指向它的構(gòu)造函數(shù)的原型
// 給構(gòu)造函數(shù)傳入屬性,注意:構(gòu)造函數(shù)的this屬性
// 參數(shù)傳進Constructor對obj的屬性賦值座韵,this要指向obj對象
// 在Coustructor內(nèi)部手動指定函數(shù)執(zhí)行時的this 使用call险绘、apply實現(xiàn)
Constructor.call(obj,...args);
return obj;
}
- 上面的代碼注釋太多踢京,剔除注釋以后的代碼:
function objectFactory() {
let Constructor = [].shift.call(arguments);
const obj = new Object();
obj.__proto__ = Conctructor.prototype;
Constructor.call(obj,...arguments);
return obj;
}
- 還有另外一種操作:
function myNew(Obj,...args){
var obj = Object.create(Obj.prototype);//使用指定的原型對象及其屬性去創(chuàng)建一個新的對象
Obj.apply(obj,args); // 綁定 this 到obj, 設(shè)置 obj 的屬性
return obj; // 返回實例
}