js new的原理

学习本文内容内容前,你需要了解js中对象,原型链call(),bind(),apply(),arguments的用法。

new操作符的原理

在调用 new 的过程中做了四件事:

  1. **新生成对象:**new关键字会首先创建一个空对象
  2. **链接到原型:**将这个空对象的原型对象指向构造函数的原型属性,从而继承原型上的方法
  3. **绑定this:**将this指向这个空对象,执行构造函数中的代码,以获取私有属性
  4. **返回新对象:**如果构造函数返回了一个对象res,就将该返回值res返回,如果返回值不是对象,就将创建的对象返回

理解了new的原理,我们就可以手动实现一个new的创建了。

//创建一个 _new
function _new() {
    //定义空对象
    /*
        * arguments获取调用_new时所传入的实参
        * 它并不是一个真正的数组
        * 我们约定,调用_new时,所传入的第一个元素是构造器
        */
    const obj = {};

    // 取出参数列表的第一个参数(构造函数)
    /*
        * shift作用:
        * 1.取出数组的第一个元素(构造器)
        * 2.同时它会修改数组
        */
    const fn = [].shift.call(arguments);

    //手动指正obj的构造函数为 fn(链接原型)
    obj.__proto__ = fn.prototype;

    //调用fn,改变this为obj,传入剩余参数arguments(此时arguments是取出第一个元素后的部分)
    const res = fn.apply(obj, arguments);

    //考虑到fn函数中有return的原因,需要对res进行判断
    // return typeof res === 'object' || typeof res === 'function' ? res : obj;
    return res instanceof Object ? res : obj;
}

案例

//构造函数
function Person(name, sex) {
    this.name = name;
    this.sex = sex
}
 Person.prototype.getName = function() {
    return this.name
}

const person1 = new Person('hugh', '男');
const person2 = _new(Person, 'hugh', '男');
console.log(person1) //Person {name: 'hugh', sex: '男'}
console.log(person2)//Person {name: 'hugh', sex: '男'}

//共享原型上的方法
console.log(person1.getName === person2.getName); //true

注解:

  1. 关于[].shift.call(arguments)
    因为 arguments 是类数组对象,虽然有length属性,但是没有 shift 方法,故通过 call 方法改变执行上下文调用 shift 方法

  2. 关于obj.proto = fn.prototype
    原型链使用, __proto__ 是每个对象拥有的隐藏属性,指向它构造函数的原型对象(prototypeprototype 是每个构造函数(Fuction.prototype除外)拥有的属性,它是函数所独有的,它是从一个函数指向一个对象(构造函数的原型对象)

若是对上面的shiftcall和原型链不是特别熟悉,我们再看看下面一个。

//不携带参数
function new1() {
    // 获取构造函数和传递的参数
    const [fn, ...args] = [...arguments];

    //1.通过Object.create()方法创建一个构造函数实例原型引用的一个对象
    const obj = Object.create(fn.prototype);

    //2.将构造函数中的this指向obj,执行构造函数代码,获取返回值 
    const res = fn.apply(obj, args);
    //3.判断返回值类型 
    return res instanceof Object ? res : obj;
}

//携带参数
function new2(fn, ...args) {
    //1.创建一个空对象,并将对象的__proto__指向构造函数的prototype 这里我两步一起做了
    const obj = Object.create(fn.prototype);
    //2.将构造函数中的this指向obj,执行构造函数代码,获取返回值 
    const res = fn.apply(obj, args);
    //3.判断返回值类型 
    return res instanceof Object ? res : obj;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

天弈初心

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值