在讲 Javascript 中 new 操作符的机制之前,首先需要说明的一点是:Javascript 中 new 操作符的机制和传统的面向对象语言的 new 机制完全不同,所以千万不要把两者联系到一起来理解。
好了,记住上面一点后,我们来说一下 new 操作符的用法,看下面的代码:
let obj = new FunctionName()
new 操作符使用起来很简单,只要在 new 操作符的后面加上已经定义了的函数名,再加上括号即可。该操作符的返回值是一个对象字面量。其内部运行的机制可分为以下四个步骤:
- 创建一个全新的对象。
- 将这个对象的原型链(__proto__)指向函数的 .prototype。
- 将这个对象绑定到函数中的 this,然后执行函数,函数内部可以借助 this 给这个对象添加属性。
- 如果这个函数没有返回其他对象的话,new 操作符就会将上面步骤创建的对象返回出去。但如果该函数最后返回了一个其他对象的话,new 操作符就会把这个函数返回的对象返回出去。
例如,我们想创建一个 "人" 的对象。
function Person({name, age, height}) {
this.name = name
this.age = age
this.height = height
}
Person.prototype = {
speak() {
console.log(`我的名字叫${this.name},今年${this.age}岁了,身高是${this.height}。`)
}
}
let p = new Person({
name: 'tom',
age: 18,
height: 180
})
console.log(p) // { name: 'tom', age: 18, height: 180 }
p.speak() // 我的名字叫tom,今年18岁了,身高是180。
上面代码中的对象 p 就是 new 操作符的返回值对象,又因为 Person 函数最后没有返回其他的对象,所以 p 就是上面四个步骤中的第一个所创建的那个对象。
因为这个对象的原型链指向 Person.prototype,所以 p 能够获取并执行 speak 方法。
因为这个对象被绑定到了函数中的 this,所以 p 的值是 { name: 'tom', age: 18, height: 180 }。
下面展示 Person 函数返回其他对象的情况,看下面的代码:
function Person({name, age, height}) {
this.name = name
this.age = age
this.height = height
let otherObj = {
foo: '111',
bar: '222'
}
return otherObj
}
Person.prototype = {
speak() {
console.log(`我的名字叫${this.name},今年${this.age}岁了,身高是${this.height}。`)
}
}
let p = new Person({
name: 'tom',
age: 18,
height: 180
})
console.log(p)
p.speak()
这段代码的执行结果如下图所示:
因为 Person 函数最后返回了一个其他的对象(otherObj),所以 new 操作符将 Person 函数返回的这个对象返回出去,所以 p 指向 otherObj。
所以 console.log(p) 的结果是 { foo: '111', bar: '222' }。
又因为这个返回对象的原型链并没有指向 Person.prototype,所以 p.speak 是 undefined,因此报错:p.speak is not a function。