要创建 Person 的新实例,必须使用 new 操作符。以这种方式调用构造函数实际上会经历以下 4个步骤:
(1) 创建一个新对象;
(2) 将构造函数的作用域赋给新对象(因此 this 就指向了这个新对象) ;
(3) 执行构造函数中的代码(为这个新对象添加属性) ;
(4) 返回新对象。
new 操作符具体就干了三件事
//1. 生成一个空对象
var obj = {};
//2. 将空对象的 __proto__ 成员指向 构造函数的 prototype (原型对象)
obj.__proto__ = Base.protype;
//3. 将构造函数的 this 指针替换成 obj
Base.call(obj);
常用的 new()
// new 的使用
// ES5构造函数
let Parent1 = function (name, age) {
this.name = name;
this.age = age;
};
Parent1.prototype.sayName = function () {
console.log(this.name);
};
const child1 = new Parent1('一晌贪欢', 25);
child1.sayName() //'一晌贪欢'
//ES6 class类
class Parent2 {
constructor(name, age) {
this.name = name;
this.age = age;
}
sayName() {
console.log(this.name);
}
};
const child2 = new Parent2('echo', 25);
child2.sayName() //echo
手动实现一个 new
// 手动实现 new
// 构造器函数
let Parent3 = function (name, age) {
this.name = name;
this.age = age;
};
Parent3.prototype.sayName = function () {
console.log(this.name);
};
//自己定义的new方法
let newMethod = function (Parent3, ...rest) {
// 1.以构造器的prototype属性为原型,创建新对象;
let child3 = {};
child3.__proto__ = Parent3.prototype;
// let child3 = Object.create(Parent.prototype);
// 2.将this和调用参数传给构造器执行
Parent3.apply(child3, rest);
// 3.返回第一步的对象
return child3;
};
//创建实例,将构造函数Parent与形参作为参数传入
const child = newMethod(Parent3, 'ldh', 26);
child.sayName() //'ldh';
//最后检验,与使用new的效果相同
child instanceof Parent3//true
child.hasOwnProperty('name')//true
child.hasOwnProperty('age')//true
child.hasOwnProperty('sayName')//false
可以将
let child3 = {};
child3.__proto__ = Parent3.prototype;
用下面这替换,结果一致
let child3 = Object.create(Parent.prototype);
结果
let myNew = function (Parent, ...rest){
let child = {};
child.__proto__ = Parent.prototype;
//验证 rest 是否是数组
// console.log(rest instanceof Array);//true
// Parent.call(child,rest);
//rest 本身是参数数组,应当使用 apply
Parent.apply(child,rest);
return child;
}
const child5 = myNew(Parent3,'jialei',66);
child5.sayName();
第一次写时,因为不熟悉 rest,用了call,输出结果打印的是整个对象,发现是call的问题,找到了rest的解释,改成apply就正确了。rest是参数数组。