- JavaScript的函數既可以作爲普通函數被調用,也可以作爲構造函數被調用。
- 我們使用new運算符來調用函數時,此時的函數就是一個構造器。
- JavaScript中絕大部分數據都是對象,那麼JavaScript中也一定會有一個根對象的存在,這些對象的鼻祖(根源)都來自於這個根對象。
- JavaScript中的根對象是Object.prototype對象,而這個Object.prototype對象是一個空對象,追其根源,我們遇到的每一個對象都是從Object.prototype克隆而來的,Object.prototype對象就是他們的原型。
- 原型鏈:從Object.prototype克隆除了A對象,我們又從A對象克隆出了B對象,實際上他們的關聯就是一個鏈路,彼此關聯,同時根原型就是Object.prototype。
- 使用new運算符來創建對象的過程:實際上就是先去克隆Object.prototype對象,再進行一些其他額外操作的過程。
首先:
- 創建一個普通函數(使用它來當做構造函數)
function person(name) {
this.name = name;
}
2.在它的原型上創建一個方法
person.prototype.getName = function () {
return this.name
}
- 實現一個new
let _new = function () {
// 從Object上克隆一個對象
let obj = new Object();
// 獲取外部傳入的構造器 person
Constructor = [].shift.call(arguments);
console.log(arguments);
// 指向正確的原型:我們使用person對象創建的
obj.__proto__ = Constructor.prototype;
// 給obj設置屬性
var ret = Constructor.apply(obj, arguments);
// 返回這個對象
return typeof ret === 'object' ? ret : obj;
};
- 驗證這個new是否創建成功
let obj_1 = _new(person, 'sven');
console.log(obj_1.name); // => sven
- 完整代碼
function person(name) {
this.name = name;
}
person.prototype.getName = function () {
return this.name;
};
let _new = function () {
// 從Object上克隆一個對象
let obj = new Object();
// 獲取外部傳入的構造器 person
Constructor = [].shift.call(arguments);
console.log(arguments);
// 指向正確的原型
obj.__proto__ = Constructor.prototype;
// 克隆構造器的屬性給obj
var ret = Constructor.apply(obj, arguments);
// 返回這個對象
return typeof ret === 'object' ? ret : obj;
};
let obj_1 = _new(person, 'sven');
console.log(obj_1.name);
- 7 可能會疑惑的地方
[].shift.call(arguments): 這個是獲取arguments對象的第一個參數,arguments是一個數組對象,但是它又不具備數組的一些方法,打印出來如下:
arguments
{'0': [Function: person], '1': 'sven' }
借用array.prototype對象上的方法就可以完成shift操作,會給我們返回第一個值,也就是person對象,其他的值就是我們傳入的參數。
Constructor.apply(obj, arguments); :用來鏈接構造器,其實就是把剩下的參數也克隆給obj。
{"0":'sven'}