js new的实现原理

new的使用方法

new用来创建一个实例对象,其隐式原型__proto__指向构造函数的原型prototype

1、在构造函数中使用new

// 构造函数
function Car(color, brand) {
    this.color = color
    this.brand = brand
    this.age = 0
    // 默认返回实例对象 this
}
// 原型方法
Car.prototype.getcolor = function () {
    return this.color
}
Car.prototype.getbrand = function () {
    return this.brand
}

const VW = new Car('white', '大众')
const BMW = new Car('red', '宝马')
console.log(VW, BMW);//Car { color: 'white', brand: '大众', age: 0 } Car { color: 'red', brand: '宝马', age: 0 }

用构造函数Car创建对象,该函数默认返回this(也就是一个实例)
我们也可以指定构造函数的返回值,让他不返回this,而是返回指定的对象

const instance = { color: 'blue', brand: '奔驰' }
// 构造函数
function Car(color, brand) {
    this.color = color
    this.brand = brand
    this.age = 0
    return instance // 指定返回对象
}
const VW = new Car('white', '大众')
console.log(VW);// { color: 'blue', brand: '奔驰' }

2、在类中使用new

// 类
class Book {
    constructor(color, name) {
        this.color = color
        this.bookname = name
        this.page = 0
        // 默认返回实例对象 this
    }

    getcolor = function () {
        return this.color
    }

    getbrand = function () {
        return this.brand
    }
}
const b1 = new Book('white', '第一行代码')
const b2 = new Book('red', 'javascript')
console.log(b1, b2);//Book { color: 'white', bookname: '第一行代码', page: 0 } Book { color: 'red', bookname: 'javascript', page: 0 }

constructor方法是类的默认方法,创建类的实例化对象时被调用。
我们也可以指定constructor的返回值

// 类
const instance = { color: 'blue', brand: '学电脑' }
class Book {
    constructor(color, name) {
        this.color = color
        this.bookname = name
        this.page = 0
        return instance // 指定返回对象
    }
}
const b1 = new Book('white', '第一行代码')
console.log(b1);// { color: 'blue', brand: '学电脑' }

原理分析

那么new关键字到底做了哪几件事情,如何实现new的功能?

  1. new首先可以返回一个实例对象
  2. 该对象的__proto__ 指向构造函数的prototype
  3. 该对象身上的属性是由构造函数执行而添加进去的
  4. 构造函数默认返回一个实例对象,但是也可以自己指定返回的对象

代码实现

实现方法一:

function Fn() {
    this.age = 23
    this.class = 3
}

function $new(Fn) {
    const obj = {}
    obj.__proto__ = Fn.prototype
    obj.Fn = Fn
    obj.Fn()
    delete obj.Fn
    return obj
}

const instance = $new(Fn)
console.log(instance);// Fn { age: 23, class: 3 }

分析:

  • 先创建一个空的字面量对象obj,把obj的原型指向构造函数的原型
  • 我们希望obj的age属性设置为23,class属性设置为3,如何实现呢?
  • 只需要把Fn这个函数在obj身上执行一下就可以了
  • 所以,临时给obj加上Fn属性,一会调用Fn的时候,obj的age和class属性就被设置好了
  • 最后得删除这个临时属性Fn

实现方法二:

function $new(Fn) {
    const obj = {}
    obj.__proto__ = Fn.prototype
    Fn.apply(obj)
    return obj
}

const instance = $new(Fn)
console.log(instance);// Fn { age: 23, class: 3 }

分析:
刚才在obj身上添加临时的Fn的目的:让Fn在执行的时候this指向obj(谁调用Fn,this就指向谁)
所以上面做了优化,直接用apply方法改变this指向,免去了添加临时属性的操作

实现方法三:

function $new(Fn) {
    const obj = Object.create(Fn.prototype)
    Fn.apply(obj)
    return obj
}

const instance = $new(Fn)
console.log(instance);// Fn { age: 23, class: 3 }

分析:
其实原型的挂载也可以用Object.create来进一步简化代码,于是又少了一行代码

进一步完善

$new返回值问题

我们知道,new关键字有个特点:构造函数默认返回一个实例对象,但是也可以自己指定返回的对象
为了实现这个需求,我们对$new的返回值做个区分:

function $new(Fn) {
    const obj = Object.create(Fn.prototype)
    const inner = Fn.apply(obj)// 检查Fn有没有定义返回值
    return inner instanceof Object ? inner : obj// 定义了返回值就返回inner对象,默认返回实例对象obj
}

const instance = $new(Fn)
console.log(instance);// Fn { age: 23, class: 3 }

这里代码的核心就是会去检查Fn执行完成后的返回值,$new发现Fn中有返回值就抛出去,否则默认返回刚创建好的对象

$new传参问题

function $new(Fn,...arg) {
    const obj = Object.create(Fn.prototype)
    const inner = Fn.apply(obj,arg)
    return inner instanceof Object ? inner : obj
}

const instance = $new(Fn,'abc','hahaha')
console.log(instance);// Fn { age: 23, class: 3 }

参数通过剩余运算符收集,传递给Fn

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值