• 
    

    
    

      99热精品在线国产_美女午夜性视频免费_国产精品国产高清国产av_av欧美777_自拍偷自拍亚洲精品老妇_亚洲熟女精品中文字幕_www日本黄色视频网_国产精品野战在线观看 ?

      JavaScript中的面向?qū)ο?/h1>
      2016-10-21 07:03:09賈紅健
      電子技術(shù)與軟件工程 2016年5期
      關(guān)鍵詞:多態(tài)繼承面向?qū)ο?/a>

      賈紅健

      摘 要 在很多編程者的心目中,JavaScript作為一種函數(shù)式腳本語言長期行走在面向?qū)ο笳Z言的邊緣,對于它是否面向?qū)ο竽@鈨煽?,本文通過簡單的示例,回歸面向?qū)ο蟊疽?,從語法角度闡述JavaScript是一種徹底的面向?qū)ο笳Z言以及如何應(yīng)用這種特性。

      【關(guān)鍵詞】JavaScript 面向?qū)ο?封裝 繼承 多態(tài)

      面向?qū)ο蟪绦蛟O(shè)計(OOP)是一種程序設(shè)計范型,同時也是一種程序開發(fā)方法。對象是指類的實例,它將對象作為程序的基本單元,將程序和數(shù)據(jù)封裝其中,以提高軟件的重用性、靈活性和擴(kuò)展性。面向?qū)ο蟪绦蛟O(shè)計推廣了程序的靈活性和可維護(hù)性,并且在大型項目設(shè)計中廣為應(yīng)用。那么,JavaScript(以下簡稱JS)是否是面向?qū)ο笳Z言?答案是:從語法角度來說,是。但是在實踐中相當(dāng)多的開發(fā)者并不嚴(yán)格遵從面向?qū)ο?。面向?qū)ο笕齻€要素:封裝,繼承,多態(tài)。通常JS開發(fā)中這三個要素并不會被完全遵守,請看以下例子。

      //定義個Person類

      function Person(id, name)

      {

      this.id = id; //身份證號

      this.name = name;//姓名

      }

      //實例化一個Person對象

      var user = new Person("321321xxxxxx", "Jack");

      實現(xiàn)封裝了嗎?實現(xiàn)了,但是不很嚴(yán)格。盡管user變量包含了id, name兩個成員,但這兩個成員都可以被任意更改,比如代碼:user.name = “Rose”,沒有Java、c++中類似private的關(guān)鍵字來控制訪問權(quán)限。繼承呢?JS中沒有顯式關(guān)鍵字來表示繼承,像Java中有extends、implements,C++中有”:”。至于多態(tài),是基于繼承的,沒有繼承哪來多態(tài)。所以看起來JS對面向?qū)ο蟮闹С植缓冒?,那為什么還要說它是面向?qū)ο蟮恼Z言呢?下面就從面向?qū)ο笕齻€要素:封裝,繼承,多態(tài)逐條講解JS對它們的支持。

      1 封裝

      封裝是說,不只是讓你能用簡化的視圖來看復(fù)雜的概念,同時還不能讓你看到復(fù)雜概念的任何細(xì)節(jié),你能看得到的就是你能全部得到的“代碼大全”。將一組變量放到一個對象中并不是完全的封裝,所以前文所說示例中的封裝不嚴(yán)格,因為不想暴露的成員變量還是暴露了。一般OO語言中成員變量、函數(shù)都至少有三個訪問級別:public所有對象可見;protected自身、子類可見;private自身可見。JS無法支持到如此詳細(xì),僅僅支持public、private。以下示例是在JS類中定義private變量,public方法。

      function Person(id, name)

      {

      varmId; //身份證號

      varmName; //姓名

      mId = id;

      mName = name;

      //私有函數(shù),通過身份照Id來取得生日

      functiongetBirthday(){}

      //讀取姓名

      this.getName = function(){returnmName;}

      //修改姓名,人是可以改名字的

      this.setName = function(name){mName = name;}

      //id沒有set方法,身份證號碼是不能改的

      this.getId = function(){returnmId;}

      this.print = function(){console.log("name:" + mName + " id: " + id);}

      }

      var user = new Person("P1", "Jack");

      private成員變量使用var關(guān)鍵字聲明放在Person函數(shù)內(nèi)部,可以防止對象外部的函數(shù)直接訪問,而成員函數(shù)可以訪問,從而實現(xiàn)了private成員變量。private成員函數(shù)getBirthday也只有成員函數(shù)才能訪問,類外面是訪問不了的。這個實現(xiàn)方法的原理是使用閉包,篇幅原因不對閉包進(jìn)行展開講解。實現(xiàn)了private就是完成了封裝了嗎?沒有。

      當(dāng)實例化一個Person對象之后,外部盡管訪問不了private變量,但是卻可以惡意或不小心擴(kuò)展、篡改這個對象,進(jìn)而導(dǎo)致軟件缺陷。

      比如這樣的代碼,getName函數(shù)將無法返回正確的結(jié)果:

      var user = new Person("P1", "Jack");

      user.getName = function() {return "foo";}

      盡管這種情況比較少,但是當(dāng)軟件變得復(fù)雜,人員規(guī)模變大后,很可能出問題,這是墨菲定律所決定的(墨菲定律:如果有兩種或兩種以上的方式去做某件事情,而其中一種選擇方式將導(dǎo)致災(zāi)難,則必定有人會做出這種選擇。)。

      為了解決這個問題,則要使用函數(shù)Object.freeze

      var user = new Person("P1", "Jack");

      Object.freeze(user); //凍結(jié)對象

      user.getName = function() {return "foo";}

      這個函數(shù)調(diào)用之后,后面的修改user的代碼將不起作用。不過很可惜,這個函數(shù)在IE8,或者更低的IE版本下不支持

      2 繼承

      繼承是OO設(shè)計中支持復(fù)用的基石,可以很方便的復(fù)用、擴(kuò)展已有功能。JS中沒有顯式支持繼承的關(guān)鍵字,但可把子類的prototye定義為父類的實例來實現(xiàn)。接上面的Person例子,定義一個子類Programmer。

      function Programmer(id, name, skill)

      { //id, name 的意義和Person一樣

      Person.call(this, id, name); //調(diào)用父類構(gòu)造函數(shù)

      varmSkill = skill; //數(shù)組,表示技能

      this.getSkill = function() {returnmSkill;}

      this.addSkill = function(s) {mSkill.push(s);}

      this.useSkill = function(){console.log(mSkill);}

      }

      //將子類的prototype指向父類的實例,否則instanceof操作將出錯

      Programmer.prototype = newPerson();

      //設(shè)置constructor,否則子類的constructor將是父類的構(gòu)造函數(shù)

      Programmer.prototype.constructor = Programmer;

      var nerd = newProgrammer("321321aaaa", "Linus",[ "c++", "JS" ]);

      這樣的操作就實現(xiàn)了繼承。但由于無法實現(xiàn)protected權(quán)限,導(dǎo)致子類無法訪問父類的private變量。對于父類成員的訪問,子類和其他的類并沒有更多的權(quán)限。所以將父類的成員設(shè)置為public還是private,要視情況決定了。

      3 多態(tài)

      面向?qū)ο笾卸鄳B(tài)即意味著子類的某一功能可以有區(qū)別于父類的實現(xiàn),并且同一父類的不同子類的實現(xiàn)也可以不一樣。多態(tài)在JS中實現(xiàn)很簡單,直接在子類中用同名函數(shù)重寫父類函數(shù)即可。如下所示,在Programmer類重寫print函數(shù),將skill也打印出來:

      this.print = function(){console.log("name: " + this.getName() + " id: " + this.getId() + " skill: " + JSON.stringify(this.getSkill()));}

      4 其他元素

      面向?qū)ο笾羞€有一些其他元素,如重載、靜態(tài)變量、多繼承/接口繼承以及弱類型語言中的鴨式辯型,此處僅做簡要介紹。

      重載可在JS函數(shù)內(nèi)部判斷參數(shù)個數(shù)、類型來執(zhí)行不同功能,以此實現(xiàn)重載,代碼如下:

      functionfoo(v)

      {

      if(typeof(v) == "number"){console.log(v + " is a number");}

      else if (typeof(v) == "string"){console.log(v + " is a string");}

      else if (typeof(v) == "boolean"){console.log(v + " is a boolean");}

      }

      靜態(tài)變量可通過在類的prototype上面定義變量來實現(xiàn),代碼如下:

      Person.prototype.staticVar= "test";

      多繼承/接口繼承是指子類有多個父類,兼有多個父類的功能。JS中沒有很好的辦法來實現(xiàn),但由于JS是弱類型語言,只要在一個對象中添加某一個類型的方法就可以冒充該類型,即鴨式辯型。

      5 小結(jié)

      以上討論了面向?qū)ο笕卦贘S中的實現(xiàn)。我們討論JS面向?qū)ο蟮哪康牟⒎枪膭畲蠹揖帉慜O的JS代碼,而是當(dāng)你認(rèn)真考慮發(fā)現(xiàn)OO更加適合當(dāng)下的需求之后,用本文提供的方法可以寫出更健壯的JS代碼。

      作者單位

      中國郵政集團(tuán)公司南京分公司 江蘇省南京市 210029

      猜你喜歡
      多態(tài)繼承面向?qū)ο?/a>
      分層多態(tài)加權(quán)k/n系統(tǒng)的可用性建模與設(shè)計優(yōu)化
      參差多態(tài)而功不唐捐
      面向?qū)ο蟮挠嬎銠C(jī)網(wǎng)絡(luò)設(shè)計軟件系統(tǒng)的開發(fā)
      電子測試(2018年15期)2018-09-26 06:01:34
      面向?qū)ο蟮臄?shù)據(jù)交換協(xié)議研究與應(yīng)用
      淺談杜審言、杜甫的祖孫關(guān)系:推崇、繼承、發(fā)展
      人間(2016年28期)2016-11-10 21:48:10
      淺論紫砂藝術(shù)的繼承與創(chuàng)新
      論電影《暮光之城》的哥特文化
      氣象科技史研究領(lǐng)域又一重要學(xué)術(shù)成果
      面向?qū)ο骔eb開發(fā)編程語言的的評估方法
      人多巴胺D2基因啟動子區(qū)—350A/G多態(tài)位點(diǎn)熒光素酶表達(dá)載體的構(gòu)建與鑒定及活性檢測

      平原县| 图们市| 平利县| 曲阳县| 东阳市| 南乐县| 渝中区| 和政县| 云浮市| 荔浦县| 成都市| 五指山市| 梅河口市| 奈曼旗| 达尔| 富裕县| 通化市| 姜堰市| 屯昌县| 广昌县| 乐清市| 广平县| 威信县| 安阳市| 宝清县| 略阳县| 凤凰县| 嵊州市| 疏勒县| 宜兰市| 镇宁| 信阳市| 固始县| 营山县| 桂阳县| 抚顺县| 哈尔滨市| 肥东县| 淳安县| 杂多县| 宁安市|