# 模拟实现 new 操作符

如果你对面对对象编程有所了解的话,你对new操作符一定不会陌生。js也可以使用new来创建一个新的对象,今天我们就来看看new的实现原理,以及如何自己实现一个具备new功能的函数。

首先我们先来看一下MDN上对new操作符的介绍,它归结为以下四个步骤:

    1. Creates a blank, plain JavaScript object; (创建一个简单对象)
    1. Links (sets the constructor of) this object to another object; (链接这个对象到另一个对象上)
    1. Passes the newly created object from Step 1 as the this context; (将第一步创建的对象作为this
    1. Returns this if the function doesn't return its own object. (如果函数没有返回对象的话,返回this

OK,有一个大概的了解,我们就开始。

本文的内容,你需要有js的原型对象有所了解,推荐《javascript高级程序设计》一书。

首先来看一个例子:

function Player(name) {
  this.name = name;
}
var player = new Player('Kobe')

console.info(player) // => Player { name: 'Kobe' }

首先,我们能直观看到的,是使用new操作符,创建了一个Player的实例,它有一个实例属性name,值为"Kobe"。但是,这个player实例,其实这时候已经被加上了一个内部属性[[prototype]],大部分浏览器都会使用__proto__这个属性来表示这个对象。也就是说,我们的player.__proto__对象,就是它的原型对象(实际上它是一个指针,指向的是Player.prototype对象)。

所以,这个时候,有如下的关系:

player.__proto__ === Player.prototype // true
// 或者使用 ES5 的方法:
Object.getPrototypeOf(player) === Player.prototype

还有一个,就是我们的playername属性被正常赋值了,也就是说,函数中的this,实际上会绑定到我们的player对象上。

对此,总结上面的几点,new的功能如下:

  • 返回一个新对象。这里要提醒一下,如果函数返回了对象类型的值,那么这个值会作为new操作符的结果;如果返回的是基本类型,则会被忽略
  • 绑定this
  • 把对象的[[prototype]]属性指向函数的prototype属性。

我们可以写出new的实现源码:





 








function newOp(Ctor, ...rest) {
  if (typeof Ctor !== 'function') {
    throw new Error('First argument must be a function')
  }
  var o = Object.create(Ctor.prototype)
  var result = Ctor.apply(o, rest)
  if (result instanceof Object) {
    return result
  }
  return o;
}

这里使用了Object.create来建立了对象和函数原型对象的关系,关于这个方法的介绍,可以参考另一篇博文我们也可以使用 Object.setPrototypeOf(o, Ctor.prototype)来达到相同的目的

我们用上面的例子来测试一下:

var player = newOp(Player, 'Fisher')

console.info(player.__proto__ === Player.prototype) // => true
console.info(player.name) // => Fisher

Done!

上次更新: 5/23/2020, 3:25:52 PM