一、简介
什么是对象,其实就是一种类型,即引用类型。在JavaScript层面更简单的说就是一个存放属性的容器。
而对象的值就是引用类型的实例。
在ECMAScript中引用类型是一种数据结构,用于将数据和功能组织在一起。
它也常被称做为类,但ECMAScript中却没有这种东西。虽然ECMAScript是一门面向对象的语言,却不具备传统面向对象语言所支持的类和接口等基 结构。
二、创建一个Object对象
var box = new Object(); //创建对象
box.name = '李炎恢'; //给属性赋值
box.age = 28;
方式二:
var box = {};//创建对象
box.name = '李炎恢';//给属性赋值
box.age = 28;
方式三:
var box = {
name : '李炎恢',
age : 28
};
其它:删除对象的属性
delete box.name;//删除对象的属性
三、创建多个对象的模式
当在工程中创建多个相同类型的对象时不可能每次都用new或字面量方式去一个一个的创建对象添加属性,这时就需要更简单的方法去创建多个相同的对象。这个方法就是一种模式。
1、工厂模式
function createObject(name, age) {
//集中实例化的函数
var obj = new Object();
obj.name = name;
obj.age = age;
obj.run = function () {
return this.name + this.age + '运行中...';
};
return obj;
}
var box1 = createObject('Lee', 100);
var box2 = createObject('Jack', 200);
优点:工厂模式可以避免创建对象产生大量的重复代码。
缺点:1.每个对象内部的方法作用相同,但不是同一个方法。创建一个对象就会新增一个相同功能的方法。2.识别问题,所有创建出来的对象都是Object类型。
2、构造函数
function Box(name, age) {
//构造函数模式
this.name = name;
this.age = age;
this.run = function () {
return this.name + this.age + '运行中...';
};
}
var box1 = new Box('Lee', 100); //new Box()即可
var box2 = new Box('Jack', 200);
3、原型模式
方法一:
//给原型对象增加属性
function Box() {}
Box.prototype.name = 'Lee';
Box.prototype.age = 100;
Box.prototype.run = function () {
return this.name + this.age + '运行中...';
};
方法二:
function Box() {};
//直接将一个对象赋值给原型对象
Box.prototype = {
constructor : Box,//指定原型对象的构造属性
name : 'Lee',
age : 100,
run : function () {
return this.name + this.age + '运行中...';
}
};
4、组合模式:构造+原型
function Box(name, age) {
//不共享的使用构造函数
this.name = name;
this.age = age;
this. family = ['哥哥', '姐姐', '弟弟'];
};
Box.prototype = {
constructor : Box,
//共享的使用原型模式
run : function () {
return this.name + this.age + this.family;
}
};
另一种写法:
function Box(name ,age) {
//将所有信息封装到函数体内
this.name = name;
this.age = age;
this.family = ['哥哥','姐姐','弟弟'];
if (typeof this.run != 'function') {
//仅在第一次调用的初始化
Box.prototype.run = function () {
return this.name + this.age + '运行中...';
};
}
}
PS:原型模式
一、原型模式介绍:
1、每个类型都有一个prototype(原型)属性,这个属性是类型的原型对象,它的用途是让所有实例共享属性和方法。
也就是说不必在构造函数中定义对象信息,而是可以直接将这些信息添加到原型中。 (当你通过原型模式创建一个对象时将会开辟一个空间,对象的属性需要有个初始值,这个初始值是从原型对象那里得到的,也就是值传递。所以可以理解为原型对象只是一个存储共享信息的对象。)
获取原型对象:
box.__proto__;//通过实例对象获取原型对象,不是所有浏览器都支持
Box.prototype;//通过类名获取原型对象
2、每个类型的
原型对象都有一个constructor(构造)属性,这个属性是对象的构造方法。
系统默认:(通过new Object();或{}方式创建的对象的构造属性对应的构造方法)
function Object() {
[native code]
}
构造函数创建对象:(通过构造函数创建的对象的构造属性对应的构造方法)
function Box(age,text){
this.age = age;
this.text = text;
this.run = function(){
return this.age + this.text;
};
}
3、重写对象的原型对象。
Box.prototype = {
constructor : Box,
name : 'Lee',
age : 100,
run : function () {
return this.name + this.age + '运行中...';
}
};
此代码中是新创建一个对象,给Box的原型对象赋值。
此代码中的属性constructor就是将新建对象的构造属性指向Box。不设置的话默认是Object。4、原型对象不仅可以在自定义对象的情况下使用,ECMAScript内置的引用类型都可以使用这种方式。
alert(Array.prototype.sort); //Array类型的原型方法
alert(String.prototype.substring);//String类型的原型方法
String.prototype.addstring = function () {
return this + ',被添加了!';//类型添加一个方法
};
alert('Lee'.addstring());//使用这个方法
PS:尽管给原生的内置引用类型添加方法使用起来特别方便,但不推荐使用这种方法。因为它可能会导致命名冲突,不利于代码维护。
原型模式的执行流程:1.先查找构造函数实例里的属性或方法,如果有,立刻返回;2.如果构造函数实例里没有,则去它的原型对象里找,如果有,就返回;
hasOwnProperty()函数来验证实例里是否有某个属性。
in操作符判断是否有某个属性,无论该属性存在于实例中还是原型中。
通过以上两个方法可以准确判断出属性存在实例还是原型里。
function isProperty(object, property) {
//判断原型中是否存在属性
return !object.hasOwnProperty(property) && (property in object);
}
二、原型模式的缺点
1、原型模式无法传递参数。
2、当原型对象中的属性A为引用类型时,改变其中一个实例对象的A属性,所有的实例对象的属性都会发生改变。
举例:
function Box(){}
Box.prototype = {
name : 'lee',
age :100,
family : ['哥哥','姐姐','弟弟'],//引用类型,放在原型对象中共享会出现问题
run : function(){
return this.name + this.age + '运行中...'
}
};
var box1 = new Box();
var box2 = new Box();
alert(box1.family);//哥哥,姐姐,弟弟
alert(box2.family);//哥哥,姐姐,弟弟
box1.family.push('妹妹');//改变实例对象box1的family属性。
alert(box1.family);//哥哥,姐姐,弟弟,妹妹
alert(box2.family);//哥哥,姐姐,弟弟,妹妹 box2的family属性也发生改变
产生上述现象的原因是实例对象从原型对象那里得到初始信息,基本类型得到的是一个值,引用类型得到的是一个地址。所有的实例对象得到的地址都是一样的,当改变了其中一个实例对象的family属性,就相当于改变了这个地址引用的那个family对象的内容,所以所有的实例对象的family属性发生改变,而基本类型就不存在这种问题。
如果代码改写成如下就不会出现这种问题。
box1.family = ['哥哥','姐姐','弟弟','妹妹'];