new 操作符干了什么
首先说 new,new 是创建实例,常规如下:
function a(x){ this.x = x } // 实例化 let b = new a(3) // { x: 3} b.__proto__ === a.prototype // true b.__proto__ === Object.prototype // false
new 有另一种情况,函数有返回值且是对象,此时:
function a(x){ this.x = x return { x: 2 } } // 实例化 let b = new a(3) // { x: 2} b.__proto__ === a.prototype // false b.__proto__ === Object.prototype // true
很容易理解其实,正常函数实例化后,原型指向构造函数的 prototype
而有对象返回值的函数实例化后,其实就是指向了这个返回的对象,而通过字面量创建的对象,其原型指向的是Object构造函数的prototype属性,所以会出想上述情况。
================================================================================================================
再说new的执行过程,我们直接上代码
// new 一个对象的过程 function myNew() { // 1.创建一个空对象 let obj = {} // 2.取出参数中的第一个参数,获得构造函数
// 此处请理解 call 的作用,并非真正的在 [] 上执行,而是在 arguments 这个数组中执行,删除了 arguments 中的构造函数,并将此构造函数返回 let constructor = [].shift.call(arguments) // 3.连接原型,将 obj 的原型指向构造函数的 prototype obj._proto_ = constructor.prototype // 4.执行构造函数,但 this 使用的是 obj 对象的this,其实到这一步,正常情况下 obj 这个对象就已经彻底构造完毕,成为实例了
let res = constructor.apply(obj, arguments) // 5.返回新对象
// 正常来讲,直接返回 obj 即可,但上面解释了,万一这个构造函数本身就返回一个对象呢?所以作此判断。如果是,那其实上面指来指去的都白干了 return typeof res === 'object' ? res : obj } function People(name, age) { this.name = name this.age = age } function School(name) { this.name = name return { name: "学校" } } const xiaozhang = myNew(People, 'xiaozhang', 19) console.log(xiaozhang.name) // xiaozhang console.log(xiaozhang.age) // 19 const newSchool = myNew(School, '大学') console.log(newSchool.name) // 大学