JavaScript 之 new 操作符

97 阅读2分钟

new 是做什么的?

MDN 文档上是这样描述的,new 运算符创建一个用户定义的对象类型的实例或具有构造函数的内置对象的实例。

先来了解一下 new 的使用的特性:

function Person(name) {
  this.name = name
}

Person.prototype.sayName = function () {
  console.log(this.name)
}

var p1 = new Person('jack')
console.log(p1.age);                // 22
console.log(p1.name)                //jack
p1.sayName()                        //jack
console.log(p1);

image.png

  1. new 通过构造函数 Person 创建的实例具有构造函数的属性
  2. 创建的实例对象的原型指向构造函数Person,可以访问构造函数原型上的方法和属性

构造函数的返回值

function Person(name){
  this.name = name
  return 1
}

var p1 = new Person('Jack')
console.log(p1.name);  // name

image.png

如果我们显示的给构造函数返回 1,结果一样。但是如果返回一个对象呢

function Person(name){
  this.name = name
  return {age:20}
}

var p1 = new Person('Jack')
console.log(p1.name);  // undefined
console.log(p1.age);   // 20
console.log(p1);

image.png

我们可以看见构造函数的属性name不存在了,同时构造函数的原型对象也变成了 Object 的原型了。

  1. 构造函数返回值是对象,那么返回值就会被使用
  2. 返回的值将影响构造函数的原型指向与this绑定

模拟实现

  1. 创建一个空的对象
  2. 将新创建的对象的原型指向构造函数的原型
  3. 将构造函数的this指向绑定为新创建的对象,并传入剩余的参数
  4. 判断构造函数返回值是否为对象,如果为对象就返回构造函数返回的值,否则返回obj
function New(constructor, ...args) {
  var obj = new Object()
  Object.setPrototypeOf(obj, constructor.prototype)  
  var result = constructor.apply(obj, args)
  return result instanceof Object ? result : obj
}

这里 Object.setPrototypeOf(obj, constructor.prototype) 等同于 obj.__proto__ = constructor.prototype

来测试一下:

function Person() {
  this.name = 'jack'
}

var p1 = New(Person)

p1.age = 20
Person.prototype.name = "Alice"
Person.prototype.sayName = function () {
  console.log(this.name)
}
p1.sayName()          // jack
console.log(p1);

image.png

实例上的属性,原型上的方法与指向,构造函数指向都与预期的new 操作符一致.