您的位置:首页 > Web前端 > JavaScript

JavaScript面向对象编程-阮一峰-已读

2016-04-14 16:16 465 查看
封装

最简单的封装就是将属性封装在对象中,这是生成对象的原始模式;

缺点在于写起来麻烦,而且原型与实例之间没有联系;

//原型
var Cat={
name:"",
color:""
}
//实例
var cat1={};
cat1.name="Tom";
cat1.color="yellow";
var cat2={};
cat1.name="Peter";
cat1.color="black";

用函数生成实例:原型与实例之间仍然没有关联

//用函数生成实例
function Cat(name,color){
return{
name:name,
color:color
}
}

var cat1=Cat("Tom", "yellow");
var cat2=Cat("Peter", "black");

构造函数模式:构造函数其实是个普通函数,但内部使用this变量;

实例的constructor属性指向构造函数

构造函数模式的问题在于浪费内存:当为构造函数添加固定值的属性和方法时,在所有实例中这些属性和方法时一样的,但

//构造函数
function Cat(name,color){
this.name=name;
this.color=color;
}
//生成实例
var cat1=new Cat("Tom","yellow");
var cat2=new Cat("Peter","black");

继承

//animal对象的构造函数,使cat对象继承animal
function(){
this.species="动物";
}


构造函数绑定:使用call()或apply()方法将要继承的对象的构造函数绑定到子对象的构造函数中;



function Cat(name,color){

//将Animal构造函数作为cat对象的方法调用,使cat对象继承animal的属性和方法

Animal.apply(this,arguments);

this.name=name;

this.color=color;

}



prototype模式

Cat.prototype.constructor默认是指向Cat的,但是重写了Cat.prototype之后,该属性就指向Animal()了,而且实例将继承该属性,cat1的构造函数也变成了Animal(), 所以必须手动纠正,将Cat.prototype.constructor重新指向Cat, 这在重写prototype是必须的;



Cat.prototype=new Animal(); //将cat的原型指向Animal的实例



Cat.prototype.constructor=Cat; //将cat原型原型的constructor设置为Cat



直接继承原型

Animal的属性可以直接写到Animal.prototype中,所以可以直接让Cat.prototype继承Animal.prototype;

优点是效率高,不需要创建Animal的实例;

缺点是Cat.prototype和Animal.prototype指向同一个对象,对Cat.prototype的修改同样会反映到Animal.prototype;

所以现在Animal.prototype.constructor也指向Cat();



function Animal(){}

Animal.prototype.species="动物";
Cat.prototype=Animal.prototype;
Cat.prototype.constructor=Cat;



利用空对象作为中介,然后继承原型;

F是空对象,几乎不占内存;

通过F()作为中介,修改cat的原型就不会影响animal的原型了;



var F=function(){};



F.prototype=Animal.prototype;



Cat.prototype=new F();



Cat.prototype.constructor=Cat;



将以上方法封装为函数:child对象将继承parent对象



function extend(Child, Parent){ //Child是子类,Parent是父类



var F=function(0{};



F.prototype=Parent.prototype;



Child.prototype=new F();



Child.prototype.constructor.=Child;



Child.uber=Parent.prototype;



}



uber属性直接指向Parent.prototype, 是为了使对象可以直接调用父对象的方法,纯属备用性质;

复制继承:将父类的属性和方法都复制到子类中



//复制继承

function extend2(Child,Parent){

var p=Parent.prototype;

var c=Child.prototype;

for(var prop in p){

c[prop]=p[prop]; //将父类的属性复制给子类

}

c.uber=p;

}


不使用构造函数的继承

不经过构造函数,直接实现实例对象之间的继承;

object()方法:该函数返回的对象继承了传入的对象;


//object()函数:实现实例对象之间的继承
function object(parent){
function F(){};
F.prototype=parent;
return new F(); //返回的对象不包含自有属性
}



浅复制:将父对象的属性复制给子对象

当对象的属性值是引用类型时,子对象获得是该属性值一个引用,当修改子对象的属性只时,父对象的属性也会被修改

所以浅复制只适用于复制基本类型属性值;



//浅复制

function extendCopy(parent){

var child={};

for(prop in parent){

child[prop]=parent[prop];

}

c.uber=p;

return c;

}



深复制:真正实现对对象的复制,而不是引用



//深复制

function deepCopy(parent,child){

var c=c || {};

for(prop in parent){

if(parent[prop]==="object"){

child[prop]=(p[prop].constructor===Array) ? []:{};

deepCopy(parent[prop],child[prop]); //递归,将prop对象的属性值复制给child[prop]对象

}

else{

child[prop]=parent[prop];

}

}

return child;

}

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: