这是我参与更文挑战的第16天,活动详情查看: 更文挑战
写在前面
很多时候,我们想要创建一个实例对象的时候,就会用到new
这个操作符。 但是我们很多时候并不知道它的内部具体做了什么。而且,这也是一个面试高频题,面试的时候面试官经常问能说说new
的过程中发生了什么等等。今天,就带你们一起来学学new
的过程。
例子
既然我们要知道它的内部做了什么,我们先通过几个例子来看看,通过例子来分析分析。
后退,我要开始秀代码了!!!
// 构造函数
function Dog (name) {
this.name= name
this.getName = function () {
return this.name
}
}
Dog.prototype.bark = function () {
return `汪汪`
}
// new实例
var dogA = new Dog('旺财')
console.log(typeof dogA) // 'object'
console.log(dogA.name) // '旺财'
console.log(dogA.getName()) // '旺财'
console.log(dogA.bark()) // 汪汪
从上面打印的结果我们可以看到,实例后的dogA
是一个对象,具有name
属性和getName
函数,并且继承了Dog构造函数prototype
上的bark
方法。
我们可以得出结论:
new
内部会创建一个对象- 构造函数里的
this
指向这个对象 - 继承了构造函数
prototype
上面的方法
等等,这样就结束了吗?
没有,没有,这里我们还忽略了一种情况, 上面我们的Dog
函数里没有写return
语句。所以,new
一个实例如果构造函数没有return
,则会默认返回创建的对象。
那如果有return
语句,情况还是一样的吗?
后退,我又要开始秀代码了!!!
// 构造函数
function Dog (name) {
this.name= name
return '我是构造函数Dog'
}
// new实例
var dogB = new Dog('旺财')
console.log(dogB) // Dog {name: "旺财"}
从上面打印的结果我们可以看到,虽然我在构造函数里面写了return
一个字符串,但是结果还是打印了dogB
实例
再看个例子,我又又又要秀代码了!!!
// 构造函数
function Dog (name) {
this.name= name
return {name: '我是个普通对象'}
}
// new实例
var dogC = new Dog('旺财')
console.log(dogC) // {name: '我是个普通对象'}
从上面打印的结果我们可以看到,我在构造函数里面写了return
一个新对象,结果打印了新的对象。
所以构造函数里return
什么类型的值是有区别的,如果你return
了新对象,则会返回新对象,其它情况则会返回实例对象。
总结一下过程:
new
内部会创建一个对象- 构造函数里的
this
指向这个对象 - 继承了构造函数
prototype
上面的方法 - 如果构造函数返回的是对象,返回会是这个对象,其它情况会返回实例对象
如果我们要通过代码实现这个过程,该怎么写呢?
代码实现new的过程
依照上面的过程,我们可以这样实现:
function NewFn (fn, ...args) {
const obj = Object.create(fn.prototype)
const res = fn.apply(obj, args)
return res instanceof Object ? res : obj
}
解释:
- 先通过
Object.create
创建新对象,并且把fn.prototype
赋给obj的原型上,这样就可以继承fn
的原型上的方法 - 接着执行
fn
函数,使用apply
方法把fn
的this
指向obj
- 最后根据第二步函数执行返回的
res
,判断如果res
是Object
的实例,则返回res
;否则返回obj
下面我们用上面例子验证一下:
// 构造函数
function Dog (name) {
this.name= name
this.getName = function () {
return this.name
}
}
Dog.prototype.bark = function () {
return `汪汪`
}
function NewFn (fn, ...args) {
const obj = Object.create(fn.prototype)
const res = fn.apply(obj, args)
return res instanceof Object ? res : obj
}
var dogA = NewFn(Dog, '旺财')
console.log(typeof dogA) // 'object'
console.log(dogA.name) // '旺财'
console.log(dogA.getName()) // '旺财'
console.log(dogA.bark()) // 汪汪
function Dog (name) {
this.name= name
return '我是构造函数Dog'
}
// new实例
var dogB = NewFn(Dog, '旺财')
console.log(dogB) // Dog {name: "旺财"}
// 构造函数
function Dog (name) {
this.name= name
return {name: '我是个普通对象'}
}
// new实例
var dogC = NewFn(Dog, '旺财')
console.log(dogC) // {name: '我是个普通对象'}
运行通过,完美!
总结
总结一下,new对象过程中发生了以下过程:
new
内部会创建一个对象- 构造函数里的
this
指向这个对象 - 继承了构造函数
prototype
上面的方法 - 如果构造函数返回的是对象,返回会是这个对象,其它情况会返回实例对象。
希望对你们有帮助~