前面提过, JavaScript 中的构造器是通过 new 操作符调用,在 3.3 中的Person构造函数,当我们执行var person1 = new Person()是,到底发生了什么?
MDN 上是这么说的, 对于var o = new Foo();
//JavaScript 实际上执行的是:
var o = new Object();
o.[[Prototype]] = Foo.prototype;
Foo.call(o);
我们按照MDN上面的过程来理解下var person1 = new Person()的执行过程
var obj = new Object(); // 创建一个空对象 obj
obj.[[Prototype]] = Person.prototype; // obj 空对象的原型指向构造器 Person 的原型对象
Person.call(obj); // Person 构造器中的 this 指向对象 obj
var person1 = obj; // 把这个 obj 赋给 person1, 完成 var person1 = new Person() 的过程.
五、new 操作符的缺点
但是 new 操作符有个很严重的缺点:构造器内部的属性和方法无法被共享。 👍
function Person(name){
this.name = name;
this.group = 'China'; // 我要将 group 作为实例对象的共有属性
this.getGroup = function() {
console.log('method: ', this.group);
}
}
// 生成两个实例对象
var p1 = new Person('p1');
var p2 = new Person('p2');
// 两个实例对象的 group 属性都是独立的,修改其中一个不会影响另外一个
p1.group = 'US';
p1.getGroup = function() {
console.log('change the method in p1: ', 'US, But is not China');
}
console.log('change the property in p1: ', p1.group);
console.log(p1.getGroup());
console.log('property:', p2.group);
console.log(p2.getGroup());
在上面的代码中,p1 和 p2 对象的 group 属性和 getGroup 方法都是独立的,修改其中一个不会影响另外一个,因此每一个实例对象都会拥有其构造器内部的属性和方法的副本。这无法做到数据共享,也是占用内存极大的浪费资源。
一、构造函数
在以类为中心的面向对象编程语言中,类和对象的关系可以想象成铸模和铸件的关系,对象总是从类中创建而来。构造函数(
constructor function
)是类的一个成员方法,用于在类的实例化时初始化对象的。不过在
JavaScript
里并没有“类”(class
)的概念(ES5之后加入了class
关键词),虽然没有‘类’来创建对象,但是对象仍然可以通过多种方式创建,其中就有构造器方式,也可以称为构造函数,其表现形式就是函数。因此我们也可以这么去理解
JavaScript
中的构造器:构造器就是一个函数,用于创建对象,通过new
操作符调用。二、书写规则及调用方式
JavaScript
构造器的书写规则和调用方式new
操作符来调用,那它就可以作为构造器, 如果不通过new
操作符来调用,那它跟普通函数没有什么区别。我们来看个Case
上面的代码,当构造函数作为普通函数使用时,我们可以发现一些坑, 构造函数与一个普通函数并无不同,如果你故意不使用
new
,或忘记用new
,都会得到怪异的错误:person2
并不是Person
的实例, 其值为undefined
this
指向window
,this
下的变量和属性变为全局变量和属性。new
调用Person
构造函数会出现错误。三、构造器的返回值
JavaScript
构造器就是一个函数,函数都是有返回值的!。3.1、默认返回实例化对象
JavaScript
构造器与类式面向对象语言中的构造函数一样,默认是不需要显式return
语句的,默认返回实例化的对象。这是JavaScript
构造器的推荐写法。3.2、返回值为基本数据类型
如果存在显式
return
语句,则检查其返回值是否为引用类型,如果为非引用类型,如string
,number
,boolean
,null
,undefined
,则与3.1
一样,实际返回实例化的对象,显式return
无效3.3、返回值是引用类型
如果存在显式
return
语句,则检查其返回值是否为引用类型,如果是引用类型则返回引用类型,这种情况下,建议不要把这个函数当作构造器使用四、new 操作符到底都干了啥?
前面提过,
JavaScript
中的构造器是通过new
操作符调用,在3.3
中的Person
构造函数,当我们执行var person1 = new Person()
是,到底发生了什么?MDN
上是这么说的, 对于var o = new Foo()
;我们按照
MDN
上面的过程来理解下var person1 = new Person()
的执行过程五、new 操作符的缺点
但是
new
操作符有个很严重的缺点:构造器内部的属性和方法无法被共享。 👍在上面的代码中,
p1
和p2
对象的group
属性和getGroup
方法都是独立的,修改其中一个不会影响另外一个,因此每一个实例对象都会拥有其构造器内部的属性和方法的副本。这无法做到数据共享,也是占用内存极大的浪费资源。六、内置构造器
JavaScript
有九种内置的构造器:Object()
,Function()
,Array()
,Number()
,String()
,Boolean()
,RegExp()
,Date()
,Error()
,当我们需要创建这些值的时候,我们可以自由选择使用字面量或者构造器。但是相同情况下,字面量对象不仅易读,而且运行速度更快,因为他们可以在解析的时候被优化。所以当你需要使用简单对象的时候就使用字面量吧。Reference