老生常谈javascript的面向对象思想
面向对象的三大基本特性
封装(把相关的信息(无论数据或方法)存储在对象中的能力)
继承(由另一个类(或多个类)得来类的属性和方法的能力)
多态(一个对象在不同情况下的多种形态)
定义类或对象
第一种:基于Object对象
varperson=newObject(); person.name="Rose"; person.age=18; person.getName=function(){ returnthis.name; }; console.log(person.name);//Rose console.log(person.getName);//function(){returnthis.name;} console.log(person.getName());//Rose
缺点:不能创建多个对象。
第二种:基于字面量方式
varperson={ name:"Rose", age:18, getName:function(){ returnthis.name; } }; console.log(person.name);//Rose console.log(person.getName);//function(){returnthis.name;} console.log(person.getName());//Rose
优点:比较清楚的查找对象包含的属性和方法;
缺点:不能创建多个对象。
第三种:工厂模式
方式一:
functioncreatePerson(name,age){ varobject=newObject(); object.name=name; object.age=age; object.getName=function(){ returnthis.name; }; returnobject; } varperson1=createPerson("Rose",18); varperson2=createPerson("Jack",20); console.log(person1.name);//Rose console.log(person2.name);//Jack console.log(person1.getName===person2.getName);//false//重复生成函数,为每个对象都创建独立的函数版本
优点:可以创建多个对象;
缺点:重复生成函数getName(),为每个对象都创建独立的函数版本。
方式二:
functioncreatePerson(name,age){ varobject=newObject(); object.name=name; object.age=age; object.getName=getName; returnobject; } functiongetName(){ returnthis.name; } varperson1=createPerson("Rose",18); varperson2=createPerson("Jack",20); console.log(person1.name);//Rose console.log(person2.name);//Jack console.log(person1.getName===person2.getName);//true//共享同一个函数
优点:可以创建多个对象;
缺点:从语义上讲,函数getName()不太像是Person对象的方法,辨识度不高。
第四种:构造函数方式
方式一:
functionPerson(name,age){ this.name=name; this.age=age; this.getName=function(){ returnthis.name; } } varperson1=newPerson("Rose",18); varperson2=newPerson("Jack",20); console.log(person1.name);//Rose console.log(person2.name);//Jack console.log(person1.getName===person2.getName);//false//重复生成函数,为每个对象都创建独立的函数版本
优点:可以创建多个对象;
缺点:重复生成函数getName(),为每个对象都创建独立的函数版本。
方式二:
functionPerson(name,age){ this.name=name; this.age=age; this.getName=getName; } functiongetName(){ returnthis.name; } varperson1=newPerson("Rose",18); varperson2=newPerson("Jack",20); console.log(person1.name);//Rose console.log(person2.name);//Jack console.log(person1.getName===person2.getName);//true//共享同一个函数
优点:可以创建多个对象;
缺点:从语义上讲,函数getName()不太像是Person对象的方法,辨识度不高。
第五种:原型方式
functionPerson(){ } Person.prototype.name='Rose'; Person.prototype.age=18; Person.prototype.getName=function(){ returnthis.name; }; varperson1=newPerson(); varperson2=newPerson(); console.log(person1.name);//Rose console.log(person2.name);//Rose//共享同一个属性 console.log(person1.getName===person2.getName);//true//共享同一个函数
缺点:它省略了为构造函数传递初始化参数,这在一定程序带来不便;另外,最主要是当对象的属性是引用类型时,它的值是不变的,总是引用同一个外部对象,所有实例对该对象的操作都会影响其它实例:
functionPerson(){ } Person.prototype.name='Rose'; Person.prototype.age=18; Person.prototype.lessons=["语文","数学"]; Person.prototype.getName=function(){ returnthis.name; }; varperson1=newPerson(); person1.lessons.push("英语"); varperson2=newPerson(); console.log(person1.lessons);//["语文","数学","英语"] console.log(person2.lessons);//["语文","数学","英语"]//person1修改影响了person2
第六种:构造函数+原型方式(推荐)
functionPerson(name,age){ this.name=name; this.age=age; } Person.prototype.getName=function(){ returnthis.name; }; varperson1=newPerson('Rose',18); varperson2=newPerson('Jack',20); console.log(person1.name);//Rose console.log(person2.name);//Jack console.log(person1.getName===person2.getName);//true//共享原型中定义的方法
缺点:属性定义在构造函数内,方法定义在构造函数外,与面向对象的封装思想不符。
第七种:构造函数+动态原型方式(推荐)
方式一:
functionPerson(name,age){ this.name=name; this.age=age; if(typeofPerson._getName==="undefined"){ Person.prototype.getName=function(){ returnthis.name; }; Person._getName=true; } } varperson1=newPerson('Rose',18); varperson2=newPerson('Jack',20); console.log(person1.name);//Rose console.log(person2.name);//Jack console.log(person1.getName===person2.getName);//true//共享原型中定义的方法
方式二:
functionPerson(name,age){ this.name=name; this.age=age; if(typeofthis.getName!=="function"){ Person.prototype.getName=function(){ returnthis.name; }; } } varperson1=newPerson('Rose',18); varperson2=newPerson('Jack',20); console.log(person1.name);//Rose console.log(person2.name);//Jack console.log(person1.getName===person2.getName);//true//共享原型中定义的方法
对象属性的扩展及删除
Javascript的对象可以使用'.'操作符动态的扩展其属性,可以使用'delete'关键字或将属性的值设置为'undefined'来删除属性。
functionPerson(name,age){ this.name=name; this.age=age; if(typeofPerson._getName==="undefined"){ Person.prototype.getName=function(){ returnthis.name; }; Person._getName=true; } } varperson=newPerson("Rose",18); person.job='Engineer';//添加属性 console.log(person.job);//Engineer deleteperson.job;//删除属性 console.log(person.job);//undefined//删除属性后值为undefined person.age=undefined;//删除属性 console.log(person.age);//undefined//删除属性后值为undefined
对象属性类型
数据属性
特性:
[configurable]:表示能否使用delete操作符删除从而重新定义,或能否修改为访问器属性。默认为true;
[enumberable]:表示是否可通过for-in循环返回属性。默认true;
[writable]:表示是否可修改属性的值。默认true;
[value]:包含该属性的数据值。读取/写入都是该值。默认为undefined;如上面实例对象person中定义了name属性,其值为'Myname',对该值的修改都反正在这个位置
functionPerson(name,age){ this.name=name; this.age=age; if(typeofPerson._getName==="undefined"){ Person.prototype.getName=function(){ returnthis.name; }; Person._getName=true; } } varperson=newPerson("Rose",18); Object.defineProperty(person,"name",{configurable:false,writable:false}); person.name="Jack"; console.log(person.name);//Rose//重新赋值无效 deleteperson.name; console.log(person.name);//Rose//删除无效
注意:
一旦将configurable设置为false,则无法再使用defineProperty将其修改为true(执行会报错:cannotredefineproperty:propertyName)
functionPerson(name,age){ this.name=name; this.age=age; if(typeofPerson._getName==="undefined"){ Person.prototype.getName=function(){ returnthis.name; }; Person._getName=true; } } varperson=newPerson("Rose",18); Object.defineProperty(person,"name",{configurable:false,writable:false}); person.name="Jack"; console.log(person.name);//Rose//重新赋值无效 deleteperson.name; console.log(person.name);//Rose//删除无效 Object.defineProperty(person,"name",{configurable:true,writable:true});//Cannotredefineproperty:name
访问器属性
特性:
[configurable]:是否可通过delete操作符删除重新定义属性;
[numberable]:是否可通过for-in循环查找该属性;
[get]:读取属性时调用,默认:undefined;
[set]:写入属性时调用,默认:undefined;
访问器属性不能直接定义,必须使用defineProperty()或defineProperties来定义:如下
functionPerson(name,age){ this.name=name; this._age=age; if(typeofPerson._getName==="undefined"){ Person.prototype.getName=function(){ returnthis.name; }; Person._getName=true; } } varperson=newPerson("Rose",18); Object.defineProperty(person,"age",{ get:function(){ returnthis._age; }, set:function(age){ this._age=age; }}); person.age=20; console.log(person.age);//20//person.age=20是使用set方法将20赋值给_age,person.age是使用get方法将_age的读取出来 console.log(person._age);//20
获取所有的属性和属性的特性
使用Object.getOwnPropertyNames(object)方法可以获取所有的属性;
使用Object.getOwnPropertyDescriptor(object,property)方法可以取得给定属性的特性;
functionPerson(name,age){ this.name=name; this._age=age; if(typeofPerson._getName==="undefined"){ Person.prototype.getName=function(){ returnthis.name; }; Person._getName=true; } } varperson=newPerson("Rose",18); Object.defineProperty(person,"age",{ get:function(){ returnthis._age; }, set:function(age){ this._age=age; }}); console.log(Object.getOwnPropertyNames(person));//["name","_age","age"] console.log(Object.getOwnPropertyDescriptor(person,"age"));//{enumerable:false,configurable:false,get:function,set:function}
对于数据属性,可以取得:configurable,enumberable,writable和value;
对于访问器属性,可以取得:configurable,enumberable,get和set;
继承机制实现
对象冒充
functionFather(name){ this.name=name; this.getName=function(){ returnthis.name; } } functionSon(name,age){ this._newMethod=Father; this._newMethod(name); deletethis._newMethod; this.age=age; this.getAge=function(){ returnthis.age; } } varfather=newFather("Tom"); varson=newSon("Jack",18); console.log(father.getName());//Tom console.log(son.getName());//Jack//继承父类getName()方法 console.log(son.getAge());//18
多继承(利用对象冒充可以实现多继承)
functionFatherA(name){ this.name=name; this.getName=function(){ returnthis.name; } } functionFatherB(job){ this.job=job; this.getJob=function(){ returnthis.job; } } functionSon(name,job,age){ this._newMethod=FatherA; this._newMethod(name); deletethis._newMethod; this._newMethod=FatherB; this._newMethod(job); deletethis._newMethod; this.age=age; this.getAge=function(){ returnthis.age; } } varfatherA=newFatherA("Tom"); varfatherB=newFatherB("Engineer"); varson=newSon("Jack","Programmer",18); console.log(fatherA.getName());//Tom console.log(fatherB.getJob());//Engineer console.log(son.getName());//Jack//继承父类FatherA的getName()方法 console.log(son.getJob());//Programmer//继承父类FatherB的getJob()方法 console.log(son.getAge());//18
call()方法
functionFather(name){ this.name=name; this.getName=function(){ returnthis.name; } } functionSon(name,job,age){ Father.call(this,name); this.age=age; this.getAge=function(){ returnthis.age; } } varfather=newFather("Tom"); varson=newSon("Jack","Programmer",18); console.log(father.getName());//Tom console.log(son.getName());//Jack//继承父类getName()方法 console.log(son.getAge());//18
多继承(利用call()方法实现多继承)
functionFatherA(name){ this.name=name; this.getName=function(){ returnthis.name; } } functionFatherB(job){ this.job=job; this.getJob=function(){ returnthis.job; } } functionSon(name,job,age){ FatherA.call(this,name); FatherB.call(this,job); this.age=age; this.getAge=function(){ returnthis.age; } } varfatherA=newFatherA("Tom"); varfatherB=newFatherB("Engineer"); varson=newSon("Jack","Programmer",18); console.log(fatherA.getName());//Tom console.log(fatherB.getJob());//Engineer console.log(son.getName());//Jack//继承父类FatherA的getName()方法 console.log(son.getJob());//Programmer//继承父类FatherB的getJob()方法 console.log(son.getAge());//18
apply()方法
functionFather(name){ this.name=name; this.getName=function(){ returnthis.name; } } functionSon(name,job,age){ Father.apply(this,newArray(name)); this.age=age; this.getAge=function(){ returnthis.age; } } varfather=newFather("Tom"); varson=newSon("Jack","Programmer",18); console.log(father.getName());//Tom console.log(son.getName());//Jack//继承父类getName()方法 console.log(son.getAge());//18
多继承(利用apply()方法实现多继承)
functionFatherA(name){ this.name=name; this.getName=function(){ returnthis.name; } } functionFatherB(job){ this.job=job; this.getJob=function(){ returnthis.job; } } functionSon(name,job,age){ FatherA.apply(this,newArray(name)); FatherB.apply(this,newArray(job)); this.age=age; this.getAge=function(){ returnthis.age; } } varfatherA=newFatherA("Tom"); varfatherB=newFatherB("Engineer"); varson=newSon("Jack","Programmer",18); console.log(fatherA.getName());//Tom console.log(fatherB.getJob());//Engineer console.log(son.getName());//Jack//继承父类FatherA的getName()方法 console.log(son.getJob());//Programmer//继承父类FatherB的getJob()方法 console.log(son.getAge());//18
原型链方法
functionFather(){ } Father.prototype.name="Tom"; Father.prototype.getName=function(){ returnthis.name; }; functionSon(){ } Son.prototype=newFather(); Son.prototype.age=18; Son.prototype.getAge=function(){ returnthis.age; }; varfather=newFather(); varson=newSon(); console.log(father.getName());//Tom console.log(son.getName());//Tom//继承父类FatherA的getName()方法 console.log(son.getAge());//18
混合方式(call()+原型链)
functionFather(name){ this.name=name; } Father.prototype.getName=function(){ returnthis.name; }; functionSon(name,age){ Father.call(this,name); this.age=age; } Son.prototype=newFather(); Son.prototype.getAge=function(){ returnthis.age; }; varfather=newFather("Tom"); varson=newSon("Jack",18); console.log(father.getName());//Tom console.log(son.getName());//Jack//继承父类Father的getName()方法 console.log(son.getAge());//18
多态机制实现
functionPerson(name){ this.name=name; if(typeofthis.getName!=="function"){ Person.prototype.getName=function(){ returnthis.name; } } if(typeofthis.toEat!=="function"){ Person.prototype.toEat=function(animal){ console.log(this.getName()+"说去吃饭:"); animal.eat(); } } } functionAnimal(name){ this.name=name; if(typeofthis.getName!=="function"){ Animal.prototype.getName=function(){ returnthis.name; } } } functionCat(name){ Animal.call(this,name); if(typeofthis.eat!=="function"){ Cat.prototype.eat=function(){ console.log(this.getName()+"吃鱼"); } } } Cat.prototype=newAnimal(); functionDog(name){ Animal.call(this,name); if(typeofthis.eat!=="function"){ Dog.prototype.eat=function(){ console.log(this.getName()+"啃骨头"); } } } Dog.prototype=newAnimal(); varperson=newPerson("Tom"); person.toEat(newCat("cat"));//Tom说去吃饭:cat吃鱼 person.toEat(newDog("dog"));//Tom说去吃饭:dog啃骨头
以上这篇老生常谈javascript的面向对象思想就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持毛票票。