new关键字的神奇之处
- 首先构造函数就是一个函数,可以执行,默认函数的返回值为undefined
- 同时可以通过
new
关键字来创建实例对象,对于函数的构造调用(此时把构造函数看作生产同一类对象的加工厂)
实际上并不存在所谓的“构造函数”,只有对于函数的“构造调用”
function People(name, age) {
this.name = name;
this.age = age;
this.show = function() {
console.log(this.name);
}
}
console.log(People('孙悟空', 20)); //undefined
let p = new People('孙悟空', 20);//通过new关键字构造调用创建实例对象
console.log(p);//People{...}
new关键字功能
- 创建一个实例对象(相当于在内存中注册了一个空间)
- 将创建的新对象的
__proto__
属性指向构造函数的prototype
原型对象(原型链继承的关键)
console.log(p.__proto__ === People.prototype); //true
最简单的原型链
obj.__proto__
=> Object.prototype
Object.prototype.__proto__
=> null
let obj = new Object();
console.log(obj.__proto__ === Object.prototype); //true
console.log(Object.prototype.__proto__); //null
-
将新对象作设置为构造函数的调用(意味着
this
关键字指向该新对象) -
执行构造函数中的代码(初始化新对象的属性和方法)
-
返回新对象
let p = new Object();//创建新对象
p.__proto__ === People.prototype;//实例对象原型指向构造函数的原型对象
People.call(p,'孙悟空',20);//使构造函数中的this指向实例对象p
return p;//返回实例对象
手写new
function People(name, age) {
this.name = name;
this.age = age;
return {
sex: 'xxx',
}
}
function _new(constructor, ...argus) {
if (typeof constructor != 'function') {
return;
}
//1.创建一个新对象
let obj = {};
//2.新对象的原型指向构造函数的原型对象
obj.__proto__ = constructor.prototype;
//3.改变this指向,用新对象来调用构造函数(为新对象配置属性和方法)
let result = constructor.apply(obj, argus);
//4.返回该对象
// return obj;
//如果构造函数返回对象,则返回构造函数返回的对象
return typeof result === 'object' ? result : obj;
}
注意当构造函数有返回对象的时候,最终new出来的对象会使用构造函数返回的对象,而不是new过程中创建的对象,当构造函数返回的不是对象的时候,就会返回new出来的对象(也就是说使用new关键字最终都会返回一个对象)
注意:防止忘记new,通过判断条件控制使用new操作符构造调用
function Person(name) {
//如果不是Person的实例,说明没有使用new操作符
if (!(this instanceof Person)) {
return new Person(name);
}
this.name = name;
this.say = function () {
return 'hello';
};
}
let p1 = Person('孙悟空');
let p2 = new Person('猪八戒');
//两者都会是People的实例
console.log(p1);
console.log(p2);