通过原型理解 javascript 中 new 命令的原理

原型

引出原型

    开始之前,我们先看一段代码

const obj = {}
obj.toString()	//[object Object]

    这段代码做了两件事情:

  1. 创建一个名为 obj 的对象
  2. 调用 obj 的 toString 方法,返回这个对象的字符串形式

    我们创建了一个空对象,并没有在它身上声明 toString 方法,但是却成功调用了 toString 并返回了一个字符串。这里我们就要明白,我们调用 toString 方法都经历了哪些过程:

  1. 浏览器首先检查,obj 对象是否具有可用的 toString() 方法。
  2. 如果没有,则浏览器检查 obj 对象的原型对象是否具有可用的 toString() 方法,这里有这个方法(为什么会有,请看下文),于是该方法被调用。

    所以,在这里 obj 调用的并不是自身的 toString 方法,而是找到了它的原型对象中的 toString ,然后再调用。那么,原型对象又是怎么来的?

什么是原型对象

JavaScript 规定,每个函数都有一个prototype属性,指向一个对象

    每个函数都有一个prototype属性,指向一个对象,但是这些和 obj 有什么关系?我们知道,obj 对象是 Object 构造函数生成的实例,构造函数也是函数。那么 Object 就有一个 prototype 属性,指向一个对象,而这个对象,就是 obj 要找的原型对象。我们不妨在控制台打印一下 Object.prototype

控制台打印 Object.prototype
    所以,obj 调用的其实就是它的原型对象(Object.prototype)上的 toString 方法。
    注意上图中 prototype 对象还有一个 constructor 属性,默认指向实例对象所在的构造函数。也就是说,obj 的原型对象上的 constructor 指向 Object ,打印 Object.prototype.constructor === Object 会返回 true 。 到现在,实例对象、原型对象、构造函数三者之间的关系应该是很明确的,如下图所示:
实例对象、原型对象、构造函数的关系

Object.getPrototypeOf() 方法返回指定对象的原型

new 命令的原理

    知道什么是原型和实例对象、原型对象、构造函数三者之间的关系后,可以自己实现一个 _new 函数来模仿 new 命令的操作。
    前置知识:Object.create

Object.create() 方法用于创建一个新对象,使用现有的对象来作为新创建对象的原型(prototype)

const person = { name: 'xxx' }
const person2 = Object.create(person)
person2.name	//xxx

自定义构造函数

    首先,我们自定义一个 Dog 构造函数,并生成一个实例:

function Dog(breed) {
  this.breed = breed
}
const myDog = new Dog('中华田园犬')

    有一点需要注意的是,如果构造函数内部有 return 语句,而且 return 后面跟着一个对象,new 命令会返回 return 语句指定的对象,否则,直接返回实例对象:

function Dog(breed) {
  this.breed = breed
  return { name: 'xxx' }
}
const myDog = new Dog('中华田园犬')
myDog.name	//xxx

自定义 _new 函数

    那么不通过 new 命令来创造实例,如何自己去实现 new 命令的操作。其实,主要有三个地方需要考虑:

1.以构造函数的 prototype 属性为原型创建一个空对象,这样空对象才能正确的继承属性和方法
2.将这个空对象绑定为构造函数内部的 this 并且执行,这样才能实现构造函数内部的操作(比如附值操作:this.name = ‘xxx’)
3.判断构造函数的返回值并返回

    具体实现如下:

function _new(Constructor, ...arg) {
  // 以构造函数的 prototype 属性为原型创建一个空对象
  const newObject = Object.create(Constructor.prototype)
  // 将这个空对象绑定为构造函数内部的 this 并且执行
  // arg 是构造函数需要的参数,也应该传入
  const result = Constructor.apply(newObject, arg)
  // 判断返回值
  return typeof result === 'object' && result != null ? result : newObject
}
const myDog = _new(Dog, '中华田园犬')
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值