通过new关键字创建一个对象,并赋予属性和方法。
var obj = new Object();
obj.name='wrx';
obj.age=20;
obj.show=function(){
return "Name:"+this.name+" Age:"+this.age;
}; //注意分号哦!
alert(obj.run()); //Name:wrx Age:20
show()方法里的this就是代表obj这个对象,这种方法是创建对象最基本的方法,但是如果想要创建一个类似的对象,还是需要写多一次相同的代码,从而产生了大量的代码。
一、工厂模式
为了解决以上这一问题,我们可以通过工厂模式的方式创建对象。
function createObject(name, age) { //集中实例化的函数
var obj = new Object();
obj.name= name;
obj.age= age;
obj.show= function () {
return "Name:"+this.name+" Age:"+this.age;
}; //注意分号哦!
return obj;
}
var box1 = createObject(wrx', 20); //第一个实例
var box2 = createObject('hx', 21); //第二个实例
alert(box1.show()); //Name:wrx Age:20
alert(box2.show()); //Name:wrx Age:21
工厂模式解决了重复实例化对象的问题,但是还有一个问题,就是识别问题。
alert(typeof box1); //Object
alert(box1 instanceof Object); //true
alert(typeof box2); //Object
alert(box2 instanceof Object); //true
可以看出,根本无法分辨出box1和box2是哪一个具体的对象
二、构造函数
ECMAScript 中可以采用构造函数创建特定的对象,使用构造函数即解决了重复实例化的问题,又解决了对象识别的问题。
function Box(name, age) { //构造函数模式
this.name= name;
this.age= age;
this.run= function () {
returnthis.name + this.age + '运行中...';
};
}
var box1 = new Box('Lee', 100);
var box2 = new Box('Jack', 200);
alert(box1.run());
alert(box1 instanceof Box); //很清晰的识别他从属于Box
可以看出,虽然没有new Object(),但却可以实例化Box(),这是因为后台会自动 var obj = new Object(); 而且构造函数中的this就是相当于当前作用域的obj。另外,构造函数也
不需要返回对象引用, 这同样是因为强大的后台为它自动返回了。
构造函数也有一些规范:1.函数名第一个字母大写; 2.必须new 构造函数名(),即 new Box()
构造函数和普通函数的唯一区别在于他们调用的方式不同,其实构造函数也是函数,只不过必须用new运算符来调用,否则就是普通函数了。
三、深入探索构造函数
首先看下两个实例化后的属性或方法是否相等:
var box1 = new Box('Lee', 100);
var box2 = new Box('Lee', 100);
alert(box1.name == box2.name); //true,属性的值相等
alert(box1.run == box2.run); //false,方法其实也是一种引用地址
alert(box1.run() == box2.run()); //true,方法的值相等,因为传参一致
把构造函数里的方法(或函数)用new Function()方法来代替,得到一样的效果,更加证明,他们最终判断的是引用地址,唯一性。
function Box(name, age) { //new Function()唯一性
this.name= name;
this.age= age;
this.run= new Function("return this.name + this.age + '运行中...'");
}
可以看出,每次实例化一个对象,对象的方法都会使用一个新的地址,这样会造成内存空间的浪费。我们可以通过构造函数外面绑定同一个函数的方法来保证引用地址的一致
性,但这种做法没什么必要。因为这种方式又带来了一个新的问题,全局中的this在对象调用的时候是Box本身,而当作普通函数调用的时候,this又代表window。
function Box(name, age) {
this.name= name;
this.age= age;
this.run= run;
}
function run() { //通过外面调用,保证引用地址一致
returnthis.name + this.age + '运行中...';
}
四、原型我们创建的每个函数都有一个prototype(原型)属性,这个属性其实是一个对象,它的用途是包含可以由特定类型的所有实例共享的属性和方法。使用原型的好处可以让所有
对象实例共享它所包含的属性和方法。也就是说,不必再构造函数中定义对象信息,而是可以直接将这些信息添加到原型中。
注:box1.prototype是不可行的,因为prototype其实是一个对象。
function Box() {} //声明一个构造函数
Box.prototype.name ='Lee'; //在原型里添加属性
Box.prototype.age =100;
Box.prototype.run =function () { //在原型里添加方法
return this.name + this.age + '运行中...';
};
比较一下原型内的方法地址是否一致:
var box1 = new Box();
var box2 = new Box();
alert(box1.run == box2.run); //true,方法的引用地址保持一致,因为方法是共享的
判断一个对象是否指向了该构造函数的原型对象,可以使用isPrototypeOf()方法来测试。
alert(Box.prototype.isPrototypeOf(box) ; //只要实例化对象,即都会指向
var obj = new Object();alert(Box.prototype.isPrototypeOf(obj)); //false,因为obj是通过new Object()创建的,没有指向Box()构造函数
五、深入探索原型
在原型模式声明中,多了两个属性,这两个属性都是创建对象时自动生成的。
__proto__属性是实例指向原型对象的一个指针,它的作用就是指向构造函数的原型属性constructor。通过这两个属性,就可以访问到原型里的属性和方法了。
IE浏览器在脚本访问__proto__会不能识别,火狐和谷歌浏览器及其他某些浏览器均能识别。虽然可以输出,但无法获取内部信息。
alert(box1.__proto__); //[objectObject]
alert(box1.prototype); //undefined 这个属性是一个对象,访问不到
alert(box1.constructor); //构造属性,可以获取构造函数本身,即function Box() { }
原型模式的执行流程:
1.先查找构造函数实例里的属性或方法,如果有,立刻返回;
2.如果构造函数实例里没有,则去它的原型对象里找,如果有,就返回;
function Box() {} //声明一个构造函数
Box.prototype.name ='Lee'; //在原型里添加属性
Box.prototype.age =100;
Box.prototype.run =function () { //在原型里添加方法
return this.name + this.age + '运行中...';
};
var box1 = new Box();
alert(box1.name); //Lee,原型里的值
box1.name = 'Jack';
alert(box.1name); //Jack,就近原则,
var box2 = new Box();
alert(box2.name); //Lee,原型里的值,没有被box1修改
delete box1.name; //删除实例中的属性
delete Box.prototype.name; //删除原型中的属性
Box.prototype.name = 'KK'; //覆盖原型中的属性
六、判断一个属性是实例属性还是原型属性
in操作符会在通过对象能够访问给定属性时返回true,无论该属性存在于实例中还是原型中。
alert('name' in box); //true,存在实例中或原型中
如何判断属性是在构造函数的实例里,还是在原型里?可以使用hasOwnProperty()函数来验证:
alert(box.hasOwnProperty('name')); //实例里有返回true,否则返回false
如果原型里有,但实例里没有,也会返回false
我们可以通过hasOwnProperty()方法检测属性是否存在实例中,也可以通过in来判断实例或原型中是否存在属性。那么结合这两种方法,可以判断原型中是否存在属性。
function isProperty(object, property) { //判断原型中是否存在属性
return!object.hasOwnProperty(property) && (property in object);
}
var box = new Box();
alert(isProperty(box, 'name')) //true,如果原型有