一、几种比较基础的方式
- 使用 {} 创建
/**
使用{}创建对象,等同于 new Object();
**/
var o = {};
o.name = 'jack';
o.age = 20;
o.sayName = function(){
alert(this.name);
}
- Object构造函数
// 使用 new Object() 创建对象
var o = new Object();
o.name = "zhangsan";
o.sayName = function(){
alert(this.name);
}
o.sayName();
- 对象字面量
var person = {name: 'zhang', age:20}
以上几种方式的缺点:
1.代码冗余
说人话:每次创建新的实例,都要再从头到尾写一遍代码
2.方法不能共享
说人话:每创建一个实例,就要创建一个属于该实例的方法
二、工厂模式
// 使用工厂模式创建对象
// 定义一个工厂方法
function createObject(name){
var o = new Object();
o.name = name;
o.sayName = function(){
alert(this.name);
};
return o;
}
var o1 = createObject('zhang');
var o2 = createObject('li');
alert(o1.sayName===o2.sayName); //false
工厂模式的优缺点:
优点:解决了代码冗余
说人话:每次创建新的实例,只需要调用一次方法即可
缺点:1. 方法不能共享 2. 没有解决对象识别问题
说人话:还是没有解决:每创建一个实例,就要创建一个属于该实例的方法
说人话:创建对象的类型都是object,过于宽泛
三、构造函数模式
/**
* 构造函数模式创建对象
**/
function Person(name){
this.name = name;
this.sayName = function(){
alert(this.name);
};
}
注意:
- 规范:构造函数的函数名大写,和其他非构造函数区分
- 构造函数也是函数,只不过可以用来创建对象
- 任何函数,只要通过new来调用,那它就可以作为构造函数;如不用new,那么和普通函数毫无差异。
var personA = new Person('zhangsan');
调用构造函数经历了:
- 创建一个新对象(开辟了新的空间,用于存储新对象)
- 将构造函数作用域赋给新对象(this指向了这个新对象)
- 执行构造函数代码(为personA添加了name属性,并赋值)
- 返回新对象(personA)
注意:
- 实例personA的类型是Person
typeof personA == Person //true
- 实例personA有一个constructor属性,指向了Person
console.log(personA.constructor) //Person
构造函数模式的优缺点:
优点:解决了工厂模式的对象识别问题
说人话:通过new创建的实例有了具体、确定的类型,不再是模糊的object了
缺点:方法不能共享
说人话:还是没有解决:每创建一个实例,就要创建一个属于该实例的方法
四、改进的构造函数模式
function Person(name){
this.name = name;
this.sayName = sayName
}
function sayName() {
alert(this.name);
}
var person1 = new Person('zhangsan')
var person2 = new Person('lisi')
console.log(person1.sayName == person2.sayName) //true
改进构造函数模式的优缺点:
优点:解决了方法共享问题
说人话:不同实例可以共享一个sayName方法
缺点: 破坏了构造函数的封装性
说人话:sayName方法本应是Person实例专有的,但是改进构造函数中,
不但Person的实例可以调用sayName(),其他对象也可以调用。
五、总结
根据如上几种模式,我们理想的创建对象方式:属性私有,方法公用。
重要的事情说三遍:
属性私有,方法公用!
属性私有,方法公用!
属性私有,方法公用!
个人认为这句话很重要,是因为后面原型模式的出现,以及构造+原型模式组合使用,都是意在达成此目的。 把握住属性私有,方法公用的主线,就会理解原型模式的出现,以及它解决的问题。
Thanks for Reading......