js OOP编程
今天来总结下关于JavaScript的面向对象编程!
<h1>一、封装</h1> <h2>/*1. 生成对象的原始模式*/</h2>var Cat = { name:'', color:'' } //根据这个原型对象的规格,生成2个实例对象。 var cat1 = {}; cat1.name = "大毛"; cat1.color = "黄色"; var cat2 = {}; cat2.name = "二毛"; cat2.color = "黑色"; //缺点:1.代码冗余 2.实例之间看不出联系,它们属于object <h2>/*2. 原始模式改进(工厂模式)*/</h2>function Cat(name,color){ return { name:name, color:color } } //使用: var cat1 = Cat("大毛","黄色"); var cat2 = Cat("二毛","黑色"); //缺点:1.实例之间看不出联系,它们属于object <h2>/*3. 构造函数模式*/</h2>function Cat(name,color){ this.name = name; this.color = color; } //使用: var cat1 = new Cat("大毛","黄色"); var cat2 = new Cat("二毛","黑色"); //这时,cat1和cat2会自动包含一个constructor属性,指向它们的构造函数 alert(cat1.constructor == Cat);//true alert(cat2.constructor == Cat);//true alert(cat1 instanceof Cat);//true alert(cat2 instanceof Cat);//true //缺点:浪费内存 <h2>/*4. 构造函数模式的问题和Prototype模式*/</h2> function Cat(name,color){ this.name = name; this.color = color; this.type = "猫科动物"; this.eat = function(){ alert("吃老鼠"); } } //使用: var cat1 = new Cat("大毛","黄色"); var cat2 = new Cat("二毛","黑色"); //实际上这样做是十分浪费内存的,因为type属性和eat方法是所有Cat类都应该有的, //没有必要每次实例化的时候都为这两个属性分配空间。 //从这里可以看出为它们另外分配了空间: alert(cat1.type == cat2.type);//false alert(cat1.eat == cat2.eat);//false //下面用prototype模式可以解决这个问题 //javascript规定,每一个构造函数都有一个prototype属性,指向另一个对象。 //这个对象的所有属性和方法,都会被构造函数的实例继承。 //这样,我们就可以将那此不变的属性和方法,直接定义在prototype对象中。 function Cat(name,color){ this.name = name; this.color = color; } Cat.prototype.type = "猫科动物"; Cat.prototype.eat = function(){ alert("吃老鼠"); } //prototype对象是一个类所有实例公用的,可以以此来验证: alert(cat1.type == cat2.type);//true alert(cat1.eat == cat2.eat);//true //指向同一空间 <h2>/*5. prototype模式的验证方法*/</h2> <h3>1).isPrototypeOf()</h3>//用来判断,某个prototype对象和某个实例之间的关系。 alert(Cat.prototype.isPrototypeOf(cat1));//true alert(Cat.prototype.isPrototypeOf(cat2));//true <h3>2).hasOwnProperty()</h3>//用来判断,一个属性是不是本地属性 alert(cat1.hasOwnProperty("name"));//true alert(cat1.hasOwnProperty("type"));//false //type属性是继承自prototype对象的属性,不是本地属性,所以为false <h3>3).in运算符</h3>//用来判断,某个实例是否含有某个属性,不管是不是本地属性。 alert("name" in cat1);//true alert("type" in cat1);//true //in运算符还可以用来,遍历某个对象的所有属性。 for(var prop in cat1){ alert(cat1[prop]); } <h1>二、继承</h1> <h2>/*1.“构造函数”继承*/</h2> function Animal(){ this.species = '动物'; } function Cat(name,color){ this.name = name; this.color = color; } //问题:怎样才能让“猫”继承“动物”呢? <h3>/*1). 构造函数绑定*/</h3>function Cat(name,color){ Animal.apply(this,arguments);//实际上是调用了父类的构造函数 this.name = name; this.color = color; } <h3>/*2). prototype模式*/</h3>Cat.prototype = new Animal(); Cat.prototype.constructor = Cat; <h3>/*3). 直接继承prototype*/</h3>//这种方法是对第二种方法的改进,由于Animal对象中, //不变的属性都可以直接写入Animal.prototype,所以我们也可以让Cat()跳过Animal(), //直接继承Animal.prototype //改写Animal对象: function Animal(){} Animal.prototype.species = '动物'; //开始继承: Cat.prototype = Animal.prototype; Cat.prototype.constructor = Cat; //与前一种方法相比,这样做的优点是效率高(不用建立Animal实例),比较节省内存 //缺点:Cat.prototype和Animal.prototype现在指向了同一个对象,那么任何对 //Cat.prototype的修改,都会反映到Animal.prototype中,这并不是我们想要的 <h3>/*4). 利用空对象作为中介*/</h3>//正因为存在上述的缺点,所以才有了第四种继承方式,利用一个空对象作为中介实现继承。 var F = function(){} F.prototype = Animal.prototype; Cat.prototype = new F(); Cat.prototype.constructor = Cat; //F是空对象,所以几乎不占用内存。 //为了使用的方便,将其封装一下: function extend(Child, Parent) { var F = function(){}; F.prototype = Parent.prototype; Child.prototype = new F(); Child.prototype.constructor = Child; Child.uber = Parent.prototype;//主要是用来做扩展的 } <h3>/*5). 拷贝继承*/</h3>//对于父类,还是将它所有不变的属性放到它的prototype对象中。 function Animal(){} Animal.prototype.species = '动物'; function extend2(Child, Parent){ var p = Parent.prototype; var c = Child.prototype; for(var i in p){ c[i] = p[i]; } c.uber = p;<span style="font-family: Arial, Helvetica, sans-serif;">// 用于功能扩展</span> } <h2>/*2.“非构造函数”继承*/</h2> var Chinese = { nation:'中国' }; var Doctor = { career:'医生' } //怎样让“医生”去继承“中国人”,从而得到一个中国医生对象? //注:这里的两个对象都是普通对象,而不是构造函数,无法使用构造函数方法实现继承。 <h3>/*1). object()方法*/</h3>function object(o){ function F() {} F.prototype = o; return new F(); } <h3>/*2). 浅拷贝方法*/</h3>function extendCopy(p){ var c = {}; for(var i in p){ c[i] = p[i]; } c.uber = p;// 用于功能扩展 return c; } <h3>/*3). 深拷贝方法*/</h3>function deepCopy(p,c){ var c = c||{}; for(var i in p){ if(typeof p[i] === 'object'){ c[i] = (p[i].constructor === Array) ? [] : {}; deepCopy(p[i],c[i]); } else { c[i] = p[i]; } } } return c; }
郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。