new是怎么实现的?
我们经常听说‘你new一个对象呀’,为什么new就能出来一个对象?带着下面三个疑问我仔细研究了很久,终于搞懂了。你们也跟我一起来看看吧。
- 为什么我们要new一个对象?
- new的过程到底做了什么?
- 怎样实现一个自己的new?
1. 为什么我们经常说new一个对象?
总所周知,对象创建常用的两种方式:
1.对象直接量
var person = {};
person.name = '小明';
person.say = 'hello world';
这时我们创建了一个‘小明’,但如果这时候需要再创建N个小明、小红等这些人呢?再写这么多相似的代码似乎有些繁琐,能不能有个解决方法让我们可以少写一些冗余的代码也能拥有这些属性和方法?那接下来我们了解一下构造函数
。
2.构造函数
先看下面这段代码:
let Person = function(name) {
this.name = name;
this.say = function() {
console.log(this.name +'hello world');
}
};
var xiaoMing = new Person('小明');
xiaoMing.name // 小明
xiaoMing.say(); // 小明hello world
xiaoMing.__proto__ === Person.prototype // true
可见构造函数的原型指向了’小明’的__proto__
属性,也就是’小明’完全继承了构造函数原型的属性和方法,即改变了this的指向;那么,这时我们会思考一个问题,为什么new了一下,他的this指向就变了,中间的过程发生了什么?
2. new的过程到底做了什么?
下面我们重新看这段代码:
let Person = function(name) {
this.name = name;
this.say = function() {
console.log(this.name +'hello world');
}
};
刚开始我很不理解,为啥直接在函数内部就this.name=name
了,这个this
哪里来的,到底指向哪里?于是我在函数内部打印了一下this,直接调用时this指向window
,但当我用new创建实例时this指向了一个新对象,并继承了构造函数的属性和功能,像下面这样:
let Person = function(name) {
this.name = name;
this.say = function() {
console.log(this.name + 'hello world');
}
console.log(this); // >Person {name: '小明', say: ƒ}
return this; // 注意这里加了return this
};
var xiaoMing = new Person('小明');
所以,这里我们能知道在new的过程中,在构造函数内部创建了一个空的对象,相当于var this = {}
,把这个空对象的引用地址给了this,然后我们对他以对象的形式操作(增加属性和方法等),并且这个对象同时还继承了构造函数的属性和方法,伪代码相当于{}.__proto__ === Person.prototype
, 也可以这样说var {} = Object.create(Person.prototype)
,把构造函数的原型指向了this引用的空对象,也改变了构造函数内部this的指向,最后返回this指向的新对象,相当于return this
,这里隐性省略了;
那么,这里有个问题,构造函数只能返回this吗,能不能返回其他的数据,下面我们用that
代替this来测试一下:
- that替代this
let Person = function(name) {
let that = {};
that.name = name;
that.say = function() {
console.log(that.name + 'hello world');
}
return that;
};
var xiaoMing = new Person('小明');
xiaoMing // > {name: '小明', say: ƒ}
可见,‘小明’同样继承了自定义构造函数的原型,继承了其方法和属性;