简单的new过程
- 新建一个对象
- 将这个对象的原型指向构造函数的原型
- 将this指向这个对象,并且调用构造函数
- 将这个新对象返回
话不多说上代码:
function myNew(fn,...arg){
let obj = {} //创建新的对象
obj.__proto__ = fn.prototype //obj原型指向构造函数原型
fn.call(obj,...arg) // 将this指向新对象,并调用构造函数
return obj//返回新对象
}
测试:
function Peson(name,age){
this.name = name
this.age = age
this.sayname = function(){
console.log(this.name)
}
}
let p1 = myNew(Person,'小王',18)
cosole.log(p1) // {"name":"小王","age":18}
对于返回值的处理
当然,如果构造函数没有返回,我们只需要返回新创建的对象即可,但是如果构造函数有返回值,且返回值为基础类型或者引用类型的情况,我们该怎么处理呢?
首先我们先看看原生new对于这些情况的处理
基础类型
function Peson(name,age){
this.name = name
this.age = age
this.sayname = function(){
console.log(this.name)
}
return 1
}
let p2 = new Peson('tom',20)
console.log(p2) //{"name":"tom","age":20}
可以看到基础类型是没有返回的(当然还有其他基础类型,也都是没有返回,包括null了,和undefined,大家可以下去自行尝试)
引用类型
function Peson(name,age){
this.name = name
this.age = age
this.sayname = function(){
console.log(this.name)
}
return {
name:'我是返回的对象',
age: 18
}
//return [1,2,3,4]
//reurn function fn(){}
}
let p2 = new Peson('tom',20)
console.log(p2)
可以看到引用类型都返回来了。
所以我们要进行边界处理,第四步需要对于返回值进行判断
完整的new过程
- 新建一个对象
- 将这个对象的原型指向构造函数的原型
- 将this指向这个对象,并且调用构造函数
-
如果构造函数有返回值,且此返回值为引用类型,则返回此值
-
如果构造函数无返回值,则将这个对象返回
function myNew(fn,...arg){
let obj = {} //创建新的对象
obj.__proto__ = fn.prototype //obj原型指向构造函数原型
let result = fn.call(obj,...arg) // 将this指向新对象,并调用构造函数
return resu instanceof Object ? result : obj //如果构造函数有返回值,且返回值为引用类型,则返回构造函数的返回值,反之返回新创建的对象
}
测试:
function Peson(name,age){
this.name = name
this.age = age
this.sayname = function(){
console.log(this.name)
}
return {
name:'我是返回的对象',
age: 18
}
// return [1,2,3,4]
// return function fn(){}
}
let p1 = myNew(Peson,'小王',18)
console.log(p1)
后续思考
思考到还有一种边界情况,箭头函数不能作为构造函数,因为箭头函数的this不能改变,如果箭头函数作为构造函数会出现报错:
let Peson = (name, age)=>{
this.name = name
this.age = age
}
let p2 = new Peson('tom',20)
console.log(p2)
而此时我们手写的new函数还是会返回一个对象
function myNew(fn,...arg){
let obj = {}
obj.__proto__ = fn.prototype
let result = fn.call(obj,...arg)
return result instanceof Object ? result : obj
}
let Peson = (name, age)=>{
this.name = name
this.age = age
}
let p1 = myNew(Peson,'小王',18)
console.log(p1)
我看到网上很少对这种情况进行考虑,所以我们还需要加一个新的判断:
因为箭头函数没有prototype属性,所以当fn.prototype为undefined时,抛出错误
let Peson = (name, age)=>{
this.name = name
this.age = age
}
function myNew(fn,...arg){
let obj = {}
if(fn.prototype === undefined){
throw new Error(fn +'is not a constructor')
} //判断是否是箭头函数
obj.__proto__ = fn.prototype
let result = fn.call(obj,...arg)
return result instanceof Object ? result : obj
}
let p1 = myNew(Peson,'小王',18)
console.log(p1)
小结
如有不对,欢迎大家指正,非常感谢