一、创建对象
ECMAScript有两种开发模式:1.函数式(过程化);2.面向对象(OOP);面向对象语言有一个标志,就是有类的慨念,而通过类可以创建任意多个具有相同属性和方法的对象。但是,ECMAScript没有类的慨念,所以它的对象与基于类的语言的对象有所不同。
1、JS中普通创建对象的方法
var box = new Object();
box.name = 'wu';
box.age = 100;
box.run =function(){
return this.name + this.age + '运行中。。';
};
alert(box.run());
JavaScript创建对象的基本方法,但有一个缺点,就是创建一个类似的对象要大量的代码。
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;
}
var box1 = createObject('wu', 18);
var box2 = createObject('yan',19);
alert(box1.run());
alert(box2.run());
alert(typeof box1);
工厂模式解决了重复实例化的问题,但还有一个问题,就是识别问题,无法搞清楚是哪个对象的实例。
3、构造函数
ECMAScript中可以采用构造函数来创建特定的对象。类似于Object对象。
function Box(name, age){ //构造模式
this.name = name;
this.age = age;
this.run = function (){
return this.name + this.age + '运行中。。';
};
}
构造函数与普通函数的区别就是他们的调用方式不同。构造函数必须使用new运算符来调用,否则就是普通函数。
var box1 = new Box('wu', 18);
var box2 =new Box('yan', 19);
alert(box1.run());
alert(box2.run());
alert(box1 instanceof Box);
Box('Jet', 20);//无效
var o = new Box('Jet', 20);
Box.call(o, 'Lee', 100);//对象冒充
alert(o.run());
function Box(name, age){ //构造模式
this.name = name;
this.age = age;
this.run = function (){
return this.name + this.age + '运行中。。';
};
}
var box1 = new Box('xxx', 100);
var box2 = new Box('xxx', 100);
alert(box1.name == box2.name);//ture
alert(box1.run == box2.run);//false, 方法其实也是一种引用地址,唯一性
alert(box1.run() == box2.run());//ture,方法的值相等,因为传参相等。
二、原型
我们在创建的每一个对象都有一个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);//ture, 原型内的方法的引用地址一致
在原型模式声明中,多了两个属性,这两个属性都是创建对象时自动生成的。__proto__属性是实例指向原型对象的一个指针,它的作用就是指向构造函数的原型属性constructor。通过这两个属性,就可以访问到原型里的属性和方法了。
判断一个对象是否指向该构造函数的原型对象,可以使用isPrototypeOf()方法来测试;
function Box(){};
Box.prototype.name = 'Lee';
Box.prototype.age = 100;
Box.prototype.run = function (){
return this.name + this.age + '运行中。。';
};
var box = new Box();
alert(Box.prototype.isPrototypeOf(box));
原型模式的执行流程:
1.先查找构造函数实例里的属性或方法,如果有,立刻返回;
2..如果构造函数实例里没有,则去它的原型对象里找,如果有,就返回;
var box1 = new Box();
alert(box1.name); //Lee,原型里的值
box1.name = 'Jack';
alert(box.1name); //Jack,就近原则,
var box2 = new Box();
alert(box2.name); //Lee,原型里的值,没有被box1修改
如何判断属性是在构造函数的实例里,还是在原型里?可以使用hasOwnProperty()函数来验证:
alert(box.hasOwnProperty('name')); //实例里有返回true,否则返回false
in操作符会在通过对象能够访问给定属性时返回true,无论该属性存在于实例中还是原型中。
我们可以通过hasOwnProperty()方法检测属性是否存在实例中,也可以通过in来判断实例或原型中是否存在属性。那么结合这两种方法,可以判断原型中是否存在属性。
function isProperty(object, property) { //判断原型中是否存在属性
return !object.hasOwnProperty(property) && (property in object);
}
var box = new Box();
alert(isProperty(box, 'name')) //true,如果原型有