手写new new到底干了什么

想要手写一个new操作符,首先得知道new到底做了什么?new一个构造函数,最终我们得到的是一个对象,那么我们从工厂模式和构造函数模式上来看看这背后的发生了什么。

首先,我们先来看工厂模式下的一个函数,创建一个新的对象:

// 工厂模式

function person (name, age, gender) {
    var obj = {};
    obj.name = name;
    obj.age = age;
    obj.gender = gender;
    return obj;
}

// 使用工厂函数创建一个新对象

const p0 = person('Mary', 18, 'female');

// 这样我们得到一个新的对象 {name: 'Mary', age: 18, gender: 'famale'}

然后,我们再看构造函数模式下创建一个新的对象:

// 构造函数模式下

function Person (name, age, gender) {
    this.name = name;
    this.age = age;
    this.gender = gender;
}

// 使用构造函数创建一个对象

const p1 = new Person('Jerry', 20, 'male');

// 这样我们可以得到一个新的对象 {name: 'Jerry', age: 20, gender: 'male'}

再然后,对比这两种模式,似乎看到些许奥秘。this。

可以看到,构造函数中,对象出现的地方都用了 this 进行了替代,并且在new的时候,直接可以把这个对象return出来。

到了这里,我们看到了 new 操作符其中的一个作用,就是创建了一个新的对象,并且把构造函数中的this(执行环境)给了这个新建的这个对象。

然后,我们再看,使用构造函数还可能用到一些公共的属性和方法,也就是会在prototype上定义一些公共的方法:

// 在原型上定义一些公共方法,以便所有的实例对象都可以使用

// 接上

Person.prototype = {
    sayName: function () {
        console.log(this.name)
    }
}

const p1 = new Person('Jerry', 20, 'male');

p1.sayName(); // -> 'Jerry'

// p1 这个实例,可以使用构造函数原型上的方法。

可以看到,利用构造函数创建的这个实例对象,可以访问到构造函数原型上的方法。那么 new 一下,让实例对象有了这个能力。这是怎么做到的? 立马可以想到 原型链。也就是说,在new的时候,js底层手动的将新创建的这个对象的原型链等于了这个构造函数的原型,用代码表示:

// -> 用代码表示一下就是:

p1.__proto__ = Person.prototype;

// 这样原型链打通之后,就可以直接访问 构造函数原型上的属性和方法了;

至此,可以得到 new 操作符最重要和核心的两个功能:

  1. 创建一个新的对象,并分配给构造函数的this
  2. 手动把新建对象的原型链分配给构造函数的prototype

那么,搞清了new主要干了什么事情之后,就可以开始手写new了:

// 开始手写 new方法

function myNew (func, ...args) {
    //1、新建一个新的对象
    var obj = {};
    
    //2、手动改变新建对象的原型链
    obj.__proto__ = func.prototype;

    //3、改变this指向 执行构造函数
    func.call(obj, ...args);
    
    //4、返回这个新对象
    return obj;
}

想起创建对象还有个方法   Object.create() : 方法创建一个新对象,使用现有的对象来提供新创建的对象的__proto__。附上 MDN 方便查看:      https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Object/create

可以再简写一下:

// 利用 Object.create()方法 简化一下

function myNew (func, ...args) {
    
    var obj = Object.create(func.prototype);
    
    func.call(obj, ...args);

    return obj;

}

附加题: 这里改变this指向的时候只是用了call,但是传参的 args 是一个数组,那么为什么这里不直接用 apply?这只是因为 call的性能会比apply好。为什么呢? 附上github上issue : https://github.com/noneven/__/issues/6。 

额,暂时就这样吧...

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值