前面的话
new运算符的原理也是重点之一,这篇文章介绍new运算符。
定义
new 运算符创建一个用户定义的对象类型的实例或具有构造函数的内置对象的实例。
看一个例子:
function Person (name) {
this.name = name;
}
Person.prototype.getName = function () {
console.log( 'hello '+ this.name );
}
var person = new Person('wan');
person.name;// 访问构造函数里的属性
// wan
person.getName();// 访问原型里的属性
// hello wan
可以看到new创建的实例有以下两个特性:
- 访问构造函数里的属性
- 访问到原型里的属性
模拟实现
下面来模拟实现 调用new的过程,细分为下面几个过程:
- 新生成了一个对象
- 获得构造函数
- 链接到原型
- 绑定 this,执行构造函数
- 返回新对象
function create() {
// 创建一个空对象
let obj = new Object();
// 获得构造函数, arguments中去除第一个参数(第一个参数为构造函数)
let Con = [].shift.call(arguments);
// 链接到原型
obj.__proto__ = Con.prototype;
// 绑定this,执行构造函数
let result = Con.apply(obj, arguments);
// 优先返回构造函数返回的对象
return typeof result === 'object' ? result : obj;
}
测试一下:
var person1 = create(Person, 'li');
person1.getName();// hello li
可以看到使用create函数创建的实例对象与new创建的实例对象功能一样。
这里注意的是,new 运算符优先返回的对象不是创建的空对象,而是构造函数返回的对象。
function Person2 (name, age) {
this.name = name;
return {
age : age
}
}
var person2 = new Person2('wan', 20);
console.log(person2.name);// undefined
console.log(person2.age);// 20
发现实例对象person2只能访问return语句返回的对象属性
所以在create函数的最后一步要检查构造函数返回的是否为一个对象,如果是则优先返回这个对象,否则返回创建的新对象
优先级
new运算符还要注意运算符优先级
function Foo() {
return this;
}
Foo.getName = function () {
console.log('1');
}
Foo.prototype.getName = function () {
console.log('2');
}
new Foo.getName();// 1
new Foo().getName(); // 2
new Foo()的优先级大于new Foo,上面的运算可以看做:
new ( Foo.getName());
(new Foo()).getName();
对于第一个函数来说,先执行了 Foo.getName() ,所以结果为 1;
对于后者来说,先执行 new Foo() 产生了一个实例,然后通过原型链找到了 Foo 上的 getName 函数,所以结果为 2