大部分面试的时候,面试官先已原型链铺路,随后就会问你 new 关键词都做了些什么?也是为了下一个继承问题再次铺路!
那这篇文章我们就来讲讲这个 new!
我们通常在什么地方能看到它,在创建实例的时候,new 后面加上一个构造函数,就是创建这个构造函数的实例。
首先我们创建一个构造函数,看看 new 都做了哪些事情:
1 2 3 4 5 6 7 8 9 10 11
| function Person() { this.name = "Jack"; this.age = "29"; } Person.prototype.eat = function () { console.log("烤鸭"); }; var person = new Person(); console.log(person.name); console.log(person.age); person.eat();
|
我们从上述可以看出,new 关键词主要做了以下几个事情:
- 创建了一个新的对象,
- 将新对象的__proto__函数指向构造函数的 prototype,这个新对象就可以访问构造函数原型上的属性
- 将 this 指向改变,指向新的对象,这样就可以访问构造函数内部的属性
- 返回新的对象
接下来来模拟一下 new 函数:
1 2 3 4 5 6 7
| function MyNew() { let obj = new Object(); Constructor = [].shift.call(arguments); obj.__proto__ = Constructor.prototype; Constructor.apply(obj, arguments); return obj; }
|
我们来验证一下写的这个方法是否正确:
1 2 3 4 5 6 7 8 9 10 11
| function Person() { this.name = "Jack"; this.age = "29"; } Person.prototype.eat = function () { console.log("烤鸭"); }; var person = MyNew(Person); console.log(person.name); console.log(person.age); person.eat();
|
输出结果一样,那忽然有个想法,构造函数毕竟是个函数,如果构造函数有返回值,那 new 后结果是怎样呢:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
| function Person() { this.name = "Jack"; this.age = "29"; return 1; } Person.prototype.eat = function () { console.log("烤鸭"); }; var person = new Person(); console.log(person.name); console.log(person.age); 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); console.log(person.age); console.log(person.sex); console.log(person.like); person.eat();
|
当构造函数返回的是一个基本数据类型时,跟没有返回值是一样的结果,但是当返回值是一个对象时,就会真的返回这个对象,return 之前定义的属性都会失效,并且定义在原型上的属性也会失效。根据这个特性,对之前写的 MyNew 函数进行升级。
1 2 3 4 5 6 7
| 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; }
|