JavaScript中new的用處及其實現


new 的用途

newnew 運算符用於創建一個自定義對象實例,或者是一個構造函數內置對象的實例。啥意思呢,有點拗口,我們先看個栗子先。

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"}

👏👏👏👏👏👏


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM