亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 開發 > JS > 正文

JavaScript面向對象的程序設計(犯迷糊的小羊)

2024-05-06 16:44:37
字體:
來源:轉載
供稿:網友

導語

前面的系列文章,基本把JavaScript的核心知識點的基本語法、標準庫等章節講解完;
本章開始進入JavaScript核心知識點的高級部分——面向對象的程序設計,這一部分的內容將會對對象這一數據類型做進一步的深化理解,并且講述幾種創建對象的設計模式以及JavaScript獨特的繼承機制;

1.理解對象和面向對象的程序設計

1.1 面向對象的程序設計

"面向對象編程"(Object Oriented Programming,縮寫為OOP)本身是一種編程的思維模式,它把世界的一切看作是對象的集合,世界的運轉就是靠一個個對象分工、合作的結果,體現一切皆“對象”思想;
而在程序設計當中,面向對象編程就可以看做編寫各個具有特定功能的對象(模塊)并將它們進行有機的分工合作,即目前的模塊化編程就是面向對象的程序設計的實際應用;

1.2 理解對象

對象在前面的系列文章中曾經提到,從數據特征上看,對象是無序屬性(鍵值對)的集合;
我們可以使用字面量和構造函數的方式去創建一個最為簡單的對象:

var person = new Object();person.name = "teren";person.age = 18;person.greet = function(){   console.log("hello "+this.name);}var teren = { name:"teren", age:18, greet:function(){   console.log("hello "+this.name); }}

通常創建一個簡單的對象,都是采用字面量的方式;
上面的對象就是對現實對象的一種抽象表達;

1.3 對象的屬性類型

前面章節中我們使用delete命令可以刪除一些對象的屬性,有一些又不可以,使用Object.keys()方法只能遍歷可枚舉屬性,那么對象的屬性是否有一些特性是我們尚未了解的呢?
ES5提供了一種只有內部才用的特性(attribute)去描述對象的屬性(property)的各種特性,使用[[attribute]]表示,在JavaScript中不能直接訪問它們;
一個我們非常熟悉的栗子就是Number構造函數構造出來的實例對象;

js,面向對象,程序設計

我們無法直接訪問num.[[PrimitiveValue]],這一屬性,只能通過num.valueOf()訪問該值;

ES5中定義對象屬性的兩種特性,數據特性和訪問器特性,對象屬性可以兼備這兩種特性;

數據特性定義對象的屬性值的特性,一個屬性值可以包括以下四個數據特性:

[[Value]]:存放屬性值;[[Writable]]:是否可寫屬性;[[Enumerable]]:是否為可枚舉屬性;[[Configurable]]:是否可用delete命令刪除;

訪問器特性定義對象的屬性在訪問屬性和設置屬性時調用的兩個函數getter和setter;

[[Get]]:訪問屬性時調用的函數;
[[Set]]:設置屬性時調用的函數;

下面以一個實例對象直接講解這兩個特性:

//數據特性;var teren = {};Object.defineProperty(teren,{  value:"teren",  writable:false,  enumerable:true,  configurable:true})//訪問器特性;//html<div id="name"></div>//jsvar obj = Object.defineProperty({},"name",{set:function(name){ document.getElementById('name').innerHTML=name},get:function(){ console.log( document.getElementById('name').innerHTML  )  },})obj.name = "hello world"obj.name

[demo]

Object.defineProperties可以一次性配置對象的多個屬性;

js,面向對象,程序設計

2. 創建對象的方式

上一節我們對面向對象的程序設計思想和對象有了初步理解,這一節我們深入探討一下對象的創建方式及其優缺點;

創建對象的不同方式也可以簡單的稱作設計模式,不同的設計模式在實際編程應用中起到不同的作用;

2.1 單例模式

單例模式就是產生一個類的唯一實例對象,它能夠確保您只有一個對象實例能夠實際派上用場;

單例模式下,創建對象方式如下:

var singleton = { attr:1, method:function(){  return this.attr }}var ex1 = singleton;var ex2 = singleton;ex1 === ex2//true

上述創建單例的方式:

優點:使用非常簡捷;
缺點:缺乏封裝,成員暴露,初始化時占用資源;

可以使用閉包方式解決這一問題:

var substance = (function(){ var unique;  function init(){  var type;    return {   setType:function(t){    return type = t;   }  } } return {  getInstance:function(){   if(!unique){    unique = init();   }   return unique;  }  }})();var Adam = substance.getInstance();var Eve = substance.getInstance();Adam === EveAdam.setType('Man')//Man

