【js重学系列】new
new 运算符创建一个用户定义的对象类型的实例或具有构造函数的内置对象的实例
// ES5构造函数
let Parent = function (name, age) {
this.name = name;
this.age = age;
};
Parent.prototype.sayName = function () {
console.log(this.name);
};
const child = new Parent('听风是风', 26);
child.sayName() //'听风是风'
//ES6 class类
class Parent {
constructor(name, age) {
this.name = name;
this.age = age;
}
sayName() {
console.log(this.name);
}
};
const child = new Parent('echo', 26);
child.sayName() //echo
new操作中发生了什么
-
创建一个空对象(即{});
var obj = {};
-
设置原型链(将实例对象的原型对象,指向构造函数的原型对象)
obj.__proto__ = Foo.prototype;
-
新创建的对象作为this的上下文 ,只改this指向并且把参数传递过去,call和apply都可以
let o = Foo.call(obj);
-
如果构造函数return了一个新的“对象”,那么这个对象就会取代整个new出来的结果。如果构造函数没有return对象,那么就会返回步骤1所创建的对象,即隐式返回this 根据规范,返回 null 和 undefined 不处理,依然返回obj
return o ? o : obj
实现一个new
function newObject() {
var con = [].shift.call(arguments)
var obj = Object.create(con.prototype)
var res = con.apply(obj, arguments)
return res instanceof Object ? res : obj
}
function myNew(Fn, ...args) { // ...args为ES6展开符,也可以使用arguments
//先用Object.create创建一个空的对象,
const obj = Object.create(Fn.prototype) //fn.prototype代表 用当前对象的原型去创建
//Object.create这个方法的使用理解为什么不能直接用 const obj={},没有把原型继承上去,必须加上设置原型链
// const rel = Fn.apply(obj, args)
const res = Fn.call(obj, ...args) //后面的参数为fn的参数
//fn函数调用后,通过call来改变指向到obj,当前指向未obj,
//现在obj就代表Fn了,但是参数和this指向没有修改
//正常规定,如何fn返回的是null或undefined(也就是不返回内容),我们返回的是obj,否则返回rel
// 判断这个是因为构造函数自身可能返回null 或者undefined或者一个对象,判断是否为对象
return res instanceof Object ? res : obj
}