JS系列-趣谈new

最近天气好冷,上下班骑着小电驴,风吹得整我的都是冰冰的,小伙伴要注意保暖,千万别冷到了。markdown

new简介

咱们先来看看MDN上给出的简介app

new 运算符建立一个用户定义的对象类型的实例或具备构造函数的内置对象的实例。函数

new 关键字你们都不陌生,用来给构造函数建立实例的,可是 new 它到底干了些什么,可能就不是很清楚了,下面我来给你们解开 new 的神秘面纱。oop

咱们先来复习下 new 的使用,来看看 new 的功能,先知道 new 作了什么事情才能更好的去实现它。测试

function Pig(name, age{
    this.name = name;
    this.age = age;
    this.habit = '吃棒棒糖';
}

Pig.prototype.sayName = function({
    console.log('我叫' + this.name);
}

Pig.prototype.skill = '降龙十巴掌!(๑•̀ㅂ•́) ✧';

let GGBond = new Pig("猪猪侠"13);

console.log(GGBond); // Pig { name: '猪猪侠', age: 13, habit: '吃棒棒糖', __proto__: Object }
console.log(GGBond.name); // 猪猪侠
console.log(GGBond.skill); // 降龙十巴掌!(๑•̀ㅂ•́) ✧
GGBond.sayName(); // 我叫猪猪侠
复制代码

经过上面的栗子咱们能够看到 new 出来的实例对象:ui

  1. 能访问到构造函数 Pig 中的私有属性
  2. 能访问到构造函数 Pig.prototype 上的属性

new的实现

经过上面的例子咱们已经明白了 new 的功能了,可是具体 new 是怎么作到的呢?让咱们来看看MDNthis

  1. 建立一个空的简单JavaScript对象(即{});
  2. 连接该对象(设置该对象的constructor)到另外一个对象 ;
  3. 将步骤1新建立的对象做为this的上下文 ;
  4. 若是该函数没有返回对象,则返回this。

咱们跟着这个功能来一步步实现 new 吧!spa

建立空对象

建立一个空的简单JavaScript对象(即{});prototype

  • 由于 new 是关键字,没办法覆盖,全部咱们使用函数来模拟 new 的效果,将构造函数以第一个参数进行传入
function myNew(Ctor, ...args{
    let obj = {}; 
}
复制代码

连接对象

连接该对象(设置该对象的constructor)到另外一个对象 ;code

  • 由于咱们的实例须要可以访问到构造函数的原型,咱们将新对象的 proto 指向构造函数,js 会经过这个属性向上查找原型链,立个flag,下周我会继续出一篇关于原型链的文章,有兴趣的小伙伴能够点个关注。
function myNew(Ctor, ...args{
    let obj = {}; 
    obj.__proto__ = Ctor.prototype;
}
复制代码

修改上下文

将步骤1新建立的对象做为this的上下文 ;

  • 修改上下文的方法有不少, bind 、 call 、apply 均可以修改咱们的上下文,这里我使用 apply 进行修改,注意这里还隐式包含了指行一次构造函数。
  • 绑定 this 指向建立的实例对象
function myNew(Ctor, ...args{
    let obj = {}; 
    obj.__proto__ = Ctor.prototype;
    const result = Ctor.apply(obj, args);
}
复制代码

返回结果

若是该函数没有返回对象,则返回this。

function myNew(Ctor, ...args{
    let obj = {}; // 建立实例对象
    obj.__proto__ = Ctor.prototype; // 原型链继承
    const res = Ctor.apply(obj, args); // 修改 this 指向实例
    if (/^(object|function)$/.test(typeof res)) return res; // 构造函数返回的是对象就直接该返回该结果
    return obj; // 不然返回实例
}
复制代码

测试功能

代码写完了,咱们来执行上面的例子来看下是否和原生 new 表现一致

function Pig(name, age{
    this.name = name;
    this.age = age;
    this.habit = '吃棒棒糖';
}
Pig.prototype.sayName = function({
    console.log('我叫' + this.name);
}
Pig.prototype.skill = '降龙十巴掌!(๑•̀ㅂ•́) ✧';

function myNew(Ctor, ...args{
    let obj = {}; // 建立一个实例对象
    obj.__proto__ = Ctor.prototype;
    const res = Ctor.apply(obj, args);
    if (/^(object|function)$/.test(typeof res)) return res;
    return obj;
}

let myGGBond = myNew(Pig, "猪猪侠"13);

console.log(myGGBond); // Pig { name: '猪猪侠', age: 13, habit: '吃棒棒糖', __proto__: Object }
console.log(myGGBond.name); // 猪猪侠
console.log(myGGBond.skill); // 降龙十巴掌!(๑•̀ㅂ•́) ✧
myGGBond.sayName(); // 我叫猪猪侠

// 测试返回函数

function Dog(name{
    this.name = name;
    this.habit = '吃骨头';
    return function({
        console.log('随便输出点什么吧');
    }
}
let myDog = myNew(Dog, '金毛');
console.log(myDog); // ƒ () {...}

// 测试返回对象
function Cat(name{
    this.name = name;
    this.habit = '吃鱼';
    return {
        name
    }
}
let myCat = myNew(Cat, '黑猫警长');
console.log(myCat); // { name: '黑猫警长' }
复制代码

能够看到和原生的 new 结果是同样的。

很是感谢各位能阅读到这里,以为有帮助的话不妨点个赞,你的支持是对我对最大的鼓励。

相关文章
相关标签/搜索