手写一个 new

写在前边:
手写一个 new 我们需要了解原型的概念,和 this的指向问题

在执行 new 的时候做了什么

我们执行 new 来看一下 new 的过程中发生了什么:

function Person(name) {
  this.name = name
  this.sayName = function () {
    console.log('name', this.name)
  }
}
const person = new Person('ayetongzhi')
console.log('person', person)
person.sayName()

在这里插入图片描述
打印结果如上,根据打印结果我们可以知道:

  1. 返回了一个对象(person),这个对象不会凭空的产生,因此在 new 的过程中是创建了一个对象并返回。
  2. this 指向创建的新对象,并执行函数。需要将 this 指向新的对象,才能构造函数的属性赋值给实例对象。
  3. 改变实例 的 __proto__ 属性,指向构造函数的原型。如下图所示,通过构造函数 (Function) 创建的实例**(instance)** ,它的 __proto__ 属性指向构造函数 **(Function)**的 prototype
    在这里插入图片描述
  4. 构造函数显示的返回一个对象,则返回该对象。下面对这条问题进行解释,上代码:
function Person(name) {
  this.name = name;
  this.sayName = function () {
    console.log("name", this.name);
  };
  // 显示的返回一个对象
  return {
    name: "maomao",
    sayName: function () {
      console.log("name", this.name);
    }
  };
}
const person = new Person("ayetongzhi");
console.log("person", person);
person.sayName();  //maomao

运行结果可知,在 new Person 操作后返回了return后面返回的对象。
在这里插入图片描述

实现 new

根据 new 操作执行的内容,来一步步实现手写的 new

// fn 构造函数
// ...args 构造函数传入的参数
function myNew (fn, ...args) {
  // 创建新的对象
  var obj = {}
  // 将对象的 __proto__ 属性指向构造函数的原型
  obj.__proto__ = fn.prototype
  // 将 **this** 指向创建的新对象,并执行构造函数,保存返回结果
  let result = fn.call(obj, ...args)
  // 构造函数返回的结果是对象则返回该对象 result,否则返回新创建的对象 obj
  return result instanceof Object ? result : obj
}

通过以上代码我们实现了手写的 new,然而 __proto__ 属性是一个有争议不建议使用的属性,我们使用 Object.create() 方法来代替。Object.create() 方法用于创建一个新对象,使用现有的对象来作为新创建对象的原型(prototype)。举个例子:

let a = {
  name: 'maomao'
}
let b = Object.create(a)
console.log('b 的 __proto__ 指向 a', b.__proto__ === a) // true

以上的代码 let b = Object.create(a) 使新创建的对象 b__proto__ 指向了 现有对象a

因此,我们优化一下手写的 myNew 方法:

// fn 构造函数
// ...args 构造函数传入的参数
function myNew (fn, ...args) {
  // 创建新对象 obj,并改变 obj 的 __proto__ 指向构造函数的 prototype
  var obj = Object.create(myNew.prototype)
  // 将 **this** 指向创建的新对象,并执行构造函数,保存返回结果
  let result = fn.call(obj, ...args)
  // 构造函数返回的结果是对象则返回该对象 result,否则返回新创建的对象 obj
  return result instanceof Object ? result : obj
}

运行以下代码检验手写的 new 方法是否存在问题:

function Person(name) {
  this.name = name;
  this.sayName = function () {
    console.log("name", this.name);
  };
}
const person = myNew(Person, "ayetongzhi");
console.log("person", person);
person.sayName();  // ayetongzhi

当没有显示的返回对象的时候,新创建了对象。并改变this指向到新的对象,同时执行构造函数。改变了新创建对象的 __proto__ 指向了构造函数的 prototype,与 new 操作符执行的结果一致。。

在这里插入图片描述

function Person(name) {
  this.name = name;
  this.sayName = function () {
    console.log("name", this.name);
  };
  return {
    name: "maomao",
    sayName: function () {
      console.log("name", this.name);
    }
  };
}
const person = myNew(Person, "ayetongzhi");
console.log("person", person);
person.sayName();  // maomao

当构造函数显示的返回一个对象的时候,打印结果如下,与 new 操作符执行的结果一致。

在这里插入图片描述

以上我们了解了在执行 new 操作时,做了些什么,并根据 new 操作的表现,实现了手写 new 函数。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值