面向過程編程就是分析出解決問題的步驟,然后使用函數(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ū)ο蟮闹攸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)的目的即可。
在學(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)容。
需求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ù)。
對于上面重復(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ù):
接下來就是調(diào)用三個方法完成了上面的需求,解決了第一種方式中大量的重復(fù)代碼的問題。
但是,這種方式仍然存在問題。在前面JS基礎(chǔ)中說過,我們應(yīng)該盡量避免大量使用全局變量,這會降低程序的執(zhí)行效率,在上面的程序中,我們就出現(xiàn)了5個(包括函數(shù))。所以需要繼續(xù)優(yōu)化。
使用面向?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ū)ο蟮奶匦裕?/p>
直接使用字面量方式創(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)建大量的相同或相似的對象。
使用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ù)和普通的函數(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ū)別
到這里,大家肯定會有疑問,自定義構(gòu)造函數(shù)到底是如何創(chuàng)建并封裝對象呢?
通過上面的分析,相信大家已經(jīng)能夠理解自定義構(gòu)造函數(shù)的基本使用以及基本的原理了。
默認(rèn)情況下,構(gòu)造函數(shù)內(nèi)部會返回新創(chuàng)建好的對象(this)
主動返回:
在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)前對象。
前面說到工廠函數(shù)創(chuàng)建對象是比較方便的,但是存在一個問題就是無法得知創(chuàng)建出來的對象的類型,所以我們選擇使用自定義的構(gòu)造函數(shù)來創(chuàng)建,構(gòu)造函數(shù)創(chuàng)建對象我們已經(jīng)會使用了,那么如何通過他得知創(chuàng)建對象的類型呢?這里我們提供兩種方式。
使用constructor屬性可以獲取到創(chuàng)建對象使用的構(gòu)造器函數(shù)對象,所以我們可以通過判斷構(gòu)造器的類型來得知創(chuàng)建的對象的類型
2.instanceof關(guān)鍵字
instanceof關(guān)鍵字可以直接用來判斷對象的類型,如果是指定的類型,返回true,反之返回false。
在學(xué)習(xí)了構(gòu)造函數(shù)之后,有的同學(xué)對于它和普通函數(shù)的區(qū)別還是不太清楚,這里我們就再對構(gòu)造函數(shù)做一個說明。
在JS編程的過程中發(fā)現(xiàn),我們大量使用到this關(guān)鍵字,用好了this,能讓我們的代碼更加優(yōu)雅。
this總是執(zhí)行一個對象(引用類型),但是具體執(zhí)行誰,需要根據(jù)我們在哪里使用this有關(guān)。這里主要分為下面幾種情況:
在開發(fā)中,我們也可以使用call或者apply函數(shù)修改this的執(zhí)行,這一點我們在后面繼續(xù)說明。
自定義構(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)建。
*請認(rèn)真填寫需求信息,我們會在24小時內(nèi)與您取得聯(lián)系。