面向對象的三個特點:封裝、繼承、多態
封裝
1、封裝的概念
所謂封裝,就是指隱藏內部的細節,不暴露在外面。
把構造函數裏的this改成 _price;
在js裏面,實現封裝的方法非常簡單,只需要在聲明屬性的時候,添加關鍵字即可。 一般來講,對於私有屬性,有一個不成文的規定,習慣使用_來命名屬性。
封裝後的屬性(私有屬性)對於外部來講,雖然不可見,但是對於內部來講,是可見的。
總結:封裝後方法可以訪問,但是屬性信息都為undefined
2、get和set 以及屬性特性
很多時候,我們對對象的屬性進行封裝,並不是為了外部訪問不到,而是為了當外部訪問對象屬性或者設置的時候進行一定的限制。也就是說,外部能夠正常的訪問到進行限制了的屬性。
Object.defineProperty(),通過這個方法可以給對象添加屬性。
語法:Object.defineProperty(obj,prop,descriptor)
obj:目標對象
prop:需要添加到屬性
descriptor:屬性相關特性
descriptor參數是一個JSON對象,可以設置特性如下:
value:屬性的值. //或者return。和 writable 一起用 默認false
writable:屬性是否可寫
get:一旦目標屬性被訪問的時候,就調用該方法
set:一旦目標屬性被設置的時候,就調用該方法
enumerable:查看屬性是否可以枚舉,就是is hi 用for..in的時候,是否可以遍歷出來。 True false
如果要設置多個屬性,可以調用object.object.defineProperties(),這樣就可以設置多個屬性。使用該方法接收的參數也是有一定變化的
語法:object.defineProperties(obj,{JSON})
JSON對象 {prop:{descriptor},prop:{descriptor},…. }
for(let I in stu)
{
console.log(i);
}
繼承
1、繼承基本介紹
在程序語言裏面,面向對象種所指的繼承就是一個子類去繼承一個父類。子類在繼承了父類之後,父類所擁有的屬性和方法自動就都擁有了。
繼承的好處:
繼承最大的好處,就在於代碼能夠進行復用。例如有兩個類,就給他們寫個父類。
繼承缺點:
首先如果我們繼承設計得非常復雜,那麽整個程序設計也會變得龐大和復雜。
如果是像C++那樣的多繼承語言,那麽可能還會出現菱形繼承的問題。 //只有c++是多繼承。改動之後 最下層方法不知道用哪一個
單繼承:只有一個父類
多繼承:有多個類
菱形繼承問題:首先需要說明,菱形繼承問題只會在多繼承裏面才會出現。
例如:a和b是繼承base類,假設base類有一個成員方法,那麽a和b都會有這個成員方法,這個時候a和b又分別對成員方法進行了修改。接下來讓一個c來同時繼承a和b,問題來了,對於同名的方法,究竟使用哪一個,這就是所謂的菱形繼承問題。這個是屬於設計上的問題。
由於js是單繼承語言,所以一定程度上避免了菱形繼承的問題。
2、js裏面實現繼承的方法
(1)對象冒充
所謂對象冒充,就是指用父類(構造函數)去充當子類的屬性
temp=構造函數名字
但是,使用對象冒充實現的繼承有一個缺點,缺陷就是無法繼承到原型對象上面的屬性或者方法
從對象冒充又衍生出來了一種通過call或者apply來實現繼承,本質上還是對象冒充。
他倆基本上一樣,只是參數接收不同
function.call(abj,arg1,arg2,arg3…)
Function.apply(obj,[arg1,arg2,arg3,arg4…])
Obj:代表當前對象
arg:代表一個參數列表
總結:簡單來講,就是將a所擁有的東西應用到b的環境裏面,讓b也擁有和a相同的東西,但是作用域還是b的,而不是a的。
c1.show.call(c2);
(2)通過原型對象來實現繼承
這種方法的核心思路就是改變構造函數的prototype的屬性值,但是這種方式也有一個缺點,就是無法傳參
(3) 混合方式實現繼承
為了實現能夠同時傳參以及能夠繼承到原型對象上面的屬性和方法,采用上面兩種方式的結合。
Person.call(this, name, age); //call 方法
Student.prototype = new Person();
(4)es6 實現繼承的方式
埃ES6裏面添加了關鍵字extends
class 子 extends 父 {
Constructor(name,age,gender,score){
super(name,age)
This..
}
}
super//訪問父類
class Student extends Person { //extends關鍵字
constructor(name,age,gender,score){
super(name,age);//訪問父類的內容
this.gender=gender;
this.score=score;
多態
1、什麽事多態
所謂多態,就是指不同的對象的同名方法卻有不同的效果,這就是多態。
最常見的多態即使to string();
雖然每個對象都有tostring()方法,但是並不是每一個對象的表現形式都一樣的
轉數組有逗號分隔
轉數字 沒有
2、實現多態
在繼承父類當法的時候直接進行覆蓋即可,這樣就實現了多態。
(1)混合方式實現多態
給子類原型對象添加同名的方法;
調用同名方法。表現形式不一樣。
(2)es6中實現多態
類裏 方法也可以看作是一個屬性
在子類裏添加一個同名的屬性進行調用
重寫或重載。
我們重寫
擴展
1、從對象創建對象
實際上在js裏面創建對象時可以完全避免使用構造函數(或者說類,)而時使用另外一個對象作為原型來創建對象
使用
boject.create();
這個方法還可以傳入第二個參數,第二個參數是json對象,用來對對象的屬性設置相關特性。
2、混入
混入就是一種不需要繼承,就將某些對象的屬性和方法添加到另一個對象上面。通過Object.assing()來實現
語法:
Object.assign(target,a,b,c,d,…..)
Let a={ } ;
Let b={
name:”xiejie”,
age:18
}
let c={
gender:male;
score:100;
}
Object.assign(a,b,c);
Console .log(a.name);
如果混入對象中包含同名的屬性,那麽後面會覆蓋前面的。
記住:混入優於繼承
3、改寫this的指向
this默認的指向:如果是全局環境或者函數裏面調用,包括嵌套,這個this指向全局對象
Node global
瀏覽器 window
如果通過對象的方式來調用,那麽this指向當前對象。
但是,這個this的指向,我們是可以改變的
(1)通過call或者apply可以改變this的指向
(2)通過bind()方法強行綁定this指向
(3)箭頭函數的this
箭頭函數基本語法
(形參)=>{函數體}
如果只有一個參數
形參=>{函數體}
這裏與其數是箭頭函數改變了this指向,更貼切的來講,汗透函數的this指向和其他函數不一樣,箭頭函數的this指向始終是外部的作用域
面向對象的三個特點:封裝、繼承、多態