首頁  >  文章  >  web前端  >  JavaScript中關於物件導向思想的介紹

JavaScript中關於物件導向思想的介紹

黄舟
黄舟原創
2017-08-22 11:07:36971瀏覽

下面小編就為大家帶來一篇老生常談javascript的物件導向想法。小編覺得蠻不錯的,現在就分享給大家,也給大家做個參考。一起跟著小編過來看看吧

物件導向的三大基本特性

封裝(把相關的資訊(無論資料或方法)儲存在物件中的能力)

繼承(由另一個類別(或多個類別)得來類別的屬性和方法的能力)

多態(一個物件在不同情況下的多種形態)

定義類別或物件

#第一種:基於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啃骨头

以上是JavaScript中關於物件導向思想的介紹的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn