面向對象的三大基本特性 封裝(把相關的信息(無論數據或方法)存儲在對象中的能力) 繼承(由另一個類(或多個類)得來類的屬性和方法的能力) 多態(一個對象在不同情況下的多種形態) 定義類或對象 第一種:基於Object對象 var person = new Object(); person.name ...
面向對象的三大基本特性
封裝(把相關的信息(無論數據或方法)存儲在對象中的能力)
繼承(由另一個類(或多個類)得來類的屬性和方法的能力)
多態(一個對象在不同情況下的多種形態)
定義類或對象
第一種:基於Object對象
var person = new Object();
person.name = "Rose";
person.age = 18;
person.getName = function () {
return this.name;
};
console.log(person.name);//Rose
console.log(person.getName);//function () {return
this.name;}
console.log(person.getName());//Rose
|
缺點:不能創建多個對象。
第二種:基於字面量方式
var person = {
name : "Rose",
age : 18 ,
getName : function () {
return this.name;
}
};
console.log(person.name);//Rose
console.log(person.getName);//function () {return
this.name;}
console.log(person.getName());//Rose
|
優點:比較清楚的查找對象包含的屬性和方法;
缺點:不能創建多個對象。
第三種:工廠模式
方式一:
function createPerson(name,age) {
var object = new Object();
object.name = name;
object.age = age;
object.getName = function ()
{
return this.name;
};
return object;
}
var person1 = createPerson("Rose",18);
var person2 = createPerson("Jack",20);
console.log(person1.name);//Rose
console.log(person2.name);//Jack
console.log(person1.getName === person2.getName);//false//重覆生成函數,為每個對象都創建獨立的函數版本
|
優點:可以創建多個對象;
缺點:重覆生成函數getName(),為每個對象都創建獨立的函數版本。
方式二:
function createPerson(name,age) {
var object = new Object();
object.name = name;
object.age = age;
object.getName = getName;
return object;
}
function getName() {
return this.name;
}
var person1 = createPerson("Rose",18);
var person2 = createPerson("Jack",20);
console.log(person1.name);//Rose
console.log(person2.name);//Jack
console.log(person1.getName === person2.getName);//true//共用同一個函數
|
優點:可以創建多個對象;
缺點:從語義上講,函數getName()不太像是Person對象的方法,辨識度不高。
第四種:構造函數方式
方式一:
function Person(name,age) {
this.name = name;
this.age = age;
this.getName = function ()
{
return this.name;
}
}
var person1 = new Person("Rose",18);
var person2 = new Person("Jack",20);
console.log(person1.name);//Rose
console.log(person2.name);//Jack
console.log(person1.getName === person2.getName); //false//重覆生成函數,為每個對象都創建獨立的函數版本
|
優點:可以創建多個對象;
缺點:重覆生成函數getName(),為每個對象都創建獨立的函數版本。
方式二:
function Person(name,age) {
this.name = name;
this.age = age;
this.getName = getName
;
}
function getName() {
return this.name;
}
var person1 = new Person("Rose",18);
var person2 = new Person("Jack",20);
console.log(person1.name);//Rose
console.log(person2.name);//Jack
console.log(person1.getName === person2.getName); //true//共用同一個函數
|
優點:可以創建多個對象;
缺點:從語義上講,函數getName()不太像是Person對象的方法,辨識度不高。
第五種:原型方式
function Person() {
}
Person.prototype.name = 'Rose';
Person.prototype.age = 18;
Person.prototype.getName = function () {
return this.name;
};
var person1 = new Person();
var person2 = new Person();
console.log(person1.name);//Rose
console.log(person2.name);//Rose//共用同一個屬性
console.log(person1.getName
=== person2.getName);//true//共用同一個函數
|
缺點:它省略了為構造函數傳遞初始化參數,這在一定程式帶來不便;另外,最主要是當對象的屬性是引用類型時,它的值是不變的,總是引用同一個外部對象,所有實例對該對象的操作都會影響其它實例:
function Person() {
}
Person.prototype.name = 'Rose';
Person.prototype.age = 18;
Person.prototype.lessons = ["語文","數學"];
Person.prototype.getName = function () {
return this.name;
};
var person1 = new Person();
person1.lessons.push("英語");
var person2 = new Person();
console.log(person1.lessons);//["語文", "數學", "英語"]
console.log(person2.lessons);//["語文", "數學", "英語"]//person1修改影響了person2
|
第六種:構造函數+原型方式(推薦)
function Person(name,age) {
this.name = name;
this.age = age;
}
Person.prototype.getName = function () {
return this.name;
};
var person1 = new Person('Rose', 18);
var person2 = new Person('Jack', 20);
console.log(person1.name);//Rose
console.log(person2.name);//Jack
console.log(person1.getName === person2.getName);//true//共用原型中定義的方法
|
缺點:屬性定義在構造函數內,方法定義在構造函數外,與面向對象的封裝思想不符。
第七種:構造函數+動態原型方式(推薦)
方式一:
function Person(name,age) {
this.name = name;
this.age = age;
if (typeof
Person._getName === "undefined"){
Person.prototype.getName
= function () {
return this.name;
};
Person._getName = true;
}
}
var person1 = new Person('Rose', 18);
var person2 = new Person('Jack', 20);
console.log(person1.name);//Rose
console.log(person2.name);//Jack
console.log(person1.getName === person2.getName);//true//共用原型中定義的方法
|
方式二:
function Person(name,age) {
this.name = name;
this.age = age;
if (typeof
this.getName !== "function"){
Person.prototype.getName
= function () {
return this.name;
};
}
}
var person1 = new Person('Rose', 18);
var person2 = new Person('Jack', 20);
console.log(person1.name);//Rose
console.log(person2.name);//Jack
console.log(person1.getName === person2.getName);//true//共用原型中定義的方法
|
對象屬性的擴展及刪除
Javascript的對象可以使用 ’.’ 操作符動態的擴展其屬性,可以使用 ’delete’ 關鍵字或將屬性的值設置為
’undefined’ 來刪除屬性。
function Person(name,age) {
this.name = name;
this.age = age;
if (typeof Person._getName
=== "undefined"){
Person.prototype.getName
= function () {
return this.name;
};
Person._getName =
true;
}
}
var person = new Person("Rose",18);
person.job
= 'Engineer';//添加屬性
console.log(person.job);//Engineer
delete person.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屬性,其值為’My
name’,對該值的修改都反正在這個位置
function Person(name,age) {
this.name = name;
this.age = age;
if (typeof Person._getName
=== "undefined"){
Person.prototype.getName
= function () {
return this.name;
};
Person._getName =
true;
}
}
var person = new Person("Rose",18);
Object.defineProperty(person,"name",{configurable:false,writable:false});
person.name
= "Jack";
console.log(person.name);//Rose//重新賦值無效
delete person.name;
console.log(person.name);//Rose//刪除無效
|
註意:
一旦將configurable設置為false,則無法再使用defineProperty將其修改為true(執行會報錯:cannot redefine property : propertyName)
function Person(name,age) {
this.name = name;
this.age = age;
if (typeof Person._getName
=== "undefined"){
Person.prototype.getName
= function () {
return this.name;
};
Person._getName =
true;
}
}
var person = new Person("Rose",18);
Object.defineProperty(person,"name",{configurable:false,writable:false});
person.name = "Jack";
console.log(person.name);//Rose//重新賦值無效
delete person.name;
console.log(person.name);//Rose//刪除無效
Object.defineProperty(person,"name",{configurable:true,writable:true});//Cannot
redefine property: name
|
訪問器屬性
特性:
[configurable]:是否可通過delete操作符刪除重新定義屬性;
[numberable]:是否可通過for-in迴圈查找該屬性;
[get]:讀取屬性時調用,預設:undefined;
[set]:寫入屬性時調用,預設:undefined;
訪問器屬性不能直接定義,必須使用defineProperty()或defineProperties來定義:如下
function Person(name,age) {
this.name = name;
this._age = age;
if (typeof Person._getName
=== "undefined"){
Person.prototype.getName
= function () {
return this.name;
};
Person._getName =
true;
}
}
var person = new Person("Rose",18);
Object.defineProperty(person,"age",{
get:function () {
return this._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)方法可以取得給定屬性的特性;
function Person(name,age) {
this.name = name;
this._age = age;
if (typeof Person._getName
=== "undefined"){
Person.prototype.getName
= function () {
return this.name;
};
Person._getName =
true;
}
}
var person = new Person("Rose",18);
Object.defineProperty(person,"age",{
get:function () {
return this._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;
繼承機制實現
對象冒充
function Father(name) {
this.name = name ;
this.getName = function ()
{
return this.name;
}
}
function Son(name,age) {
this._newMethod = Father;
this._newMethod(name);
delete this._newMethod;
this.age = age;
this.getAge = function ()
{
return this.age;
}
}
var father = new Father("Tom");
var son = new Son("Jack",18);
console.log(father.getName());//Tom
console.log(son.getName());//Jack//繼承父類getName()方法
console.log(son.getAge());//18
|
多繼承(利用對象冒充可以實現多繼承)
function FatherA(name) {
this.name = name ;
this.getName = function ()
{
return this.name;
}
}
function FatherB(job) {
this.job = job;
this.getJob = function ()
{
return this.job;
}
}
function Son(name,job,age) {
this._newMethod = FatherA;
this._newMethod(name);
delete this._newMethod;
this._newMethod = FatherB;
this._newMethod(job);
delete this._newMethod;
this.age = age;
this.getAge = function ()
{
return this.age;
}
}
var fatherA = new FatherA("Tom");
var fatherB = new FatherB("Engineer");
var son = new Son("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()方法
function Father(name) {
this.name = name ;
this.getName = function ()
{
return this.name;
}
}
function Son(name,job,age) {
Father.call(this,name);
this.age = age;
this.getAge = function ()
{
return this.age;
}
}
var father = new Father("Tom");
var son = new Son("Jack","Programmer",18);
console.log(father.getName());//Tom
console.log(son.getName());//Jack//繼承父類getName()方法
console.log(son.getAge());//18
|
多繼承(利用call()方法實現多繼承)
function FatherA(name) {
this.name = name ;
this.getName = function ()
{
return this.name;
}
}
function FatherB(job) {
this.job = job;
this.getJob = function ()
{
return this.job;
}
}
function Son(name,job,age) {
FatherA.call(this,name);
FatherB.call(this,job);
this.age = age;
this.getAge = function ()
{
return this.age;
}
}
var fatherA = new FatherA("Tom");
var fatherB = new FatherB("Engineer");
var son = new Son("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()方法
function Father(name) {
this.name = name ;
this.getName = function ()
{
return this.name;
}
}
function Son(name,job,age) {
Father.apply(this,new Array(name));
this.age = age;
this.getAge = function ()
{
return this.age;
}
}
var father = new Father("Tom");
var son = new Son("Jack","Programmer",18);
console.log(father.getName());//Tom
console.log(son.getName());//Jack//繼承父類getName()方法
console.log(son.getAge());//18
|
多繼承(利用apply()方法實現多繼承)
function FatherA(name) {
this.name = name ;
this.getName = function ()
{
return this.name;
}
}
function FatherB(job) {
this.job = job;
this.getJob = function ()
{
return this.job;
}
}
function Son(name,job,age) {
FatherA.apply(this,new Array(name));
FatherB.apply(this,new
Array(job));
this.age = age;
this.getAge = function ()
{
return this.age;
}
}
var fatherA = new FatherA("Tom");
var fatherB = new FatherB("Engineer");
var son = new Son("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
|
原型鏈方法
function Father() {
}
Father.prototype.name = "Tom";
Father.prototype.getName = function () {
return this.name;
};
function Son() {
}
Son.prototype
= new Father();
Son.prototype.age = 18;
Son.prototype.getAge = function () {
return this.age;
};
var father = new Father();
var son = new Son();
console.log(father.getName());//Tom
console.log(son.getName());//Tom//繼承父類FatherA的getName()方法
console.log(son.getAge());//18
|
混合方式(call()+原型鏈)
function Father(name) {
this.name = name;
}
Father.prototype.getName = function () {
return this.name;
};
function Son(name,age) {
Father.call(this,name);
this.age = age;
}
Son.prototype
= new Father();
Son.prototype.getAge = function () {
return this.age;
};
var father = new Father("Tom");
var son = new Son("Jack",18);
console.log(father.getName());//Tom
console.log(son.getName());//Jack//繼承父類Father的getName()方法
console.log(son.getAge());//18
|
多態機制實現
function Person(name) {
this.name = name;
if (typeof this.getName
!== "function"){
Person.prototype.getName
= function () {
return this.name;
}
}
if (typeof this.toEat
!== "function"){
Person.prototype.toEat
= function (animal) {
console.log( this.getName()
+ "說去吃飯:");
animal.eat();
}
}
}
function Animal(name) {
this.name = name;
if (typeof this.getName
!== "function"){
Animal.prototype.getName
= function () {
return this.name;
}
}
}
function Cat(name) {
Animal.call(this,name);
if (typeof this.eat
!== "function"){
Cat.prototype.eat
= function () {
console.log(this.getName()
+ "吃魚");
}
}
}
Cat.prototype = new Animal();
function Dog(name) {
Animal.call(this,name);
if (typeof this.eat
!== "function"){
Dog.prototype.eat
= function () {
console.log(this.getName()
+ "啃骨頭");
}
}
}
Dog.prototype = new Animal();
var person = new Person("Tom");
person.toEat(new Cat("cat"));//Tom說去吃飯:cat吃魚
person.toEat(new Dog("dog"));//Tom說去吃飯:dog啃骨頭
|