面向对象的语言有一个标志,就是它们都有类的概念,而通过类可以创建任意多个具有相同属性和方法的对象,而ECMAScript中没有类的概念。
ECMA-262 把对象定义为 :“无序属性的集合,其属性可以包含基本值,对象或函数。” 严格来说,这就相当于说对象是一组没有特定顺序的值。对象的每个属性或方法都有一个名字,而每个名字都映射到一个值。想象成,一组名值对,值可以是数据或函数。
创建对象:
方法一: 一次只能创建一个对象,当想创建另一个属性方法相同的对象时,会产生大量重复性的代码。
var box = new Object();
box.name = "Lee";
box.age = 100;
box.run = function () {
return this.name + this.age + "运行中...";
}
alert(box.run());
alert(this.name);
方法二:
工厂模式:解决了实例化对象产生大量重复的问题,但,存在识别问题,即,无法识别box1,box2 到底属于哪个对象的实例。
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("Qiqi", 29); // 创建第一个对象
var box2 = createObject("tianyu", 25);// 创建第二个对象
alert(box1.run()); // 打印第一个对象的run()
alert(box2.run()); // 打印第二个对象的run()
方法三:
构造函数方式 : 既解决了重复实例化的问题,又解决了对象识别的问题
function Box(name, age) { // 创建一个对象,所有构造函数的对象就是Object
this.name = name; // 添加一个属性
this.age = age;
this.run = function () { // 添加一个方法
return this.name + this.age + "运行中...";
};
}
function Desk(name, age) { // 创建一个对象,所有构造函数的对象就是Object
this.name = name; // 添加一个属性
this.age = age;
this.run = function () { // 添加一个方法
return this.name + this.age + "运行中...";
};
}
var box1 = new Box("Lee", 100); // 实例化
var box2 = new Box("Jack", 200); // 实例化
var box3 = new Desk("KKK",300); // 实例化
alert(box1.run());
alert(box2.run());
alert(box1 instanceof Box); // true;
alert(box2 instanceof Box); // true;
// 对比可知,box3 是属于 Desk 的对象的引用,而不是 Box , 解决了识别问题
alert(box3 instanceof Desk); // true;
alert(box3 instanceof Box); // false
构造函数方式与工厂模式的不同之处:
- 构造函数没有 new Object , 但它后台会自动创建,并传给一个对象 var obj = new Object();
- this 就相当于 obj
- 构造函数不需要返回对象引用,后台自动返回
构造函数规范:
- 构造函数也是函数,但函数名第一个字母大写
- 必须 new 构造函数名(), new Box(), 而这个 Box 第一个字母也是大写的
- 必须使用 new 运算符
调用构造函数实际经历的过程:
- 创建一个新对象
- 将构造函数的作用域赋给这个新对象(因此,this就指向了这个新对象)
- 执行构造函数中的代码
- 返回新对象
var o = new Object();
Box.call(o, "abc", 10);
alert(o.run());
也可以使用call()或apply() 在某个特殊对象的作用域中调用Box()函数。这里是在对象o的作用域中调用的,因此,调用后o就拥有了所有属性和run()方法
再来看一个问题:
function Box(name, age) {
this.name = name;
this.age = age;
// this.run = function () {
// return this.name + this.age + "运行中...";
// }
this.run = new Function("return this.name + this.age + '运行中...'");
}
var box1 = new Box("Lee", 100);
var box2 = new Box("Lee", 100);
alert(box1.run()); // 正常执行
alert(box1.run() == box2.run()); // true 方法的值相等
alert(box1.run == box2.run); // false 引用地址不同
以上代码可以看出,也可以使用 new Function() 的方法来代替 ,说明了 run() 是引用类型,值相等,而引用地址不等,说明值存储在堆内存中,引用地址存储在栈内存中,具有唯一性。