整合營銷服務(wù)商

          電腦端+手機端+微信端=數(shù)據(jù)同步管理

          免費咨詢熱線:

          JavaScript系列-1-面向?qū)ο?/h1>
          JavaScript系列-1-面向?qū)ο?/br>

          向過程和面向?qū)ο缶幊谈攀?/h1>

          面向過程編程就是分析出解決問題的步驟,然后使用函數(shù)把這些步驟一步步實現(xiàn),重心放在完成的每個過程上。

          面向?qū)ο髣t是以封裝的思想,將問題分析得到的數(shù)據(jù)封裝成一個個的對象,然后通過對對象的操作來完成相應(yīng)的功能。

          舉個栗子:廚師炒菜

          以面向過程的思想來分析應(yīng)該分為下面幾個步驟:

          ? 1.檢查食材是否齊全 2.如果不不夠,去菜市場買菜 3.洗菜 4.開火 5.按炒菜(按順序放入相應(yīng)的食材,調(diào)料等) 6.出鍋裝盤

          以面向?qū)ο蟮乃枷敕治鰟t是這樣的:

          ? 1.廚師,檢查食材,炒菜 2.采購員,去菜市場買菜 3.墩子,洗菜,切菜,備菜

          ? 通過調(diào)用上面對象中的行為方法即可完成炒菜的整個過程

          從上面的例子可以看出,面向?qū)ο蠛兔嫦蜻^程最大的不同在于,面向?qū)ο箨P(guān)心的是由哪些對象,每個對象應(yīng)該有哪些功能,而面向過程關(guān)心的是實現(xiàn)過程中的每個步驟。

          那么這兩種思想到底孰優(yōu)孰劣呢?從表面上看,貌似面向?qū)ο蟾茫瑸槭裁茨兀恳驗樗耆衔覀兊恼K季S方式,所以在接受度方面,面向?qū)ο蟮乃枷肟隙ㄊ歉谩5敲嫦蜻^程也有他的優(yōu)勢,就是靈活便捷,而面向?qū)ο笙鄬碚f會更耗資源,更慢一點。

          所以,至于以后使用哪一種,這就需要看我們的具體需求,根據(jù)不同的需求做不同的選擇。

          面向?qū)ο缶幊痰南嚓P(guān)概念

          通過上面的分析,我們知道面向?qū)ο蟮闹攸c在于功能分析和對象的封裝上,那么最終我們得到的對象的結(jié)構(gòu)是怎樣的,我們繼續(xù)往下學(xué)習(xí)。

          比如,我通過對人的分析得到,每個人都有姓名,年齡,性別等屬性,同時也有吃飯睡覺等行為,那么用JS可以做如下的封裝:

          var p={
              name : "xiao song",
              age : 10,
              sex : 1,
              eat : function () {
                  console.log("吃飯");
              },
              sleep : function () {
                  console.log("睡覺");
              }
          }
          console.log(p.name);//訪問對象的屬性
          p.eat();//訪問對象的方法
          

          上面的p則表示一個對象,其中的name / age / sex稱之為對象的屬性,eat / sleep 稱之為對象的方法,我們通過訪問該對象的屬性或者方法達(dá)到相應(yīng)的目的即可。

          DOM操作相關(guān)知識點復(fù)習(xí)

          在學(xué)習(xí)了html之后我們發(fā)現(xiàn),html文檔中的內(nèi)容其實就是由一堆的標(biāo)簽組成,由于在后面的課程中需要使用到html,所以我們先大致的回顧一下它的結(jié)構(gòu)。

          <div id="div1" class="clz1">
              <h3>H5-JS面向?qū)ο?lt;/h3>
          </div>
          

          div h3:元素節(jié)點

          id class:屬性節(jié)點

          H5-JS面向?qū)ο螅何谋竟?jié)點

          一個html文檔主要由這三部分組成,DOM(文檔對象模型)是對操作這些元素的屬性或者方法進(jìn)行了封裝,從而達(dá)到方便快捷的操作html的目的。

          獲取元素對象:document.getElementById(“div1”)

          訪問元素的屬性:div1.className

          訪問元素的文本內(nèi)容:div1.innerText

          增刪改元素:div1.appendChild(newNode)

          下面,我們就通過這些API來講解說明面向?qū)ο笙嚓P(guān)的內(nèi)容。

          創(chuàng)建并設(shè)置標(biāo)簽(面向過程)

          需求1:創(chuàng)建三個div元素,并設(shè)置邊框,背景色,文本及字體顏色

          for (var i=0; i < 3; i++) {
          	var div=document.createElement("div");
          	div.innerText="div"+i;
          	div.style.backgroundColor="green";
          	div.style.border="1px solid #000";
          	div.style.color="white";
          	document.body.appendChild(div);
          }
          

          需求2:為頁面中存在的三個P元素設(shè)置邊框,背景色,文本及字體顏色

          <p>我是P1</p>
          <p>我是P2</p>
          <p>我是P3</p>
          <script>
              var ps=document.getElementsByTagName("p");
              for (var i=0; i < ps.length; i++) {
                  ps[i].style.backgroundColor="red";
                  ps[i].style.border="1px solid #000";
                  ps[i].style.color="white";
              }
          </script>
          

          需求3:獲取頁面上三個class=“test”的元素,設(shè)置邊框,背景色,文本及字體顏色

          <h3 class="test">我是標(biāo)題1</h3>
          <h3 class="test">我是標(biāo)題2</h3>
          <h3 class="test">我是標(biāo)題3</h3>
          
          <script>
          	var tests=document.getElementsByClassName("test");
          	for (var i=0; i < tests.length; i++) {
          	    tests[i].style.backgroundColor="yellow";
          	    tests[i].style.border="1px solid #000";
          	    tests[i].style.color="red";
          	}
          </script>
          

          上面的代碼是以面向過程的思想完成的,可以看到,兩個需求中的每個步驟都是我們一步一步完成的,問題很明顯,代碼大量的冗余,這種代碼后期不好維護(hù)。

          創(chuàng)建并設(shè)置標(biāo)簽(函數(shù)封裝)

          對于上面重復(fù)的代碼,我們可以使用函數(shù)對其進(jìn)行封裝

          <script>
              function setStype(eles,bgcolor) {
                  for (var i=0; i < eles.length; i++) {
                      eles[i].style.backgroundColor=bgcolor;
                      eles[i].style.border="1px solid #000";
                      eles[i].style.color="white";
                  }
              }
              function getElementsByTagName(tagName) {
                  return document.getElementsByTagName(tagName);
              }
              function getElementsByClassName(className) {
                  return document.getElementsByClassName(className);
              }
              var ps=getElementsByTagName("p")
              setStype(ps,"green");
              var tests=getElementsByClassName("test");
              setStype(tests,"red");
          </script>
          

          封裝了三個函數(shù):

          1. setStype(eles,bgcolor):為元素設(shè)置樣式? eles:哪些元素? bgcolor:背景色
          2. getElementsByTagName(tagName):根據(jù)元素名稱獲取指定的元素? tagName:元素名
          3. getElementsByClassName(className):根據(jù)class屬性名獲取指定的元素? className:class屬性名

          接下來就是調(diào)用三個方法完成了上面的需求,解決了第一種方式中大量的重復(fù)代碼的問題。

          但是,這種方式仍然存在問題。在前面JS基礎(chǔ)中說過,我們應(yīng)該盡量避免大量使用全局變量,這會降低程序的執(zhí)行效率,在上面的程序中,我們就出現(xiàn)了5個(包括函數(shù))。所以需要繼續(xù)優(yōu)化。

          創(chuàng)建并設(shè)置標(biāo)簽(面向?qū)ο螅?/h1>

          使用面向?qū)ο蟮乃枷雭斫鉀Q上面的問題,我們可以將上面的三個函數(shù)都裝到一個對象中

          var $={
              setStype:function (eles,bgcolor) {
              	for (var i=0; i < eles.length; i++) {
              	    eles[i].style.backgroundColor=bgcolor;
              	    eles[i].style.border="1px solid #000";
              	    eles[i].style.color="white";
              	}
              },
              getElementsByTagName: function (tagName) {
                  return document.getElementsByTagName(tagName);
              },
              getElementsByClassName:function (className) {
                  return document.getElementsByClassName(className);
              }
          }
          var ps=$.getElementsByTagName("p")
          $.setStype(ps,"green");
          var tests=$.getElementsByClassName("test");
          $.setStype(tests,"red");
          

          后面如果我們還都需要封裝其他功能,可以直接在$這個對象中添加即可

          如,根據(jù)元素的id屬性獲取元素,并為其設(shè)置樣式

          getElementById:function (eleId) {
          	return [document.getElementById(eleId)];
          }
          

          需要注意的是,在設(shè)置樣式方法中,我們默認(rèn)是將傳遞進(jìn)來的元素當(dāng)做數(shù)組進(jìn)行處理的,所以,在這里,我們在getElementById方法中,手動將獲取到的元素添加到數(shù)組中返回。

          通過觀察,在$對象中,存在三個獲取元素的方法,這里我們最好將其按照下面的方式來歸類

          var $={
              getElements:{
                  byTagName: function (tagName) {
                      return document.getElementsByTagName(tagName);
                  },
                  byClassName:function (className) {
                      return document.getElementsByClassName(className);
                  },
                  byId:function (eleId) {
                      return [document.getElementById(eleId)];
                  }
              },
              setStype:function (eles,bgcolor) {
                  for (var i=0; i < eles.length; i++) {
                      eles[i].style.backgroundColor=bgcolor;
                      eles[i].style.border="1px solid #000";
                      eles[i].style.color="white";
                  }
              }
          }
          

          將獲取元素的方法封裝到$對象的getElements屬性中,今后如果還有其他獲取元素的方法,都應(yīng)該是添加到getElements屬性中,其他類型的方法也應(yīng)該按照這種思想進(jìn)行封裝。

          面向?qū)ο缶幊痰娜筇匦?/h1>

          面向?qū)ο蟮奶匦裕?/p>

          1. 封裝作用:復(fù)用和信息隱藏封裝,也就是把客觀事物封裝成抽象的類,并且類可以把自己的數(shù)據(jù)和方法只讓可信的類或者對象操作,對不可信的進(jìn)行信息隱藏。
          2. 繼承它可以使用現(xiàn)有類的所有功能,并在無需重新編寫原來的類的情況下對這些功能進(jìn)行擴展。通過繼承創(chuàng)建的新類稱為“子類”或“派生類”。被繼承的類稱為“基類”、“父類”或“超類”。繼承的過程,就是從一般到特殊的過程。
          3. 多態(tài)當(dāng)存在繼承關(guān)系時,允許將父類對象看成為和它的一個或多個子類對象等同.這樣,可以根據(jù)當(dāng)前賦給父類對象的子對象的具體特性以不同的方式進(jìn)行運行.

          用字面量方式創(chuàng)建對象

          直接使用字面量方式創(chuàng)建對象比較方便,以鍵值對的格式來定義數(shù)據(jù)

          var book1={
              name:"JavaScript權(quán)威指南",
              price:100,
              author:"tim",
              showInfo:function () {
                  console.log(this.name,this.price,this.author);
              }
          }
          console.log(book1);
          

          上面定義了一個書對象,并為其添加了屬性和方法,我們也可以直接訪問其中的屬性和方法。

          這種方式的弊端是,如果需要創(chuàng)建多個類似的對象,就顯得不太方便了,會出現(xiàn)大量的重復(fù)代碼。

          也就是說,這種方式不適合創(chuàng)建大量的相同或相似的對象。

          內(nèi)置構(gòu)造函數(shù)和簡單工廠創(chuàng)建對象

          使用new關(guān)鍵字+內(nèi)置的構(gòu)造函數(shù)創(chuàng)建對象

          var book2=new Object();
          book2.name="JS";
          book2.price=10;
          book2.author="作者";
          book2.showInfo=function () {
              console.log(this.name,this.price,this.author);
          }
          book2.showInfo();
          

          這種方式和字面量方式創(chuàng)建對象存在的問題差不多,在大量創(chuàng)建對象的時候都會存在大量重復(fù)的代碼。

          那么,利用前面的封裝的思想,我們應(yīng)該可以想到,當(dāng)有重復(fù)代碼的時候,我們可以將這些重復(fù)代碼抽取到函數(shù)中來解決。

          function createBook(name, price, author) {
              var book=new Object();
              book.name=name;
              book.price=price;
              book.author=author;
              book.showInfo=function () {
                  console.log(this.name,this.price,this.author);
              }
              return book;
          }
          var book3=createBook("bookName1",10,"author1");
          var book4=createBook("bookName2",10,"author2");
          console.log(book3);
          console.log(book4);
          

          我們將創(chuàng)建book對象的代碼封裝到createBook函數(shù)中,當(dāng)需要創(chuàng)建一個book對象的時候,直接調(diào)用該函數(shù),將函數(shù)需要的參數(shù)傳遞過去即可。

          那么,相同的思想,如果我們需要創(chuàng)建其他的對象,一樣可以使用封裝函數(shù)的方法來解決,這是沒問題的。

          function createPerson(name, age) {
              var p=new Object();
              p.name=name;
              p.age=age;
              return p;
          }
          console.log(createPerson("Neld", 10))
          

          利用上面的函數(shù),我們可以創(chuàng)建一個Person對象出來,但是通過打印對比,我們無法通過創(chuàng)建出來的對象判斷該對象的類型,而在實際開發(fā)中,判斷對象的類型是我們經(jīng)常需要執(zhí)行的,所以我們繼續(xù)看下面的自定義構(gòu)造函數(shù)創(chuàng)建對象。

          自定義構(gòu)造函數(shù)創(chuàng)建對象

          構(gòu)造函數(shù)和普通的函數(shù)的定義方式完全一樣,如下,我們定義一個創(chuàng)建Person的構(gòu)造函數(shù)

          function createPerson(name, age, sex) {
              this.name=name;
              this.age=age;
              this.sex=sex;
          }
          var p=new createPerson("Neld", 10, 1);
          var p2=new createPerson("Song", 12, 0);
          console.log(p);
          console.log(p2);
          

          自定義函數(shù)和工廠函數(shù)非常相似,但是還是存在很大的區(qū)別

          1. 構(gòu)造函數(shù)名的首字母要求大寫
          2. 需要使用new關(guān)鍵字和構(gòu)造函數(shù)一起創(chuàng)建對象
          3. 在函數(shù)中,不需要手動創(chuàng)建對象進(jìn)行數(shù)據(jù)封裝,會自動創(chuàng)建并封裝數(shù)據(jù)
          4. 在函數(shù)最后,不需要手動返回創(chuàng)建好的對象,會自動返回

          到這里,大家肯定會有疑問,自定義構(gòu)造函數(shù)到底是如何創(chuàng)建并封裝對象呢?

          1. 在函數(shù)內(nèi)部默認(rèn)會創(chuàng)建一個空對象 var obj=new Object();
          2. 默認(rèn)把創(chuàng)建好的對象賦值給this this=obj;
          3. 默認(rèn)設(shè)置this的原型對象為當(dāng)前構(gòu)造函數(shù)的原型對象
          4. 通過this添加屬性和方法
          5. 默認(rèn)會把內(nèi)部創(chuàng)建的對象返回 return this;

          通過上面的分析,相信大家已經(jīng)能夠理解自定義構(gòu)造函數(shù)的基本使用以及基本的原理了。

          構(gòu)造函數(shù)創(chuàng)建對象的返回值

          默認(rèn)情況下,構(gòu)造函數(shù)內(nèi)部會返回新創(chuàng)建好的對象(this)

          主動返回:

          1. 如果返回值類型的數(shù)據(jù),仍然返回創(chuàng)建好的對象(this),不做任何修改
          2. 如果返回引用類型的數(shù)據(jù),則返回指定的數(shù)據(jù),不再返回this。

          函數(shù)作為構(gòu)造函數(shù)參數(shù)使用

          在JS世界里,函數(shù)屬于一等公民,擁有最高特權(quán),在使用過程中可以作為變量賦值,可以作為參數(shù)傳遞,也可以作為函數(shù)的返回值,下面我們具體來看看他的使用。

          函數(shù)作為參數(shù)使用

          function f1(name,age,fn) {
              console.log("name:",name,"age:",age);
              fn();
          }
          function fn(){
              console.log("Hello H5");
          }
          f1("Neld", 10, fn);
          

          輸出結(jié)果:

          ? name: Neld age: 10? Hello H5

          在上面的代碼中,我們將函數(shù)fn作為參數(shù)傳遞給了函數(shù)f1,并且在函數(shù)f1中調(diào)用,得到的相應(yīng)的打印輸出。

          函數(shù)作為返回值使用

          function f1(name,age,fn) {
              console.log("name:",name,"age:",age);
              return fn;
          }
          function fn(){
              console.log("Hello H5");
          }
          var retFun=f1("Neld", 10, fn);
          retFun();
          

          在函數(shù)f1中將傳遞進(jìn)來的fn作為返回值返回,接收到調(diào)用f1之后的返回值得到的是返回的函數(shù),然后再調(diào)用retFun得到打印結(jié)果。

          此時的f1為高階函數(shù),即參數(shù)中有一個或多個函數(shù),并且把函數(shù)作為返回值。

          此時的fn為回調(diào)函數(shù),fn作為參數(shù)傳遞給函數(shù)f1,在f1內(nèi)部調(diào)用。

          函數(shù)作為構(gòu)造函數(shù)的參數(shù)使用

          function createPerson(name, age, sex, say) {
              this.name=name;
              this.age=age;
              this.sex=sex;
              this.say=say;
          }
          var p=new createPerson("Neld", 10, 1, function () {
              console.log("say hello");
          });
          var p2=new createPerson("Song", 12, 0,function () {
              console.log("say bye");
          });
          p.say();
          p2.say();
          

          在構(gòu)造函數(shù)中也可以對方法進(jìn)行封裝,如果方法的實現(xiàn)是由調(diào)用者決定的,那么可以在構(gòu)造函數(shù)中接收一個函數(shù)對象,然后在構(gòu)造函數(shù)中進(jìn)行封裝。

          如上面的函數(shù)say,在創(chuàng)建p和p2對象的時候傳遞并賦值給形參say,然后在構(gòu)造函數(shù)中賦值給當(dāng)前對象。

          構(gòu)造器屬性

          前面說到工廠函數(shù)創(chuàng)建對象是比較方便的,但是存在一個問題就是無法得知創(chuàng)建出來的對象的類型,所以我們選擇使用自定義的構(gòu)造函數(shù)來創(chuàng)建,構(gòu)造函數(shù)創(chuàng)建對象我們已經(jīng)會使用了,那么如何通過他得知創(chuàng)建對象的類型呢?這里我們提供兩種方式。

          1. constructor屬性

          使用constructor屬性可以獲取到創(chuàng)建對象使用的構(gòu)造器函數(shù)對象,所以我們可以通過判斷構(gòu)造器的類型來得知創(chuàng)建的對象的類型

          2.instanceof關(guān)鍵字


          instanceof關(guān)鍵字可以直接用來判斷對象的類型,如果是指定的類型,返回true,反之返回false。

          構(gòu)造函數(shù)的調(diào)用和命名

          在學(xué)習(xí)了構(gòu)造函數(shù)之后,有的同學(xué)對于它和普通函數(shù)的區(qū)別還是不太清楚,這里我們就再對構(gòu)造函數(shù)做一個說明。

          1. 構(gòu)造函數(shù)和普通函數(shù)在定義語法上沒有任何區(qū)別function 函數(shù)名(參數(shù)列表){代碼塊;}
          2. 為了和普通函數(shù)區(qū)分開,我們約定將構(gòu)造函數(shù)的名稱首字母大寫
          3. 構(gòu)造函數(shù)一樣可以直接調(diào)用,此時內(nèi)部的this執(zhí)行window,這種方式不太安全,有可能會在函數(shù)內(nèi)部修改當(dāng)前的全局變量,不建議使用,而且這樣做也不能創(chuàng)建對象
          4. 想要創(chuàng)建對象,必須使用new和構(gòu)造函數(shù)一起使用

          函數(shù)上下文和this指針

          在JS編程的過程中發(fā)現(xiàn),我們大量使用到this關(guān)鍵字,用好了this,能讓我們的代碼更加優(yōu)雅。

          this總是執(zhí)行一個對象(引用類型),但是具體執(zhí)行誰,需要根據(jù)我們在哪里使用this有關(guān)。這里主要分為下面幾種情況:

          1. 函數(shù)外部函數(shù)外部的作用域是全局作用域(window),所以,在全局作用域中使用的this指向window
          2. 普通函數(shù)內(nèi)部函數(shù)內(nèi)部的作用域是局部的,屬于調(diào)用當(dāng)前函數(shù)的對象,所以this執(zhí)向調(diào)用當(dāng)前函數(shù)的對象
          3. 構(gòu)造函數(shù)內(nèi)部在構(gòu)造函數(shù)中,this直接執(zhí)行當(dāng)前創(chuàng)建出來的新對象

          在開發(fā)中,我們也可以使用call或者apply函數(shù)修改this的執(zhí)行,這一點我們在后面繼續(xù)說明。

          自定義構(gòu)造函數(shù)存在的問題

          自定義構(gòu)造函數(shù)可以解決工廠函數(shù)帶來的對象類型不確定的問題,在開發(fā)中用得非常多,那么目前我們的自定義構(gòu)造函數(shù)又是否存在問題呢?先來看看下面的對象內(nèi)存結(jié)構(gòu)分析。

          function Person(name, age, say) {
              this.name=name;
              this.age=age;
              this.say=function(){
                  console.log("say hello");
              }
          }
          var p=new Person("zs", 10, say);
          console.log(p);
          

          上面創(chuàng)建的p對象的內(nèi)存結(jié)構(gòu)圖:

          可以看出,我們每創(chuàng)建一個Person對象,都會在內(nèi)存中分配如0x22和0x33這樣的內(nèi)存來存儲數(shù)據(jù),但是通過觀察發(fā)現(xiàn),0x33中存儲的是一個函數(shù),而這個函數(shù)在每個對象中都是相同

          所以從內(nèi)存資源分配考慮,我們無需為每個對象創(chuàng)建并分配一份新的函數(shù)對象(完全相同),這種函數(shù)大家最好共享同一份。

          文共3525字,預(yù)計學(xué)習(xí)時長12分鐘

          圖源:pexels

          一切都從對象開始。

          對象,即我們相互交流的一個載體,有其屬性和方法。對象是面向?qū)ο缶幊痰暮诵模粌H用于JavaScript,而且還適用于Java、C語言、C++等。不再考慮單個變量和函數(shù),而選擇自給型的對象。

          以下是在討論面向?qū)ο缶幊蹋∣OP)時最常用到的概念:

          · 對象,屬性,方法

          · 類

          · 封裝

          · 抽象

          · 復(fù)用/繼承

          · 多態(tài)性

          · 關(guān)聯(lián)

          · 聚合

          · 組合

          1. 對象,屬性,方法

          1.1 對象字面量(Objectliteral)

          在大括號中設(shè)置屬性,從而在JavaScript中創(chuàng)建一個新對象。對象字面量屬性值可以是任何數(shù)據(jù)類型,如函數(shù)字面量、數(shù)組、字符串、數(shù)字或布爾值。

          下面創(chuàng)建一個命名圖書的對象,其屬性包括作者、出版年份、標(biāo)題和方法。

          — summary.

          constbook={
          title: "Hippie",
          author: "Paulo Coelho",
          year: "2018"
          }

          對象創(chuàng)建完成后,可以使用點記法獲取值。例如,可以使用book.title.獲取標(biāo)題的值,還可以使用方括號book[‘title’]訪問屬性。

          1.2 對象構(gòu)造函數(shù)(Objectconstructor)

          對象構(gòu)造函數(shù)與常規(guī)函數(shù)相同。每次創(chuàng)建對象時都會用到。可將其與新關(guān)鍵字一起使用。當(dāng)需要創(chuàng)建具有相同屬性和方法的多個對象時,對象構(gòu)造函數(shù)非常有用。

          constbook={

          title: "Hippie",
          author: "Paulo Coelho",
          year: "2018"
          }const book1={
          title: "The Alchemist",
          author: "Paulo Coelho",
          year: "1988",
          }

          如果要創(chuàng)建多個書籍(book)對象,必須為每本書復(fù)制代碼。可以繼續(xù)創(chuàng)建 book對象,但這有點麻煩——不過對象構(gòu)造函數(shù)有助于再次使用對象字面量。

          functionBook(title, author, year) {
          this.title=title;
          this.author=author;
          this.year=year;
          }const book1=new Book ('Hippie', 'Paulo Coelho',

          '2018');

          console.log(book1);

          > Book {
          title: "Hippie",
          author: "Paulo Coelho",
          year: "2018"
          }// if we want to create more than onebook just we call

          function book with new keyword.const book2

          =new Book ('TheAlchemist', 'Paulo Coelho', '1988');

          book1 和 book2創(chuàng)建 Book的實例并將其分配給變量。想知道一個對象是否是另一個對象的實例。可以用instanceof。

          book1 instanceof Book

          > true

          1.3 Object.create()方法

          JavaScript中的每個對象都將從主對象創(chuàng)建。任何時候使用大寫字母“O”時,指的都是主對象。我們可以在console控制臺中打印主對象。主對象有很多方法,下面來看object.create()方法。

          Object.create()創(chuàng)建法使用現(xiàn)有對象作為原型來創(chuàng)建新對象。基本語法如下:

          Object.create(proto,[propertiesObject])

          proto是新建對象的原型。 propertiesObject是一個可選項。

          下面舉個簡單的例子:

          constBook={
          summary : function() {
          console.log(`${this.title} iswritten by ${this.author}.`)
          }
          }const book1=Object.create(Book);
          book1.author="Paulo Coelho";
          book1.title="Hippie";console.log(book1.summary());
          > Hippie is written by Paulo Coelho.

          以上的例子創(chuàng)建了一個原始對象book1,并為作者和標(biāo)題賦值。可以看到原始對象中的匯總函數(shù):

          下面將Object.create() 方法進(jìn)行詳細(xì)介紹。

          2. 類

          類不是對象,它是對象的藍(lán)本,是特殊函數(shù)。可以使用函數(shù)的表達(dá)式和聲明來定義函數(shù),也可以這樣定義類。藍(lán)本可用來表示對象的數(shù)量。

          可以使用類的關(guān)鍵字和名稱。語法與Java相似。

          類語法是使用面向?qū)ο缶幊毯凸芾碓偷囊粋€好途徑:

          let Book=function(name) {
          this.name=name
          }let newBook=function(name) {
          Book.call(this, name)
          } newBook.prototype=Object.create(Book.prototype);
          const book1=new newBook("The Alchemist");

          此例使用了ES6類語法:

          classBook {
          constructor(name) {
          this.name=name
          }
          }class newBook extends Book {
          constructor(name) {
          super(name);
          }
          }const book1=new newBook("The Alchemist");

          類語法是語法糖(syntactical sugar)—而場景背后它仍然使用基于原型的模型。類是函數(shù),而函數(shù)是JavaScript中的對象。

          classBook {
          constructor(title, author){
          this.title=title;
          this.author=author;
          }
          summary() {
          console.log(`${this.title} writtenby ${this.author}`);
          }
          }const book1=new Book("", "");

          console.log(typeof Book);
          > "function"console.log(typeof book1);
          > "object"

          3. 封裝(Encapsulation)

          封裝意為隱藏信息或數(shù)據(jù)。指對象在不向外部使用者透露任何執(zhí)行細(xì)節(jié)的情況下執(zhí)行其功能。換句話說,就是其私有變量只對當(dāng)前函數(shù)可見,而對全局范圍或其他函數(shù)不可訪問。

          constBook=function(t, a) {
          let title=t;
          let author=a;
          return {
          summary : function() {
          console.log(`${title} written by${author}.`);
          }
          }
          }
          const book1=new Book('Hippie', 'Paulo Coelho');

          book1.summary();
          > Hippie written by Paulo Coelho.

          在上面的代碼中,標(biāo)題和作者只在函數(shù)Book 的范圍內(nèi)可見,方法summary對Book的使用者可見。所以書名和作者被封裝在Book中。

          4. 抽象

          抽象意為實現(xiàn)隱藏。它是一種隱藏實現(xiàn)細(xì)節(jié)的方法,只向使用者顯示基本特性。換句話說,它隱藏了不相關(guān)的細(xì)節(jié),只顯示了必須對外部世界顯示的。缺乏抽象會導(dǎo)致代碼出現(xiàn)可維護(hù)性問題。

          constBook=function(getTitle, getAuthor) {

          // Private variables / properties
          let title=getTitle;
          let author=getAuthor;// Publicmethod
          this.giveTitle=function() {
          return title;
          }
          // Private method
          const summary=function() {
          return `${title} written by${author}.`
          }// Public method that has access toprivate method.
          this.giveSummary=function() {
          return summary()
          }
          }const book1=new Book('Hippie', 'Paulo Coelho');

          book1.giveTitle();
          > "Hippie"book1.summary();
          > Uncaught TypeError: book1.summary is not a

          functionbook1.giveSummary();
          > "Hippie written by Paulo Coelho."

          5. 復(fù)用/繼承

          JavaScript繼承是一種機制,允許我們使用現(xiàn)有的類創(chuàng)建一個新類。也就是子類繼承父類的所有屬性和行為。

          一般來說,JavaScript不是一種基于類的語言。關(guān)鍵字“類”是在ES6中引入的,但它是語法糖,JavaScript仍然是基于原型的。在JavaScript中,繼承是通過使用原型來實現(xiàn)的。這種模式稱為行為委托模式或原型繼承。

          同樣可以通過book例子來體現(xiàn):

          functionBook(title, author, year) {

          this.title=title;
          this.author=author;
          this.year=year;
          this.summary=function() {
          console.log(`${this.title} iswritten by ${this.author}.`)
          }
          }
          const book1=new Book ('Hippie', 'Paulo Coelho', '2018');

          const book2=newBook ('The Alchemist', 'Paulo Coelho',

          '1988');

          原型繼承

          對于Book的每個實例,我們都在為基類中的方法重建內(nèi)存。這些方法必須在所有實例之間共享 — 不應(yīng)特定于個別實例中。圖中的原型是:

          letCorebook=function(title) {

          this.title=title
          }Corebook.prototype.title=function() {
          console.log(`name of the book is${this.title}`);
          }Corebook.prototype.summary=function(author) {
          console.log(`${this.title} is writtenby ${this.author}`);
          }let Book=function(title, author) {
          Corebook.call(this, title, author)
          }Book.prototype=Object.create(Corebook.prototype);

          let book1

          =new Book('TheAlchemist', 'Paulo Coelho');book1.title();
          > name of the book is The Alchemistbook1.summary();
          > The Alchemist is written by Paulo Coelho

          在上面的代碼中,Book 的實例有一個原型的副本,能夠鏈接到Book的原型,而Book的原型又鏈接到Corebook的原型。

          6. 多態(tài)

          在不同的對象上使用同一方法,并讓每個對象具有自己的表現(xiàn)形式或形態(tài)的能力,稱為多態(tài)。

          letbook1=function () {}

          book1.prototype.summary=function() {
          return "summary of book1"
          }let book2=function() {}
          book2.prototype=Object.create(book1.prototype);
          book2.prototype.summary=function() {
          return "summary of book2"
          }let book3=function() {}
          book3.prototype=Object.create(book1.prototype);
          book3.prototype.summary=function() {
          return "summary of book3"
          }
          var books=[new book1(), new book2(), new book3()];
          books.forEach(function(book){
          console.log(book.summary());
          });> summary of book1
          > summary of book2
          > summary of book3

          對象之間的關(guān)系將由關(guān)聯(lián)、聚合和組合定義。

          7. 關(guān)聯(lián)

          關(guān)聯(lián)是兩個或多個對象之間的關(guān)系。每個對象都是獨立的。換句話說,關(guān)聯(lián)定義了對象之間的多重性:一對一、一對多、多對一、多對多。

          functionBook(title, author) {
          this.title=title;
          this.author=author;
          }

          const book1=new Book ('Hippie', 'Paulo Coelho');

          const book2=new Book ('TheAlchemist',

          'Paulo Coelho');

          book2.multiplicity

          =book1

          book1 賦值于book2的屬性多樣化,顯示對象book1 和 book2之間的關(guān)系。兩者都可以獨立添加和刪除。

          8. 聚合

          聚合是關(guān)聯(lián)的特例。在兩個對象之間的關(guān)系中,一個對象可能比另一個更重要。換句話說,當(dāng)一個對象比另一個擁有更多的所有權(quán)時,這就是聚合。對象所有者通常稱為聚合,被所有者稱為組件。聚合又叫“Has-a”關(guān)系。

          functionBook(title, author) {

          this.title=title;
          this.author=author;
          }

          const book1=new Book ('Hippie', 'Paulo Coelho');

          const book2=new Book ('TheAlchemist', 'Paulo Coelho');

          let publication={
          "name": "new publicationInc",
          "books": []
          }publication.books.push(book1);
          publication.books.push(book2);

          book1 和 book2 被添加到對象publication下設(shè)的books中。如果在book1和book2 運行之后刪除publication,則 Book和 publication 都將獨立運行。

          9. 組合

          組合是聚合的一種特殊情況。一個對象包含另一個對象,并且被包含的對象脫離后無法生存。

          let Book={

          "title": "TheAlchemist",
          "author": "PauloCoelho",
          "publication": {
          "name": "newpublication Inc",
          "address":"chennai"
          }
          }

          這里屬性publication與 Book 對象有嚴(yán)格的限制,publication不能沒有Book對象。如果Book的id被刪除,則publication也將被刪除。

          重組合輕繼承

          繼承指一個對象基于另一個對象的情況。例如,book1繼承了標(biāo)題、作者和結(jié)語等書籍的屬性和方法,所以它建立了book1 is-a Book關(guān)系。

          組合是收集單一對象并將它們組合起來構(gòu)建更復(fù)雜的對象。為構(gòu)建book1,需要一些方法,比如紙和筆。因此book1 has-a paper and a pen關(guān)系隨之出現(xiàn)。

          constgetTitle=(data)=> ({

          title : ()=> console.log(`title :${data.title}`)
          });const getAuthor=(data)=> ({
          author : ()=> console.log(`author:${data.author}`)
          });const getSummary=()=> ({
          summary :()=> console.log(`booksummary need to

          update.`)
          });const Book=(title, author)=> {
          const data={
          title,
          author
          }
          return Object.assign({},
          getTitle(data),
          getAuthor(data),
          getSummary()
          )
          }let book1=Book('The Alchemist', 'Paulo Coelho');

          book1.title();
          > "title : The Alchemist"

          留言點贊關(guān)注

          我們一起分享AI學(xué)習(xí)與發(fā)展的干貨

          如轉(zhuǎn)載,請后臺留言,遵守轉(zhuǎn)載規(guī)范

          程序員前端教程-javascript的面向?qū)ο?/p>

          一、什么是面向?qū)ο螅?/p>

          1.面向?qū)ο缶褪前褬?gòu)成問題是無分解成多個對象,建立對象不是為了完成某個步驟,而是描述某個事物在這個解決問題的步驟中的行為。

          2.面向?qū)ο笫且环N思維方法。

          3·面向?qū)ο笫且环N編程方法。

          4·面向?qū)ο蟛⒉恢会槍δ骋环N編程語言。

          二、面向?qū)ο蠛兔嫦蜻^程的區(qū)別和聯(lián)系?

          1.面向過程側(cè)重整個問題的解決步驟,著眼局部或者具體。

          2·面向?qū)ο髠?cè)重具體的功能,讓某個對象具有這樣的功能,更側(cè)重整體。

          面向過程的優(yōu)點:

          1.流程化使得編程任務(wù)明確,在開發(fā)之前基本考慮實現(xiàn)的方法和最終結(jié)果;

          2.效率高,面向過程強調(diào)代碼的短小精悍,善于結(jié)合數(shù)據(jù)結(jié)構(gòu)來開發(fā)高效率程序;

          3.流程明確,具體步驟清楚,便于節(jié)點分析。

          面向過程的缺點:

          1.需要深入的思考,耗費精力,代碼重用性低,擴展能力差,維護(hù)起來難度比較高。

          2.對復(fù)雜業(yè)務(wù)來說,面向過程的模塊難度較高,耦合度也比較高。

          面向?qū)ο蟮膬?yōu)點:

          1.結(jié)構(gòu)清晰,程序便于模塊化,結(jié)構(gòu)化,抽象化,更加符合人類的思維方式;

          2.封裝性,將事務(wù)高度抽象,從而便于流程中的行為分析,也便于操作和自省;

          3.容易擴展,代碼重用率高,可繼承,可覆蓋;

          4.實現(xiàn)簡單,可有效地減少程序的維護(hù)工作量,軟件開發(fā)效率高。?

          面向?qū)ο蟮娜秉c是:

          1.效率低,面向?qū)ο笤诿嫦蜻^程的基礎(chǔ)上高度抽象,從而和代碼底層的直接交互非常少機會,從而不適合底層開發(fā)和游戲甚至多媒體開發(fā)。

          2.復(fù)雜性,對于事務(wù)開發(fā)而言,事務(wù)本身是面向過程的,過度的封裝導(dǎo)致事務(wù)本身的復(fù)雜性提高。

          三、面向?qū)ο蟮膶崿F(xiàn)方式

          1.面向?qū)ο蟮膶崿F(xiàn)方式主流有兩種方式:基于類的面向?qū)ο蠛突谠偷拿嫦驅(qū)ο蟆?/p>

          2.面向?qū)ο笕筇卣鳎悍庋b、繼承、多態(tài)。

          3.基于類的面向?qū)ο螅篔ava、C#對象(object)依靠類(class)來產(chǎn)生。

          4.基于原型的面向?qū)ο螅簀avascript對象(object)依靠構(gòu)造器(constructor)利用原型(prototype)構(gòu)造出來的。

          四、多種創(chuàng)建對象的方式

          基礎(chǔ)封裝、工廠模式、構(gòu)造函數(shù)、原型對象、組合創(chuàng)建。


          主站蜘蛛池模板: 国产综合无码一区二区辣椒| 久久蜜桃精品一区二区三区| 午夜视频一区二区三区| 久久国产视频一区| 久久精品一区二区国产| 亚洲一区中文字幕| 亚洲国产AV无码一区二区三区| 少妇一夜三次一区二区| 无码人妻精品一区二 | 免费国产在线精品一区| 亚洲av高清在线观看一区二区 | 精品乱人伦一区二区三区| 亚洲日本va午夜中文字幕一区| 无码一区二区波多野结衣播放搜索| 精品一区二区三区电影| 色久综合网精品一区二区| 国产精品综合一区二区| 国内偷窥一区二区三区视频| 亚洲午夜一区二区三区| 国产高清精品一区| 无码人妻精品一区二区三区东京热 | 亚洲国产一区在线| 日韩一区二区三区不卡视频| 亚洲午夜福利AV一区二区无码| 中文字幕人妻AV一区二区| 亚洲高清偷拍一区二区三区| 国产精品视频一区二区三区经| 国产精品第一区第27页| 色狠狠色狠狠综合一区| 日本精品高清一区二区| 国产精品一区电影| 精品无码一区二区三区在线 | 亚洲天堂一区二区三区四区| 高清一区二区三区视频| 在线视频一区二区| 最美女人体内射精一区二区| 日本精品视频一区二区三区| 久久精品一区二区三区AV| 亚洲熟妇av一区二区三区漫画| 国产亚洲一区二区手机在线观看| 国产综合视频在线观看一区|