javascript中对象的定义:无序属性的集合,其属性包含基本值、对象或者函数。
javascript中有两种属性:数据属性和访问器属性。
数据属性包含一个数据值的位置,在这个位置可以读取和写入值。数据属性有4个描述其行为的特性。
1.[[Configurable]]:表示能否通过delete删除属性和重新定义属性。
2.[[Enumerable]]:表示能否通过for-in循环返回属性。
3.[[Writeable]]:表示能否修改属性的值
4.[[Value]]:表示这个属性的值
实例:
javascript: var person={};
Object.defineProperty(person,"name",{writable:false,value:"seacean"});
console.log(person.name);
person.name="hello wrold!";
console.log(person.name);
运行结果显示是
这些数据属性的配置如果有设置,在严格模式下进行非法操作会返回错误,非严格模式会忽略。
访问器属性不包含任何数值,包含一对get/set函数。
1.[[Configurable]]:表示能否通过delete删除属性和重新定义属性。
2.[[Enumerable]]:表示能否通过for-in循环返回属性。
3.[[get]]:在读取属性的时候调用的函数
4.[[set]]:在设置属性的时候调用的函数
访问器的属性和数据属性一样,只能使用Object.defineProperty来进行定义。这样的话,数据属性和访问器属性可以同时定义。
定义多个属性的方法是Object.defineProperties.
创建对象的方法
工厂模式
function createPerson(name,age,job){
var o=new Object();
o.name=name;
o.age=age;
o.job=job;
o.sayName=function(){ return this.name;};
return o;
}
javascript:
function createPerson(name,age,job){ var o=new Object(); o.name=name; o.age=age; o.job=job; o.sayName=function(){ return this.name;}; return o; }
这是一个创建Person类的工厂方法
构造函数方式
function Person(){
this.name="nicole";
}
原型模式
function Person(){};
Person.prototype.name="nicole";
这些方法各有优缺点,工厂无法让创建变得更像面向对象,构造函数无法保存类共享属性,原型的所有属性都是共享的。
结合各自的优缺点,我们使用构造函数创建每个类中非静态的属性和方法,原型创建类中的静态属性和方法。
function Man(obj){
this.name=obj.name;
}
Man.prototype={
constructor:Person,
sayName:function(){alert(this.name);}
}
还有一类安全程度更高的构造函数,成为稳妥构造函数,不使用this,不使用new操作符调用构造函数,与别的对象没有关联
function Person(name,age,job){
var obj=new Object();
obj.name=name;
obj.age=age;
obj.job=job;
return obj;
}
一般情况下我们用不到使用继承这种情况,使用到继承这种情况的时候大多是定义框架,开发组件等等。而且一般的web开发是用不到继承的。但是一用到继承就说明面对的情况很复杂。
面向对象的继承关系显得有些复杂
js的继承是实现上的继承,造成继承的事实。
原型链方式继承
function SuperType(){
this.property=true;
}
SuperType.prototype.getSuperValue=function(){
return this.property;
}
function SubType(){
this.subproperty=false;
}
SubType.prototype=new SuperType();
SubType.prototype.getSubValue=function(){
return this.subproperty;
}
var instance=new SubType();
alert(instance.getSuperValue());
这个说明了继承的含义和形式,继承就是采用上面的样子,不断扩展原型。
也可以将SuperType里面的全部属性和方法copy到SubType中,造成事实上的继承关系。
继承关系中的方法重写
在SubType.prototype=new SuperType();之后可以添加对里面方法的重写为SubType.prototype.getSuperValue=function(){
return this.subproperty;
}
继承的另一种方式
使用call,apply方法
借用构造函数式继承
function SuperType(name){
this.name=name;
this.colors=["red","yellow","orange"];
}
function SubType(){
SuperType.call(this,"max");
this.age=100;
}
组合继承方式,组合前面两种情况
function SuperType(name){
this.name=name;
this.colors=["red","yellow","orange"];
}
SuperType.prototype.sayName=function(){
alert(this.name);
}
function SubType(name,age){
SuperType.call(this,name);
this.age=age;
}
SubType.prototype=new SuperType();
SubType.prototype.sayAge=function(){
alert(this.age);
}
这样子类本身通过构造函数可以扩展,通过prototype也可以扩展
原型式继承
基于已有的对象创建新的对象,同时还不必因此创建新的对象
function getPerson(/*object*/ obj){
function F(){}
F.prototype=obj;
return new F();
}
obj是已将存在的对象,新对象的类型不需要给出明确定义
寄生式继承
function createAnother(original){
var clone=getPerson(original);//进行新的包装
clone.color="red";
clone.sayColor=function(){alert(this.color);};
return clone;
}
在这里面,original是一个已存在的对象,进入函数内要进行添加新的属性和方法,返回一个新的对象。这个不是通过构造函数方式运作的。
寄生组合式继承
function SuperType(name){
this.name=name;
this.colors=["red","yellow","orange"];
}
SuperType.prototype.sayName=function(){
alert(this.name);
}
function SubType(name,age){
SuperType.call(this,name);
this.age=age;
}
function inheritPrototype(subType,superType){
var proto=object(superType.prototype);
proto.constructor=subType;
subType.prototype=proto;
}
inheritPrototype(SubType,SuperType);
//对子类父类之间的关系进行修正
SubType.prototype.sayAge=function(){
alert(this.age);
}
这种继承方式只引用了一次构造函数,不改变其它东西。这种方式是目前最理想的继承方式。
var person={};
Object.defineProperty(person,"name",{writable:false,value:"seacean"});
console.log(person.name);
person.name="hello wrold!";
console.log(person.name);