首先咱們要知道new
操做符具體作了些什麼?數組
__proto__
指向函數的原型prototype
this
指向該對象return
或return
了基本類型,則將新對象做爲返回值若是對於原型還不是很瞭解的話建議先看看:JavaScript溫故而知新——原型和原型鏈bash
先來實現前三點的效果:閉包
function new2() {
// 新建一個對象
var obj = new Object(),
// 取得第一個參數,即傳入的構造函數。
// 這裏 shift 會修改原數組,所以 arguments 會被去掉第一個參數
Constructor = [].shift.call(arguments);
// 將 obj 的原型指向構造函數,這樣 obj 就能夠訪問到構造函數原型中的屬性了
obj.__proto__ = Constructor.prototype;
// 使用 apply ,改變構造函數 this 的指向到新建的對象,這樣 obj 就能夠的訪問到構造函數中的屬性了
Constructor.apply(obj, arguments);
return obj;
};
複製代碼
咱們能夠作個測試app
function Person(name, age) {
this.name = name;
this.age = age;
}
Person.prototype.sayName = function() {
console.log('I am' + this.name);
}
var person = new2(Person, 'xiao', '18')
console.log(person.name) // xiao
console.log(person.age) // 18
person.sayName(); // I am xiao
複製代碼
實現返回值的效果函數
假如構造函數是有返回值,而且返回值是一個對象:post
function Person(name, age) {
this.skill = 'eat';
this.age = age;
return {
name: name,
habit: 'sleep'
}
}
var person = new Person('xiao', '18')
console.log(person.name) // xiao
console.log(person.habit) // sleep
console.log(person.skill) // undefined
console.log(person.age) // undefined
複製代碼
能夠看到實例person
中只能訪問返回的對象中的屬性,說明此時new
的返回值爲構造函數Person
return 出來的對象。測試
假如構造函數的返回值是一個基本類型的值:ui
function Person(name, age) {
this.skill = 'eat';
this.age = age;
return 'hello world'
}
var person = new Person('xiao', '18')
console.log(person.name) // undefined
console.log(person.habit) // undefined
console.log(person.skill) // eat
console.log(person.age) // 18
複製代碼
能夠看到實例person
能夠正常訪問構造函數中的屬性,說明此時new
的返回值爲新建立的原型指向構造函數的對象。this
按照上面的結論來完整實現咱們的new2
:spa
function objectFactory() {
var obj = new Object(),
Constructor = [].shift.call(arguments);
obj.__proto__ = Constructor.prototype;
var ret = Constructor.apply(obj, arguments);
// 判斷構造函數返回值是否爲對象,是的話返回這個對象,不是則正常返回
return typeof ret === 'object' ? ret : obj;
};
複製代碼
結尾
系列文章: