new 的用途
new
:new
運算符用於創建一個自定義對象實例,或者是一個構造函數內置對象的實例。啥意思呢,有點拗口,我們先看個栗子先。
new F() 時,發生了什么
-
第一版
栗子在這:
function Person(name, age) {
this.name = name
this.age = age
console.log(this) // Person{name: "xuedinge", age: "20"}
}
Person.prototype.have = "cat"
const person = new Person("xuedinge", "20")
console.log(person.name) // xuedinge
console.log(person.have) // cat
console.log(person) // Person{name: "xuedinge", age: "20"}
從這個栗子中,我們可以看到,new 具有以下能力:
1、new
創建出來的實例可以訪問構造函數Person
內的屬性;
2、new
創建出來的實例可以訪問構造函數原型上的屬性;
3、new
可以將構造函數中的this
綁定到新創建出來的對象上;
那我們就先針對new
的這三個能力先實現一下:
function fakeNew(Fn) {
// 創建一個空對象
let obj = new Object()
// 將新對象的原型指針指向構造函數的原型
obj.__proto__ = Fn.prototype
// 處理除了 Fn 以外的剩余參數
Fn.apply(obj, [].slice.call(arguments, 1))
return obj
}
看下效果:
function Person(name, age) {
this.name = name
this.age = age
console.log(this) // Person {name: "xuedinge", age: "20"}
}
Person.prototype.have = "cat"
function fakeNew(Fn) {
// 創建一個空對象
let obj = new Object()
// 將新對象的原型指針指向構造函數的原型
obj.__proto__ = Fn.prototype
// 處理除了 Fn 以外的剩余參數
Fn.apply(obj, [].slice.call(arguments, 1))
return obj
}
const newPerson = fakeNew(Person, "xuedinge", "20")
console.log(newPerson.name) // xuedinge
console.log(newPerson.have) // 20
console.log(newPerson) // Person {name: "xuedinge", age: "20"}
看樣子跟new
的能力比較相像了。但是當構造函數里有返回值時,是怎么樣子的呢,再看個🌰:
// 當返回值是對象時:
function Person(name, age) {
this.name = name
this.age = age
console.log(this) // Person {name: "xuedinge", age: "20"}
return {
car: "leikesasi"
}
}
Person.prototype.have = "cat"
const person = new Person("xuedinge", "20")
console.log(person.name) // undefined
console.log(person.have) // undefined
console.log(person.car) // leikesasi
console.log(person) // {car: "leikesasi"}
可以看出,當構造函數有返回值是對象時,new
創建的實例對象就是構造函數返回的結果,當返回值是普通對象時呢,看下面這個🌰:
// 當返回值是普通值時:
unction Person(name, age) {
this.name = name
this.age = age
console.log(this) // Person{name: "xuedinge", age: "20"}
return "leikesasi"
}
Person.prototype.have = "cat"
const person = new Person("xuedinge", "20")
console.log(person.name) // xuedinge
console.log(person.have) // cat
console.log(person) // Person{name: "xuedinge", age: "20"}
當返回值是普通對象時,跟沒有返回值時,結果是一致的。
-
第二版
現在呢,我們把第一版的實現稍作修改:
function fakeNew(Fn) {
// 創建一個空對象
let obj = new Object()
// 將新對象的原型指針指向構造函數的原型
obj.__proto__ = Fn.prototype
// 處理除了 Fn 以外的剩余參數
let result = Fn.apply(obj, [].slice.call(arguments, 1))
// 若構造函數返回對象( null 除外),則返回 result,否則返回 obj
return typeof result === "object" ? result || obj : obj
}
看下效果,見證奇跡的時刻:
function Person(name, age) {
this.name = name
this.age = age
console.log(this) // Person {name: "xuedinge", age: "20"}
return {
car: "leikesasi"
}
}
Person.prototype.have = "cat"
function fakeNew(Fn) {
// 創建一個空對象
let obj = new Object()
// 將新對象的原型指針指向構造函數的原型
obj.__proto__ = Fn.prototype
// 處理除了 Fn 以外的剩余參數
let result = Fn.apply(obj, [].slice.call(arguments, 1))
return typeof result === "object" ? result || obj : obj
}
const newPerson = fakeNew(Person, "xuedinge", "20")
console.log(newPerson.name) // undefined
console.log(newPerson.have) // undefined
console.log(newPerson) // {car: "leikesasi"}
👏👏👏👏👏👏