js,面向對象,程序設計

2.2 工廠模式

單例模式只能創作單個實例對象,也就是說如果將該實例對象賦予多個變量時,會存在對象的引用問題,即修改其中一個變量會影響到另一個變量;
有時我們需要創造多個結構相似的對象,只有部分屬性有所區別,這時候工廠模式派上用場;

工廠模式的設計思想就是能夠像工廠一樣批量生產出相似屬性和方法的對象,使用工廠模式能解決多個相似的問題,例如創造多個彈窗(只是標題不同);

function person(name,age){ var obj = new Object(); obj.name = name; obj.age = age; obj.greet = function(){   return "hello "+this.name; }; return obj}var Adam = person("Adam",18);var Eve = person("Eve",20);

上述工廠模式:

優點:能批量生產結構類似的對象;封裝創建對象的細節;
缺點:未能解決對象的類型,即由哪個構造函數創建的;

2.3 構造函數模式

構造函數可以創建特定類型的對象,類似之前的Array、RegExp等原生對象都能創造特定類型的實例對象;

function Person(name,age){ this.name = name; this.age = age; this.greet = function(){   return "hello "+this.name; }}var p1 = new Person('Adam',18);var p2 = new Person('Eve',20);

使用構造函數模式就能夠解決實例對象由誰創建的問題;

js,面向對象,程序設計

上述代碼和工廠模式的區別在于:

1.沒有顯示創建新對象;
2.直接將屬性和方法賦給this對象;
3.沒有return語句;
4.函數名開頭大寫以區別普通函數;
5.使用new操作符去創建對象實例;

new操作符的原理

使用new操作符去調用函數和直接調用函數不同,其new操作符的運行函數的過程為:

創建一個新對象;
將構造函數的作用域賦給新對象并執行構造函
內的代碼;
返回新對象;
使用代碼表示如下:

function Person(name,age){ this.name = name; this.age = age; this.greet = function(){   return "hello "+this.name; }}function createPerson(name,age){  var o = new Object();  Person.call(o,name,age);  return o;}var p1 = createPerson('Adam',18);var p2 = createPerson('Eve',20);

使用構造函數模式創建對象的優缺點在于:

優點:能夠識別對象屬于的構造函數;
缺點:如果存在不同實例對象共享的屬性和方法,使用構造函數模式則會浪費內存;

【注】
關于this關鍵字的更多知識點可以參見【what's this】;
構造函數如果不用new操作符調用和普通函數是一樣的;

2.4 原型模式

每個函數都有一個prototype原型屬性,這個原型屬性可以部署特定類型的實例共享的屬性和方法;

