ECMAScript有两种开发模式:1、函数化;2、面向对象(OOP),
面向对象有一个标志,即“类”,通过类可以创建任意多个具有相同属性和方法的对象。
但是,ECMASctipt没有类的概念,因此它的对象也与基于类的对象有所不同。
1、创建对象
案例1-1——对象的使用以及this关键字:
var box=new Object();
box.name1='Lee';
box.age=10;
box.run=function(){
return this.name+this.age+'运行中...'; //this表示当前作用域下的对象;
};
//this表示new Object()实例化出来的对象;
//this要放在一个作用域中,比如box.run(){},只是box作用域下的方法,即可用this来表示box
alert(box.run());
var name1='Jack';
alert(this.name1); //此时this表示window对象
结果:(1)Lee 10 运行中...
(2)Jack(由于作为了全局变量,取代了之前的name1)
案例1-2——解决实例化对象产生重复的方法(工厂模式)
//工厂模式
function createObject(name,age){
var obj=new Object(); //创建对象;
obj.name=name; //为对象添加属性
obj.age=age;
obj.run=function(){ //为对象添加方法;
return this.name+this.age+'运行中...';
};
return obj.; //返回obj这个对象的引用;
};
var box1=createObject('Zhao',21); //创建第一个、第二个对象;
var box2=createObject('Zhang',20);
alert(box1.run()); //打印出第一个、第二个对象的实例化run()方法;
alert(box2.run());
alert(box1 instanceof Object); //true;
alert(box2 instanceof Object); //true;
注意:由于上述若有重复的createObject2()方法,内容与第一个完全相同,且有一个box3对象,
并把它实例化,会发现在box3 instanceof Object时,也会返回true,并不能准确判断哪个实例化方法,
为此,可采用构造函数方法,即案例1-3。
案例1-3——构造函数:既解决了重复实例化的问题,又解决了对象识别的问题,并没有new Object(),却可以实例化Box()
function Box(name,age){ //创建一个对象,所有构造函数的对象其实都是Object
this.name=name; //添加一个属性
this.age=age;
this.run=function(){ //添加一个方法;
return this.name+this.age+'运行中';
};
};
function Dock(name,age){ //创建一个对象,所有构造函数的对象其实都是Object
this.name=name; //添加一个属性
this.age=age;
this.run=function(){ //添加一个方法;
return this.name+this.age+'运行中';
};
};
var box1=new Box('Zhao,21'); //实例化;
var box2=new Box('Zhang,20');
var box3=new Dock('Huang,22');
//alert(box1.run());
//alert(box2.run());
alert(box1 instanceof Box); //true;
alert(box3 instanceof Box); //false;
解析:由于在上述函数中,构造了两个函数,若要用instanceof测试对象,即可以发现
box1是Box的实例化对象,所以返回true;box3是Dock的实例化对象,不是Box的
实例化对象,所以返回了false;
区别——构造函数、工厂模式
(1)构造函数没有显示的创建对象(new Object())
(2)直接将属性和方法赋值给this对象
(3)没有return语句;
(new Object()相当于直接在后台上创建了对象方法)
案例1-4——this的使用(全局访问name会有干扰)
function Box(user,age){
this.user=name;
this.age=age;
this.run=function(){
return this.user+this.age+'运行中...';
};
};
var box1=new Box('Zhao',21);
alert(box1.run()); //Zhao 21 运行中...
alert(this.name);
//由于该this指向的是window对象,为null,即返回“unfined”
案例1-5——对象冒充call()方法
//...构造函数
var o=new Object();
box.call(o,'Zhao',21); //对象冒充
alert(o.run());
案例1-6——属性、方法、地址的比较
var box1=new Box('Zhao',21);
var box2=new Box('Zhao',21);
alert(box1.age==box2.age); //true;
alert(box1.run()==box2.run()); //true;
alert(box1.run==box2.run); //false;
解析:由于在进行box.run比较时,比较的是地址,
box1对象实例化对应的是地址1,box2对象实例化对应的是地址2,所以二者不相等
(比较的是引用地址)
总结:对于一个对象,其属性和方法对于一个相等传递参数均相等,但对于实例化地址而言,是不相等的。
2、原型
由于创建的每一个函数都有prototype(原型)属性,这个属性是一个对象。
(1)用途:包含可以由特定类型的所有实例共享的属性和方法
简而言之,prototype通过调用构造函数而创建的那个对象的原型对象。
(2)优点:可以让所有对象实例共享它包含的属性和方法,即不必在构造函数中定义对象信息,
而是可以直接将这些信息添加到原型中。
案例2-1——原型prototype构造函数
functionc Box(){
....
};
解析:当构造函数体内有东西(属性/方法),即叫做实例属性、实例方法
Box.prototype.name='Zhao';
Box.prototype.age=21;
Box.prototype.run=function(){
return this.name+this.age+'运行中...';
};
var box1=new Box();
var box2=new Box();
alert(box1.run()); //Zhao 21 运行中;
alert(box1.run==box2.run); //true
区别——实例化构造与原型prototype构造函数
最大的不同点,即原型prototype构造函数时,会共享地址,
在进行box.run比较时,返回true,共享了同一个地址
(1)实例化构造函数,box1,box2均为function类型,但二者相互独立;
(2)原型prototype构造函数,box1,box2均会指向原型对象的一个_proto_属性(指针),当实例化了该指针属性时,
它的作用是指向构造函数的原型属性constructor。
案例2-1(2)——prototype
alert(box1.prototype); //由于prototype是一个对象,所以访问不到
注意:在IE浏览器不能识别
案例2-2——判断原型prototype是否存在
var obj=new Object();
alert(Box.prototype.isPrototypeOf(obj)); //只要实例化对象,就会指向原型
(3)原型模式的执行流程
a、先查找构造函数实例里的属性或方法,若有,即返回;
b、若构造函数中没有,则去它的原型对象中找,若有,就返回。
案例2-3——虽说可以通过对象实例访问保存在原型中的值,但不可以访问通过对象实例重写原型中的值。
var box1=new Box();
alert(box1.name); //Zhao,由于在案例2-1时,Box.prototype.name='Zhao',原型中的值;
box1.name='Zhang';
alert(box1.name); //Zhang,就近原则
var box2=new Box();
alert(box2.name); //Zhao,原型中的值,没有被box1修改
案例2-4——若想在就近原则后访问原型属性,即可以先删除实例中属性delete
delete box1.name;
alert(box1.name); //删除了就近原则时的Zhang,可返回原型中的Zhao
(4)a、判断实例中是否存在指定属性hasOwnProperty()
b、in操作符,会在通过对象能够访问给定属性时访问true,无论该属性在实例中还是在原型中
(in操作符表示只要有就返回true)
案例2-5——判断实例中是否有指定属性
function Box(){} //构造函数为空
Box.prototype.name='Zhao';
Box.prototype.age=21;
Box.prototype.run=function(){
return this.name+this.age+'运行中...';
};
var box1=new Box(); //表示实例化了Box()
box1.name='Zhang';
alert(box1.hasOwnProperty('name')); //由于实例了name->'Zhang',所以结果应该返回true
案例2-5——in操作符的使用
上述代码修改为
var box1=new Box();
alert('name' in box1);
//不管实例或原型属性是否存在,只要有就会返回true;两边都没有,返回flase。
案例2-6——判断原型中是否有属性
(将案例2-5与案例2-6合并起来)
function isProperty(object,property){
return !object.hasOwnProperty(property)&&(property in object);
//表示实例中没有,原型和实例中都有,即“只有原型中有”
}
//原型
function Box(){...}
Box.prototype.name='Zhao'; //原型属性;
Box.prototype.age=21;
var box1=new Box();
//box1.name=''; //实例属性;
//alert(isProperty(box1,'name')); //false,由于在实例化对象属性中仍有,返回false;
alert(isProperty(box1,'name')); //true
//由于在实例中创建的box1对象没有name,但在原型中有,所以返回true;