大部分面试的时候,面试官先已原型链铺路,随后就会问你 new 关键词都做了些什么?也是为了下一个继承问题再次铺路! 那这篇文章我们就来讲讲这个 new! 我们通常在什么地方能看到它,在创建实例的时候,new 后面加上一个构造函数,就是创建这个构造函数的实例。
首先我们创建一个构造函数,看看new都做了哪些事情:
function Person() {
this.name = 'Jack';
this.age = '29';
}
Person.prototype.eat = function() {
console.log('烤鸭');
}
var person = new Person();
console.log(person.name); //Jack
console.log(person.age); // 29
person.eat(); // 烤鸭
我们从上述可以看出,new关键词主要做了以下几个事情:
- 创建了一个新的对象,
- 将新对象的__proto__函数指向构造函数的prototype,这个新对象就可以访问构造函数原型上的属性
- 将this指向改变,指向新的对象,这样就可以访问构造函数内部的属性
- 返回新的对象
接下来来模拟一下new函数:
function MyNew() {
let obj = new Object();
Constructor = [].shift.call(arguments);
obj.__proto__ = Constructor.prototype;
Constructor.apply(obj, arguments);
return obj;
}
我们来验证一下写的这个方法是否正确:
function Person() {
this.name = 'Jack';
this.age = '29';
}
Person.prototype.eat = function() {
console.log('烤鸭');
}
var person = MyNew(Person);
console.log(person.name); //Jack
console.log(person.age); // 29
person.eat(); // 烤鸭
输出结果一样,那忽然有个想法,构造函数毕竟是个函数,如果构造函数有返回值,那new后结果是怎样呢:
// 返回基本数据类型
function Person() {
this.name = 'Jack';
this.age = '29';
return 1;
}
Person.prototype.eat = function() {
console.log('烤鸭');
}
var person = new Person();
console.log(person.name); //Jack
console.log(person.age); // 29
person.eat(); // 烤鸭
// 返回对象
function Person() {
this.name = 'Jack';
this.age = '29';
return {
sex: 'nan',
like: 'nv'
};
}
Person.prototype.eat = function() {
console.log('烤鸭');
}
var person = new Person();
console.log(person.name); //undefined
console.log(person.age); // undefined
console.log(person.sex); //Jack
console.log(person.like); // 29
person.eat(); // Uncaught TypeError: person.eat is not a function
当构造函数返回的是一个基本数据类型时,跟没有返回值是一样的结果,但是当返回值是一个对象时,就会真的返回这个对象,return之前定义的属性都会失效,并且定义在原型上的属性也会失效。根据这个特性,对之前写的MyNew函数进行升级。
function MyNew() {
let obj = new Object();
Constructor = [].shift.call(arguments);
obj.__proto__ = Constructor.prototype;
let res = Constructor.apply(obj, arguments);
return typeof res === 'object' ? res : obj;
}