13-2對象與原型對象
13-2-1對象的分類
在ES6以前,對象能夠分爲2大類,分別是原生對象和宿主對象。
●原生對象
原生對象又能夠分爲2類:內置對象和自定義對象。例如前面咱們學習過的Date、Math、 正則、數組等,這些就是典型的內置對象。它們是JavaScript這門語 言自己所內置的,咱們直接使用便可。
而自定義對象則是咱們開發人員本身定義的對象,例如在JS基礎中介紹過的使用{}快速生成對象。這樣的對象就能夠被稱之爲自定義對象。
。宿主對象
顧名思義,就是依存於某一個特定的環境纔會有的對象。一旦離開了特定的環境,則這些對象將不存在。例如前面咱們在講解DOM編程時介紹過
的widnow、navigator 、history 等對象,這些都是依賴於瀏覽器環境的。一旦脫離了瀏覽器環境,這些對象也就不存在了。
在ES6中,對象的類別獲得了擴充,分爲了4個類別,分別是普通對象,外來對象,標準對象和內置對象。
13-2-2原型對象
迷途 2019/7/23 星期二 19:14:34
迷途 2019/07/23 19:14:33
let Computer = function(name,price)f
this. name = name;this.price = price;
112CiE Tobject#t U35Rreturn (
name : xiejie"t
showSth : functíon()
console, log("another object");
console. log(this); 11 FJEDthis1
Computer, protatype. showSth = function()f
console. log(this); 11 JEDWthis1311
let apple = new Computer("S R" , 12000);console. log(apple.name); 11 xiejieapple. showSth();11 another object
11 [ name: 'xiejie', showSth: [Function: showSthJ ]
imit E 7ĩ83513. EXíEJLZE. kẞs pQiã gg üïxT e tiRO1EfẞxtE. this QUsft5 bs f5IJ4B
19:15:01
迷途 2019/7/23 星期二 19:15:01
迷途 2019/07/23 19:15:01
用new運算符調用函數時,該函數總會返回- -個對象,一般狀況下,構造函數裏面的this就指向返回的這個對象。示例以下:
Let Computer = function(name, price){
this.name = name;this,price F price;}
Computer . prototype. showSth = function(){
console. log(this); //打印出this所指向的對象console. log('這是一臺${this . name}電腦);}
let apple = new Computer("蘋果",12000);console. log( apple. name);//蘋果console. log(apple. price);//12000
apple, showSth();//Computer { name; ' 蘋果’,price: 12000 }這是: -臺蘋果電腦Let asus = new Computer("華碩" , 5000);console. log(asus. name);//華碩console. log (asus. price);//5000
asus. showSth();//Computer { name; ' 華碩’,price: 5000 }這是一 臺華碩電腦
這裏,咱們分別實例化出來了兩個對象apple和asus。那麼,這兩個對象就有各自的屬性值。
迷途 2019/7/23 星期二 19:15:11
13-3-2 ES6類的聲明
在ES6中,已經開始愈來愈貼近其餘的高級語言了。在ES6中有了類這個概念,使用class來建立類,而後從類裏面實例化對象。
可是,須要說明的是,雖然有了class這種關鍵字,可是這只是一種語法糖,背後對象的建立,還
是使用的是原型的方式。
具體示例以下:
迷途 2019/7/23 星期二 19:15:23
迷途 2019/07/23 19:15:22
13-3類與對象的建立
在前面的第一-小節,咱們講述了什麼是面向對象,以及什麼是類,還有類和對象之間的關係。緊接着在第二小節咱們話鋒-轉,闡述了JavaScript裏面不存在類的概念,而是基於一門基於原型的語言。
既然JavaScript裏面不存在類,那麼爲何咱們還要在第- -小節花大量的篇幅來介紹面向對象裏面的類呢?實際上,在JavaScript中 雖然沒有類,可是能夠經過構造函數來模擬其餘編程語言裏面的類。從而從構造函數裏面實例化對象出來。因此在這- -小節, 咱們就來看-下JavaScript中如何書寫構造函數來模擬其餘語言中的類的。
13-3-1構造函數
JavaScript是- -個]很特殊的語言,在ES6之 前都沒有類的概念(注: ES6新增了class關鍵字),而是經過構造函數來模擬其餘編程語言裏面的類的。構造函數實際上也是函數,不過這種函數是專門用於生產對象的,因此被稱之爲構造函數。它的外表和普通函數- -模-樣,區別只是在於被調用的方式.上面。
構造函數的函數名有一個不成文的規定,就是首字母要大寫,以便和普通函數進行區分。下面的例子就演示了在JavaScript中如何書寫一個構造函數:
迷途 2019/7/23 星期二 19:15:33
迷途 2019/07/23 19:15:33
13-3-1構造函數
JavaScript是一門很特殊的語言,在ES6以前都沒有類的概念(注: ES6新增了class關鍵字),而是經過構造函數來模擬其餘編程語言裏面的類的。構造函數實際上也是函數,不過這種函數是專]用於生產對象的,因此被稱之爲構造函數。它的外表和普通函數一模-樣,區別只是在於被調用的方式上面。
構造函數的函數名有一個不成文的規定,就是首字母要大寫,以便和普通函數進行區分。下面的例子就演示了在JavaScript中如何書寫一個構造函數:
Let Computer = function(name, price){
this.name = name;this.price = price;
Computer. prototype. showSth = function(){
console. log(這是-臺${this. name}電腦);}
這裏,咱們建立了一-個Computer類,這個類有兩個成員屬性,分別是name和price,有一-個成員方法,是showSth()。可是能夠看到,這裏的成員方法showSth()是書寫在Computer類的prototype,上面的。
迷途 2019/7/23 星期二 19:15:46
具體示例以下:
class Computer{
//構造器
constructor(name, price){
this. name = name;this.price = price;
}
//原型方法showSth(){
console.log('這是一臺${this .name}電腦^ );
}
}
Let apple = new Computer("蘋果" , 12000); console. log(apple.name);//蘋果console. log( apple. price);//12000apple. showSth();//這是一臺蘋果電腦
迷途 2019/7/23 星期二 19:15:57
迷途 2019/07/23 19:15:57
一PToto_
{})
prototype
constructor
[Function Object]
. proto_
Dror
[Function J
o
constructor
原型對象) Dron
C
_Proto__
Otyoefor
.proto_
"Clor
構造函數
o
廠( [Function Function]
)
constructor
、對象
COS
Arravll. Nuncel].Booleant. Singll.Functionll. ablectl自定義購值品報導
(對象與原型對象關係圖)
經過上面的圖咱們能夠得出如下的結論:
●每個對象都有一個原型對象。咱們能夠經過_ proto__ 來訪問到某個對象的原型對象●經過_ _proto__ 一直向上尋找原型對象的話,最終會找到null
●一個構造函數的prototype屬性指向-一個對象,而這個對象是經過該構造函數實例化出來
的對象的原型對象
●JavaScript中的根對象是0bject.prototype對象。object . prototype對象是一一個空對
象。咱們在JavaScript中遇到的每一個對象,實際上都是從0bject . prototype對象克隆而來的。0bject. prototype對象就是它們的原型。而object. prototype對象的原型爲null。
迷途 2019/7/23 星期二 19:16:08
13-2-2原型對象
在JavaScript裏面,沒有類這個概念,只有原型的概念。在JavaScript裏 面的每個對象, 都有一個原型對象,而原型對象上面也有一個本身的原型對象,一層一-層向上找,最終到達null。這聽起來感受有點複雜,這裏咱們將經過- -張圖來進行解釋,以下圖:
迷途 2019/7/23 星期二 19:16:20
迷途 2019/07/23 19:16:19
這裏,咱們分別實例化出來了兩個對象apple和asus。那麼,這兩個對象就有各自的屬性值。
但用new調用構造函數時,還要注意一個問題, 若是構造函數顯式地返回了一個object類型象,那麼這次運算結果最終會返回這個對象,而不是咱們以前所期待的this,這裏咱們經過的兩段代碼來搞清楚構造函數是否顯式返回object類型對象之間的區別,以下:
正常狀況,構造函數沒有返回object類型對象,this指向實例化出來對 象
Let Computer = function (name ,price){
this. name = name;this.price = price;
Computer . prototype. showSth = function(){
console. log(this); //打印出this所指向的對象
}
Let apple = new Computer("蘋果",12000);console. log(apple.name); //蘋果
apple. showSth(); // Computer { name: ' 蘋果’,price: 12000 }
構造函數顯式的返回一個object類型的對象,那麼最終使用的就是手動返回的這個對象。
Let Computer = function (name, price){
this. name = name;this.price = price;
迷途 2019/7/23 星期二 19:16:29
3. constructorl
i@i5 constructor Æ', F*í]ẞJIê#EJ- ↑Xj ŸẞÆft4. tGiEiš, ñtãiZ↑XfXRXf#жR, 5Jk0F:
let Computer = function(name,price)[
this. name = name;this.price = price;]
Computer, prototype. showSth = function()f
console. log(' i&Æ- a$íthis . name]@i );]
let apple = new Computer("#Q" , 12000);
console. log(apple.const ructor);// [Function: Computer]
I
迷途 2019/7/23 星期二 19:16:39
迷途 2019/07/23 19:16:38
關鍵字來提供不一樣的訪問權限。可是在JavaScript中並無提供對這些關鍵字的支持。
不過在JavaScript中要實現封裝的方法也很是簡單,能夠利用函數的做用域來進行模擬。在聲明屬性的時候,添加關鍵字(et、const、 var)便可。緣由也很是簡單,由於構造函數也是函數,既然是函數就會有函數做用域,因此在屬性的前面添加了關鍵字以後使其成爲一個局部變量,外部天然而然也就訪問不到了。示例以下:
Let Computer = function name, price){
this.name = name ;Let price = price;
Computer. prototype. showSth = function(){
console. log(這是一臺${this. name}電腦~ );}
Let apple = new Computer("蘋果」,12000);
console. log(apple. name);//蘋果
console. log(apple. price);//undefinedconsole. log(apple._ price);//undefined
-般來說,對於私有屬性,有一個不成文的規定,那就是習慣使用_開頭來命名私有屬性。這裏咱們能夠看到,因爲咱們對price屬性進行了封裝,因此外部沒法訪問到。
迷途 2019/7/23 星期二 19:16:50
迷途 2019/07/23 19:16:49
13-3-3靜態方法
所謂靜態方法,又被稱之爲類方法。顧名思義,就是經過類來調用的方法。靜態方法的好處在於不須要實例化對象,直接經過類就可以進行方法的調用。
在ES6建立類的方法的時候,能夠給方法前面添加一個關鍵字static,來建立一個靜態方法。
class Computer{
//構造器
const ructor(name, price){
this.name = name;this.price = price;
}
//原型方法
showSth(){ T
console. log( .這是一臺${this . name}電腦);
//靜態方法
static comStruct(){
console. log("電腦由顯示器,主機,鍵鼠組成");
}
Computer. comStruct();
//電腦由顯示器,主機,鍵鼠組成
迷途 2019/7/23 星期二 19:16:58
4. instanceofjklF7
l
#JF- -↑XJXE2€- -↑133315J. s↓# iẞtrue, EJtiEfalse
let Computer = function(name, price)f
this.name = name;this.price = price;
Computer. prototype. showSth = function()(
console. log(' i&- a$[this, name]@Æ" );]
let apple = new Computer("E R", 12000); .
console. log(apple instanceof Computer);//trueconsole. log(apple instanceof Array);//false
19:17:09
迷途 2019/7/23 星期二 19:17:09
迷途 2019/07/23 19:17:08
6. hasOwnProperty(
#Jí-↑4ÆÆXÆX$*# LñiZMM#xæ L õẞmTЖÉJ. $ẞ#4#a, J!i@true, SOR€ÉmmxTжÉ], J!JjEfalse
let Computer = function (name, price)[
this.name = name;this.price = price;
Computer. prototype . showSth = function()f
console. log(' iXk B$[this. name]Rü );]
Computer. prototype.test = "this is a test";let apple = new Computer("E R" , 12000);console. log(apple.test);//this is a test
console. log( apple. has0wnP roperty("test"));//falseconsole. log( apple: has0wnProperty("name"));//true
迷途 2019/7/23 星期二 19:17:31
迷途 2019/07/23 19:17:30
起
x- 1. prototype和_ proto_ ^-2. Object.getPrototypeC. 3. constructor屬性. 4. instanceof操做符- 5. isPrototypeOf0. 6. hasOwnProperty03 13-5封裝
. 13-5-1 封裝基本介紹13-5-2存取器白13-6繼承
白13-6-1繼承基本介紹
繼承的好處. 繼承的缺點白13-6-2對象冒充
L方法借用模式.13-6-3原型繼承. 13-6-4 ES6繼承方式白13-7多態(選修)
-13-7-1 多態簡介. 13-7-2實現多態13-7-3多態的意義田13-8 this的指向
-13-9內置對象添加方法13-10屬性特性以及描述符13-11基於對象建立對象a 13-12混入技術
-13-12-1淺複製與深複製13-12-2用mixin函數添加總結
13-6-1繼承基本介紹
在程序語言中,面向對象裏面的繼承是指一個子類去繼承-個父類。子類繼承了父類以後,父類全部的屬性和方法都自動都擁有了。
繼承的好處
繼承最大的好處,就在於代碼複用。例若有兩個類,這兩個類的屬性和方法基本相同,那麼咱們就能夠考慮給這兩個類寫-一個父類
繼承的缺點
首先若是繼承設計得很是複雜,那麼整個程序的設計也會變得龐大和臃腫。甚至常常會出現"大猩猩與香蕉"的問題。"大猩猩與香蕉"這個名字來自於Erlang編程語言的創始人Joe Armstrong的文章:你想要一個香蕉,可是獲得的是拿着香蕉和整個叢林的大猩猩。
還有一個問題就是,若是是像C+ +那樣的多繼承語言,那麼還可能會遇到菱形繼承的問題。這裏咱們首先來看一下什麼叫作多繼承。既然有多繼承,天然就有單繼承。單繼承:所謂單繼承,就是指只有一個父類多繼承:所謂多繼承,就是指有多個父類
菱形繼承問題:首先須要說明,菱形繼承問題只會在多繼承裏面纔會出現。例如: A和B都繼承MindonBase類,假設Base類 裏面有一個成員方法, 那麼A和B裏面都會有這個成員方法,這個時候A和B
兩個類又都對這個成員方法進行了修改。接下來讓一個C來同時繼承A和B,那麼 這個時候就會產 Q
迷途 2019/7/23 星期二 19:18:00
迷途 2019/07/23 19:17:59
13-4與原型相關的方法
前面已經介紹了JS裏面比較有特點的原型對象,也介紹了在JS裏面如何建立構造函數或者類,而後經過構造函數和類來實例化出對象。接下來,咱們就來看一下JS中和原型對象相關的一- 些方法。
1. prototype和_ proto_
prototype是構造函數上面的一個屬性,指向一個對象,這個對象是構造函數實例化出來的對象的原型對象。實例化出來的對象能夠經過proto_ 來找到自 己的原型對象。
Let Computer = function(name, price){
this.name = name ;this.price = price;}
Computer. prototype. showSth = function(){
console. log(這是一臺${this . name}電腦);
Let apple = new Computer("蘋果",12000);
console. log(Computer . prototype);//Computer { showSth: [Function }console. log(apple._ proto__ );//Computer { showSth; [Function] }console. log(Computer. prototype === apple._ proto__ );// true
迷途 2019/7/23 星期二 19:18:17
迷途 2019/07/23 19:18:17
2. Object.getPrototypeOf)
Bâ7. Lïẞîi_ proto_ жäE!JXJ EXRIX9N, tEFJlXi Object. getPrototypeOfl) жE# - -↑XJ SgR@XJR
let Computer = function (name,price)f
this. name = name;this.price = price;
Computer . prototype. showSth = function()f
console.log(' i&- B$íthis. name]Aü );3
let apple = new Computer("4#", 12000);
console. log(Object. getPrototypeOf (apple));//Computer ( showSth: [Function] 1console. log(apple._ _proto__ );//Computer f showSth: [Function] ]
console. log(0bject . getPrototypeOf(apple) === apple._ proto__ );//true
迷途 2019/7/23 星期二 19:18:28
迷途 2019/07/23 19:18:27
-般來說,對於私有屬性,有一個不成文的規定,那就是習慣使用_開頭來命名私有屬性。這裏咱們能夠看到,因爲咱們對price屬性進行了封裝,因此外部沒法訪問到。
封裝後的屬性,咱們能夠將其稱之爲私有屬性。對於外部來說,私有屬性是不可見的,這個咱們已經知道了,可是對於內部來說,私有屬性是可見的。這就比如電視機裏面的零部件封裝後外部沒法直接訪問到,可是電視機內部是可使用這個零部件來完成相應的功能的。示例以下:
Let Computer = function (name,price){
this. name = name;Let_ price = price;
this.sayPrice = function(){
console. log(價格爲${_ .price} );
}
}
Computer . prototype. showSth = function(){
console. log(這是一臺${this . name}電腦~ );
}
Let apple = new Computer("蘋果" , 12000);apple. sayPrice();//價格爲12000
迷途 2019/7/23 星期二 19:18:38
迷途 2019/07/23 19:18:37
callf9l]:
let Person = function(name, age)[
this. name = name;this.age = age;
Person. prototype.test = function()[
console. log("this is a test");
let Student = function( name, age , gender, score)f l
11 XPersoni Fi/this EäF11this6EE#E
Person. call(this , name , age);this . gender = gender;this.score. = score;
let xiejie = new Student("i92", 18,"B" ,100);console. log(xiejie.name);// i$%2N3console. log(xiejie.age);//18 Iconsole. log(xiejie.gender);11#console. log(xiejie. score);//100
xiejie. test();//TypeError: xiejie,test is not a function
編程