1.new 是什么
new 操作符是可以创建一个用户定义的对象的实例或具有构造函数的内置对象的实例
function Car (make, model, year) {
this.make = make
this.model = model
this.year = year
}
Car.prototype.running = function () {
return `${this.year} 年 ${this.make} 公司造的 ${this.model} 牌汽车,开动起来`
}
const car = new Car('长城', '坦克300', '2022')
console.log(car)
打印出的Car实例
从上图可以看到,实例里面有以下内容:
- 三个属性:make,model,year并且已经赋值
- 原型上有一个running方法和一个构造器函数Car
思考一下,如果构造函数返回了一个新对象或者返回其它基本类型的数据,结果还一样吗?
修改上面的例子
function Car (make, model, year) {
this.make = make
this.model = model
this.year = year
return {
info: `${this.year} 年 ${this.make} 公司造的 ${this.model}`
}
}
Car.prototype.running = function () {
return `${this.year} 年 ${this.make} 公司造的 ${this.model} 牌汽车,开动起来`
}
const car = new Car('长城', '坦克300', '2022')
console.log(car)
打印出的Car实例
从上图中可以看出:
- 实例是个普通的Object对象,这个对象就是执行构造函数return时的结果
- 实例的原型是Object
继续修改上面的例子,使其构造函数返回一个基本类型的数据
function Car (make, model, year) {
this.make = make
this.model = model
this.year = year
return '测试'
}
Car.prototype.running = function () {
return `${this.year} 年 ${this.make} 公司造的 ${this.model} 牌汽车,开动起来`
}
const car = new Car('长城', '坦克300', '2022')
console.log(car)
打印出的Car实例
从上图中可以看出和没有写return是一样的,返回的都是新创新的Car实例
2.执行new会发生什么
根据上面的例子内容,可以总结出使用new会进行如下的操作:
- 创建一个空的简单js对象(即{})
- 为步骤1新创建的对象上面添加属性proto,并将该属性链接至构造函数的原型对象
- 将步骤1创建的对象作为this的上下文
- 如果函数没有返回对象,则返回this
3.实现new
知道了new的执行过程,手写一个new,就变得很容易了
方法一
function newApply (construct, ...rest) {
// 步骤一 创建一个空对象
const newObj = {}
// 步骤二 新创建的对象上面添加属性 __proto__, 并将该属性链接至构造函数的原型对象
newObj.__proto__ = construct.prototype
// 步骤三 新创建的对象作为 this 的上下文
const result = construct.apply(newObj, rest)
// 步骤四 如果执行结果有返回值并且是一个对象,就返回执行的结果,否者返回 this 也就是新创建的对象 newObj
return typeof result === 'object' ? result : newObj
}
方法二
function newCall (construct, ...rest) {
// 步骤一 基于 construct 的原型创建一个新的对象
const newObj = Object.create(construct.prototype)
// 步骤二 新创建的对象作为 this 的上下文
const result = construct.call(newObj, ...rest)
// 步骤三 如果执行结果有返回值并且是一个对象,就返回执行的结果,否者返回 this 也就是新创建的对象 newObj
return typeof result === 'object' ? result : newObj
}
测试方法一
const car = new Car('长城', '坦克300', '2022')
console.log('car', car)
const newApplyCar = newApply(Car, '长城', '坦克300', '2022')
console.log('newApplyCar', newApplyCar)
测试方法二
const car = new Car('长城', '坦克300', '2022')
console.log('car', car)
const newApplyCar = newCall(Car, '长城', '坦克300', '2022')
console.log('newApplyCar', newApplyCar)