new的时候干了啥

12/28/2020 JS

newMDN (opens new window)上的定义是:new 运算符创建一个用户定义的对象类型的实例或具有构造函数的内置对象的实例

在 JavaScript 中,new是一个关键字,创建了一个对this的绑定.而在面向对象的语言中,new关键字总是用于实例化一个类,如在 Dart 中:

class Person {}
var p = new Person()

在 JavaScript 中,没有类的概念(ES6 的class也只是语法糖而已),但是我们只要使用函数就能来生成对象. 我们使用构造函数来创建一个对象,构造函数与一般的函数没有什么区别,只不过是在调用的时候加上了new关键字.所以我觉得用构造函数调用来代替构造函数的说法可能更加能够让人接受

function Perons() {}
let p = new Perons()
console.log(p) // Perons {}

那么我们来看一下new的时候到底干了啥?

  • 调用函数
  • 自动创建一个新对象
  • 将创建的对象和 this 进行绑定
  • 如果构造函数没有显式的返回值,隐式的返回 this 对象
let p = new Perons()

当运行这句代码的时候,内部的执行大致如下:

// 1.创建一个空对象
var obj = new Object()
// 2.将空对象的原型赋值为构造函数的原型
obj.__proto = Perons.prototype
// 3.变更构造函数内部this,将其指向刚刚创建出来的对象
Perons.call(obj)
// 4.返回对象
return obj

我们先来看看这里面的第 2 步,将空对象的原型赋值为构造函数的原型,因此在构造函数原型上的属性和方法可以被 obj 这个对象调用,我们来看如下代码:

function Person(name) {
  this.name = name
}
Person.prototype.gender = 'male'
Person.prototype.action = function() {
  console.log('breath')
}
let p = new Person('zhangsan')
console.log(p.__proto__ === Person.prototype) // true
console.log(p.__proto__.__proto__ === Object.prototype) // true
// 上面证明了将创建出来的对象的原型赋值为构造函数的原型的说法
console.log(p.name) // zhangsan
console.log(p.gender) // male
p.action() // breath

再来看第 4 步,这里要注意的是,如果构造函数显式的设置了返回值,且返回值是一个对象的话,则上面的第 4 步中,返回这个对象.如果没有显式的返回一个对象的话.则第 4 步隐式的返回创建的对象(即 obj).null是个例外,虽然我们认为null是个对象,但是返回null相当于没有显式返回.我们来看如下代码就明白了: 没有返回值的情况:

function Person(name) {
  this.name = name
}
let p = new Person('zhangsan')
console.log(p) // Person {name: "zhangsan"}

返回一个对象:

function Person2(name) {
  this.name = name
  return {
    age: 12,
  }
}
let p2 = new Person2('zhangsan')
console.log(p2) // {age: 12}

返回一个非对象:

function Person3(name) {
  this.name = name
  return 666
}
let p3 = new Person3('zhangsan')
console.log(p3) // Person3 {name: "zhangsan"}

返回 null:

function Person4(name) {
  this.name = name
  return null
}
let p4 = new Person4('zhangsan')
console.log(p4) // Person4 {name: "zhangsan"}

总结: new到底干了啥,这里我引用MDN (opens new window)中的话

  • 创建一个空的简单 JavaScript 对象(即{})
  • 链接该对象(即设置该对象的构造函数)到另一个对象
  • 将步骤 1 新创建的对象作为 this 的上下文
  • 如果该函数没有返回对象,则返回 this
    希望像星光一样闪烁
    文雀