function Person(){}}Person.prototype.greet = function(){ return "hello "+this.name;

將原來的greet函數部署在Person函數的prototype原型屬性上,這樣p1和p2可以共享該方法,而不像構造函數模式每創建一個實例就增加一個greet方法浪費內存;

【注】
關于原型對象的更多理解詳見下一節——JavaScript的繼承機制;

使用原型模式創建對象的優缺點在于:

優點:對于每個實例的共享屬性和方法能夠較好實現;
缺點:單獨采用原型模式將無法區分不同實例的私有屬性;

2.5 混合模式

混合模式,就是綜合構造函數模式和原型模式的優缺點,構造函數模式部署實例的私有屬性,原型模式部署實例的公有屬性;

function Person(name,age){  this.name = name;  this.age = age;}Person.prototype.greet = function(){  return "hello "+this.name;}var p1 = new Person("Adam",18);var p2 = new Person("Eve",20);

混合模式是目前使用最廣泛、認同度最高的一種創建自定義類型(類)的設計模式;

【注】
當然,設計模式不僅僅上述所提到,還有更加精深可以參考《設計模式》一書以及之前小羊寫的一篇文章《設計模式梗概》;

3.JavaScript的繼承機制

上一節我們通過創建對象的不同模式,隱式引出了原型對象的概念,這一節中我們將詳細了解一下原型對象、原型鏈及其實現的繼承機制;

前面,我們從數據特征上看,知道對象是無序屬性(鍵值對)的集合;
現在,我們可以從面向對象的角度看,任何對象都是更為抽象的對象的實例,可以理解為類的概念;
從這個角度理解,我們現在可以重新定義一下對象和類的含義:
對象可以說是對現實事物的抽象,對象封裝了屬性和方法,屬性值指的是對象的狀態,方法指的是對象的行為;
類是提供一種模板的‘對象',它是對象的抽象;
舉個簡單的栗子:

function Person(name,age){  this.name = name;  this.age = age;}Person.prototype.greet = function(){  return "hello "+this.name;}var p1 = new Person("Adam",18);var p2 = new Person("Eve",20);

上述代碼表明,p1和p2兩個實例是對現實Adam和Eve的抽象,而“類”Person又是對2個實例的抽象,為創建相似結構的人提供標準的模板;
[注]ES6之前JavaScript中沒有類,在ES6中定義了類;

3.1 原型對象

在上一節的原型模式中,我們提到每個函數都有一個prototype屬性,這個屬性指向函數的原型對象,可以部署特定類型的實例共享的屬性和方法;

更為深入理解prototype原型對象,prototype原型對象不僅可以部署特定類型的實例共享的屬性和方法,而且還是實現JavaScript繼承的關鍵;

只要創建一個新函數就會為該函數創建一個prototype屬性,每個prototype屬性自動獲得一個constructor屬性,該屬性指向prototype屬性所在的函數指針;

當使用構造函數創建一個實例時,該實例內部包含一個內部屬性__proto__指向構造函數的原型對象;

由此,一個簡單的繼承便產生了;
以下面代碼為例:

function Person(name,age){  this.name = name;  this.age = age;}Person.prototype.greet = function(){  return "hello "+this.name;}var p1 = new Person("Adam",18);var p2 = new Person("Eve",20);

js,面向對象,程序設計

構造函數創建之后,自動創建一個prototype屬性,prototype原型對象下有一個默認的constructor屬性指向prototype屬性所在的函數Person中;
在prototype原型對象上部署greet方法,實例p1的內部屬性__proto__指向構造函數Person.prototype,由此繼承了構造函數的原型對象上的greet方法;

【注意】

  • 實例的__proto__指向構造函數的prototype原型對象實現繼承,這種聯系存在于實例與構造函數的原型對象之間而不是構造函數之間;
  • 當js引擎解析對象的屬性時,先會搜索對象本身的屬性,如果沒有則會去搜索__proto__指向的原型對象上的屬性,直到找到為止,如果在對象本身定義的屬性和原型對象上的具有相同屬性名,則在讀取該屬性時,自身屬性會屏蔽原型對象上的屬性;
function Person(name,age){  this.name = name;  this.age = age;}Person.prototype.greet = function(){  return "hello "+this.name;}var p1 = new Person("Adam",18);p1.greet()//hello Adam;p1.greet = function(){  return "hello world"}
js,面向對象,程序設計
修改構造函數的原型對象可以直接使用點操作,效果是直接在原來的原型對象上增加屬性,有時需要增加的屬性太多是,點操作就顯得太麻煩,可以采用重置原型對象的方法:
function Person(name,age){  this.name = name;  this.age = age;}Person.prototype = { constructor:Person, greet1:function(){}, greet2:function(){}, greet3:function(){}};var p1 = new Person("Adam",18);Person.prototype.constructor.name//"Object"

需要注意的是,重置原型對象后,要重新為原型對象的constructor的屬性指回Person構造函數;
如果不重置constructor的話,那么此時的Person.prototype是由字面量創建的對象,字面量創建的對象默認的構造函數是Object;

3.2 原型鏈

上面我們只定義一個構造函數,實現一次繼承;如果存在多個構造函數,它們之間也存在繼承關系,那么就會形成一條關于繼承的原型鏈;

function SuperType(name,age){  this.name = name;  this.age = age}SuperType.prototype.greet = function(){  return "hello "+this.name}function SubType(name,age,height){  SuperType.call(this,name,age);  this.height = height;}SubType.prototype = Object.create(SuperType.prototype);SubType.prototype.constructor = SubType;SubType.prototype.method = function(){return 1;}var instance = new SubType('teren',18,180)

上面就是一個最為常用的實現多個類間繼承的設計模式;
使用Object.create(SuperType.prototype)的優缺點在于:

優點:能夠創建一個新的SuperType.prototype對象賦給SubType.prototype,修改SubType.prototype這個而不影響原來構造函數SuperType.prototype;
缺點:雖然擁有子類的prototype和父類的prototype值是相同的,但內存不同,從而切斷子類和父類之間的類型;

js,面向對象,程序設計

還可以使用SubType.prototype =new SuperType()實現相同效果,其優缺點在于:

優點:能夠體現子類和父類的繼承關系;
缺點:子類具有父類的私有屬性;

js,面向對象,程序設計

所以,一般在實際實現原型鏈時使用Object.create()方法,而理解原型鏈時使用new SuperType()方法;js,面向對象,程序設計

3.3 與原型對象相關的方法

遍歷對象屬性方法
Object.keys()Object.getOwnPropertyNames()用于遍歷對象自身而不是繼承的屬性名,返回一個數組,其中Object.keys()只返回可枚舉屬性;

js,面向對象,程序設計

in用于檢查一個對象是否具有某個屬性。它不區分該屬性是對象自身的屬性,還是繼承的屬性;
for...in用于遍歷對象的所有可枚舉屬性(不管是自身的還是繼承的)

js,面向對象,程序設計

如果只遍歷自身的屬性,可以使用如下代碼:

for (var key in instance){ if(instance.hasOwnProperty(key)){   console.log(key) }}

判斷屬性是否為自身的方法

Object.prototype.hasOwnProperty()返回一個布爾值,用于判斷某個屬性定義在對象自身,還是定義在原型鏈上;

js,面向對象,程序設計

設置和獲取實例對象的原型對象的方法

Object.getPropertyOf()返回一個實例對象的原型對象;
Object.setPropertyOf(obj,prototype)可傳兩個參數,第1個為現有參數,第2個為原型對象;

js,面向對象,程序設計

判斷一個對象是否為另一個對象的原型對象

Object.prototype.isPrototypeOf()用于判斷一個對象是否是另一個對象的原型;

js,面向對象,程序設計

小結

通讀本文,我們可以知道:

 

  • 面向對象編程時一種思維模式,它把世界的一切看做是對象的集合,世界的運作是一個個對象分工合作的結果;映射到程序設計中,就是編寫各個具有特定功能的對象(模塊),并將它們有機整合使程序得以運作;
  • 對象從數據特征角度看,是無序鍵值對的集合,對象的屬性具有兩種特性——數據特性和訪問器特性;
  • 創建對象的不同方式可以稱為設計模式,本文簡單講解了單例模式、工廠模式、構造函數模式、原型模式、混合模式等;
  • 從面向對象角度看,對象可以說是對現實事物的抽象,類是對對象的抽象;
  • 每個函數都有一個原型對象prototype,既可以部署特定類型實例的共享屬性和方法,也是JavaScript實現繼承的關鍵;
  • prototype原型對象有一個constructor屬性,該屬性指向prototype所在的函數指針;
  • 每當使用構造函數創建一個實例時,該實例內部包含一個內部屬性__proto__指向構造函數的原型對象,由此實現簡單的繼承;
  • 當A構造函數是B構造函數的實例時,由此就會形成一條原型鏈,即
    A構造函數的實例對象C的__proto__指向A構造函數的原型對象prototype,A構造函數prototype的__proto__指向B構造函數的原型對象prototype,B構造函數prototype的__proto__指向Function構造函數的prototype,Function的prototype的__proto__指向Object的prototype;
  • 與原型對象的相關方法包括:Object.keys()和Object.getPropertyNames()、for...in方法,Object.getPrototypeOf()和Object.setPrototypeOf()方法,Object.prototype.hasOwnProperty()和Object.prototype.isPrototypeOf()方法;

參考資料

《JavaScript高級程序設計(第3版)》
《JavaScript標準參考教程》——阮一峰


注:相關教程知識閱讀請移步到JavaScript/Ajax教程頻道。
發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
2019中文在线观看| 欧美日韩国产中字| www日韩欧美| 中文字幕在线亚洲| 欧洲美女7788成人免费视频| 欧美亚洲另类制服自拍| 中文字幕在线看视频国产欧美在线看完整| 在线成人一区二区| 亚洲性无码av在线| 午夜精品视频在线| 91地址最新发布| 国产亚洲视频在线观看| 日韩精品在线观| 日韩精品免费在线视频观看| 中文字幕国产日韩| 亚洲xxxx做受欧美| 国产精品久久久久91| 亚洲嫩模很污视频| 热久久免费国产视频| 日韩在线观看免费高清完整版| 亚洲色图av在线| 色琪琪综合男人的天堂aⅴ视频| 亚洲a成v人在线观看| 亚洲精品中文字| xxxxx91麻豆| 欧美激情女人20p| 欧美大片网站在线观看| 亚洲老头老太hd| 国产婷婷色综合av蜜臀av| 蜜月aⅴ免费一区二区三区| 日韩中文字幕国产| 色yeye香蕉凹凸一区二区av| 国产一区二区在线免费| 久久99热精品| 亚洲人成在线播放| 欧美视频一二三| 欧美一级免费看| 宅男66日本亚洲欧美视频| 欧美色视频日本版| 国产欧美一区二区| 亚洲wwwav| 国外成人免费在线播放| 欧美国产日韩一区二区在线观看| 国产91九色视频| 久久99热这里只有精品国产| 91精品国产综合久久男男| 欧美日韩在线视频一区二区| 日本精品视频在线| 亚洲成人aaa| 国产日韩欧美自拍| 国产精品黄色影片导航在线观看| 欧美夜福利tv在线| 韩剧1988在线观看免费完整版| 少妇高潮久久77777| 亚洲美女av在线| 精品呦交小u女在线| 国产精品女视频| 爱福利视频一区| 亚洲福利视频免费观看| 国产不卡av在线免费观看| 国产精品啪视频| 成人看片人aa| 久久久国产91| 欧美xxxx做受欧美.88| 97精品欧美一区二区三区| 欧美精品激情在线观看| 亚洲免费一级电影| 国产男女猛烈无遮挡91| 亚洲午夜激情免费视频| 久久久亚洲福利精品午夜| 最近中文字幕mv在线一区二区三区四区| 亚洲国产精品va在线看黑人动漫| 亚州成人av在线| 欧美在线视频在线播放完整版免费观看| 精品女厕一区二区三区| 亚洲va国产va天堂va久久| 欧美性猛交xxxx乱大交| 成人黄色免费在线观看| 久久久av免费| 日韩久久午夜影院| 精品偷拍各种wc美女嘘嘘| 欧美性猛交视频| 日韩av片免费在线观看| 亚洲乱码国产乱码精品精天堂| 欧美丝袜第一区| 精品国产一区二区在线| 欧美黑人一区二区三区| 一区二区三区在线播放欧美| 成人性生交大片免费观看嘿嘿视频| 亚洲欧美另类自拍| 国产成人精品在线播放| 国产精品18久久久久久麻辣| 国产视频久久久| 欧美裸体xxxx极品少妇软件| 久久久久久久久久av| 麻豆乱码国产一区二区三区| 日韩有码在线电影| 日韩av毛片网| 亚洲自拍偷拍一区| 国产精品视频自在线| 亚洲美女又黄又爽在线观看| 国产日韩中文在线| 亚洲电影免费观看高清完整版| 国产精品久在线观看| 亚洲国产精品va在线观看黑人| 日韩精品有码在线观看| 91精品在线看| 亚洲精品自拍偷拍| 国产91精品高潮白浆喷水| 97人人爽人人喊人人模波多| 狠狠躁夜夜躁人人躁婷婷91| 夜夜嗨av色一区二区不卡| 国产欧美日韩丝袜精品一区| 国产精品久久久久久久久久久久久久| 久久精品成人欧美大片| 日本欧美黄网站| 亚洲尤物视频网| 狠狠操狠狠色综合网| 亚洲精品成人免费| 国产亚洲欧美另类中文| 欧美电影在线免费观看网站| 久久精品国产一区二区电影| 国产精品自产拍高潮在线观看| 日韩大陆欧美高清视频区| 久久伊人色综合| 亚洲国产精品人久久电影| 久久人人爽人人爽爽久久| 日韩精品中文字幕在线观看| 日韩av电影在线网| 精品视频—区二区三区免费| 琪琪亚洲精品午夜在线| 亚洲欧美日本精品| 中文字幕亚洲天堂| 成人深夜直播免费观看| 欧美激情xxxx| 91精品久久久久| 欧美性xxxx极品hd满灌| 亚洲美女视频网| 欧美成人精品在线| 国外色69视频在线观看| 26uuu日韩精品一区二区| 中文字幕欧美视频在线| 日韩精品视频在线免费观看| 美女啪啪无遮挡免费久久网站| 亚洲国产另类 国产精品国产免费| 亚洲成人黄色在线| 亚洲一区亚洲二区亚洲三区| 秋霞av国产精品一区| 日本成人免费在线| 91精品国产777在线观看| 日韩亚洲欧美中文在线| 午夜精品国产精品大乳美女| 成人在线免费观看视视频| 国产福利视频一区| 色伦专区97中文字幕| 国产精品视频免费在线观看| 亚洲国产成人精品久久久国产成人一区| 影音先锋欧美精品| 国产精品一区二区三区在线播放| 国产午夜精品久久久| 亚洲精品丝袜日韩| 色综合色综合网色综合| 国产精品丝袜白浆摸在线| 亚洲欧洲午夜一线一品|