老哥:小薛,昨天给你留的作业研究好了吗?
小薛:研究好了老哥!
老哥:那你说一下 new 的过程呗。
小薛:我们new的过程其实会分为这么几步
1、首先会在堆内存里面开辟一块空间,创建一个新的空对象
2、然后将这个空对象的 __proto__ 属性指向 构造函数的原型对象
3、再改变构造函数内部的this指向,将他指向我们创建的空对象
4、然后返回创建的对象
老哥:不错呦,但是不是很全,你可以js模拟一个new嘛?
小薛:没问题!
function myNew(Fn,...args){
// 创建一个空对象
let obj = {}
// 将对象的__proto__指向构造函数的原型对象
// obj.__proto__ = Fn.prototype;
Object.setPrototypeOf(obj, Fn.prototype);
// 改变构造函数的this指向,并调用
// 因为call会直接调用函数并改变函数内部的this指向,所以调用的时候,
// 函数内部的this指向的是obj,就等同于在obj上面挂载了属性(也可以通过apply)
Fn.call(obj,...args)
// 返回这个对象
return obj
}
function Sub(name,age){
this.name = name
this.age = age
}
Sub.prototype.say = function(){
console.log('say')
}
let newObj = myNew(Sub,'小薛','18')
console.log(newObj) // {"name": "小薛", "age": "18"} newObj.prototype 上也有了say方法
老哥:很不错吗,这么快就写完了,那我出一个问题给你,你觉得new 这个函数,它返回的是什么
function Sub(name,age){
this.name = name
this.age = age
return {
name: '薛大',
age: '25'
}
}
Sub.prototype.say = function(){
console.log('say')
}
let newObj = new Sub('小薛','18')
console.log(newObj) // {"name": "薛大","age": "25"}
小薛:这个应该返回的还是
// {"name": "小薛", "age": "18"}
老哥:不是哦,你可以去试一下,如果你的构造函数有返回值,并返回值是一个对象,在new的时候他是会返回你构造函数里面return的对象,但是这里要注意一下哦! 如果return的是一个原始类型的值,那new的时候return值就不会起作用哦!
function Sub(name,age){
this.name = name
this.age = age
return 1
}
Sub.prototype.say = function(){
console.log('say')
}
let newObj = new Sub('小薛','18')
console.log(newObj) // {"name": "小薛", "age": "18"}
小薛马上去尝试了一下
老哥:你看你自己手写的new,如果构造函数有返回值,是不是就会有问题呀?
小薛:是的,我马上改一下
function myNew(Fn,...args){
if(typeof Fn !== 'function'){
console.error('type error')
return
}
// 创建一个空对象
let obj = {}
// 将对象的__proto__指向构造函数的原型对象
// obj.__proto__ = Fn.prototype;
Object.setPrototypeOf(obj, Fn.prototype);
// 改变构造函数的this指向,并调用
let res = Fn.call(obj,...args)
let flag = res && (typeof result === 'object' || typeof result === 'function')
// 返回这个对象
return flag ? res : obj
}
老哥:哈哈哈,很不错哦,那你现在可以总结一下嘛
小薛:当然可以呀
1、首先判断传进来的构造函数是否是一个函数,如果不是直接返回
2、在堆内存里面开辟一块空间,创建一个新的空对象
3、然后将这个空对象的 __proto__ 属性指向 构造函数的原型对象
4、再改变构造函数内部的this指向,将他指向我们创建的空对象,并获取返回值
5、判断返回值是否是一个对象或者是一个函数
6、如果是就返回返回值,如果不是就返回创建的对象
老哥:哈哈哈,小薛挺不错呀,明天考考你js的继承,要做好准备哦。看你在代码里面用到了类型判断,你也可以去总结一下js中有哪些常用的类型判断的方法哦!
小薛:没问题老哥。