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;
}
最简单的封装就是将属性封装在对象中,这是生成对象的原始模式;
缺点在于写起来麻烦,而且原型与实例之间没有联系;
//原型
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;
}
相关文章推荐
- 如何POST一个JSON格式的数据给Restful服务
- Jackson 框架,轻易转换JSON
- JavaScript入门篇
- JS实现图片推拉门效果
- JSP中常用的JSTL fmt(format格式化)标签用法整理
- javascript DOM艺术
- 【JS】:JS实现网页计算器
- AFNetworking如何post一个json数据到服务器
- 一起学写js Calender日历控件
- a标签中的href="#"与href="javascript:void(0)"区别
- 在HTML网页上打印需要的内容,JS代码
- javascript运行机制之执行顺序详解
- js 日期格式化函数
- 【转】用Js的eval解析JSON中的注意点
- js时间段判断的函数
- 原生js实现autocomplete插件
- JSP中一些JSTL核心标签用法总结
- JS 小技巧
- XML和JSON解析-----定义与比较
- 157 javascript中对变量和函数的hoist