js中的繼承:
Object是所有對象的父級/父類型/超類型,js中所有的對象都直接或間接的繼承自O(shè)bject.
繼承有兩種方式:接口繼承和實現(xiàn)繼承,js中只支持實現(xiàn)繼承,實現(xiàn)繼承主要依賴原型鏈來完成.
說明 : 其他語言的繼承是通過類來實現(xiàn),js中沒有類的概念,js中的繼承是某個對象繼承另一個對象,是基于對象的繼承.
一.JS實現(xiàn)繼承方式
? ? ?(1)屬性拷貝(混入式繼承)
? ? ?(2)原型式繼承
? ? ?(3)原型鏈繼承
? ? ?(4)借用構(gòu)造函數(shù)繼承 ?經(jīng)典繼承 ?偽對象繼承
? ? ?(5)組合繼承
? ? ?(6)通過特定的方法實現(xiàn)繼承
? ? ?(7)內(nèi)容拷貝
1.屬性拷貝(混入式繼承)
? ?屬性拷貝:
? ? 存在問題: 如果父對象中有引用類型,子對象和父對象的該屬性會共享一份數(shù)據(jù),修改其 ? ? ? ? ? ? ? ? ? ? ? ? 中一個影響另外一個
? ? ?函數(shù)拷貝:Object.assign(目標(biāo)對象,要拷貝屬性的對象(多個))------>ES6支持
Object.assign(o,obj1,0bj2)
2.原型式繼承(不是嚴(yán)格意義上的繼承)
(1)利用構(gòu)造函數(shù)創(chuàng)建出來的對象可以使用原型對象的屬性和方法
(2)替換原型
(3)設(shè)置子構(gòu)造函數(shù)的原型對象時是父構(gòu)造函數(shù)的原型:student.prototype=person.prototype
? ? 存在問題:1)只能獲取父構(gòu)造函數(shù)的原型對象的屬性和方法,不能獲取實例的屬性和方法
? ? ? ? ? ? ? ? ? ? 2)無法修正構(gòu)造器屬性
3.擴展內(nèi)置對象
Object Array Date Function String Number Boolean
通過這個方式可以擴展內(nèi)置構(gòu)造函數(shù),但不建議這樣做,在實際開發(fā)中很多人開發(fā),項目的代碼量非常龐大,如果每個人都通過這個方式擴展對象,可能會出現(xiàn)方法被覆蓋等安全問題,不方便項目管理問題
(1)安全的擴展內(nèi)置對象
? ? a.提供一個構(gòu)造函數(shù)(自己寫的)
? ? ?b.設(shè)置這個構(gòu)造函數(shù)的原型對象是內(nèi)置構(gòu)造函數(shù)的一個實例
安全擴展內(nèi)置對象圖解:
3.原型鏈繼承
1)每一對象都是由構(gòu)造函數(shù)創(chuàng)建的
2)每一個構(gòu)造函數(shù)都有自己的原型對象
3)構(gòu)造函數(shù)的原型對象也是一個對象
4)構(gòu)造函數(shù)的原型對象也有自己的構(gòu)造函數(shù)
5)構(gòu)造函數(shù)原型對象的構(gòu)造函數(shù)也有自己的原型對象
6)構(gòu)造函數(shù)原型對象的構(gòu)造函數(shù)的原型對象也是一個對象,也有自己的構(gòu)造函數(shù)
以上就形成了一個人鏈?zhǔn)浇Y(jié)構(gòu),這個就稱為原型鏈.
原型鏈的頂端是Object.prototype
? ? ? ? Object.prototype._proto_=null
A.原型鏈屬性的訪問原則:(就近原則)
1).通過對象.屬性訪問屬性的時候,首先會查找自身,如果有直接使用;
2).如果自身沒有,會查找該對象的原型對象,如果有直接使用;
3).如果沒有,會查找原型對象的原型對象,如果有直接使用;
4).如果沒有,就繼續(xù)之前的操作,向原型鏈的頂端繼續(xù)查找
5).直到查找到Object.prototype,如果有就直接使用,如果沒有,返回undefined或者報錯
B.原型鏈繼承:
1).提供一個父構(gòu)造函數(shù)和子構(gòu)造函數(shù)
2).設(shè)置子構(gòu)造函數(shù)的原型對象是父構(gòu)造函數(shù)的實例
Student.prototype=new Person()
C.復(fù)雜的原型鏈?zhǔn)纠?/p>
動物(毛色,跑) ->人(姓名,useTool)->學(xué)生(學(xué)號,學(xué)習(xí))->男學(xué)生(性別男,打游戲)
1).提供4個構(gòu)造函數(shù)
2).設(shè)置屬性和方法(屬性寫在構(gòu)造函數(shù)中,方法寫在原型上)
3).設(shè)置原型鏈繼承
4).修正構(gòu)造器屬性
D.原型鏈繼承注意點:
? ? 1)在完成原型鏈繼承后再修正構(gòu)造器屬性
? ? ?2)在完成原型鏈繼承后再設(shè)置原型對象的屬性和方法
? ? ?3)在完成原型鏈繼承后只能通過對象的動態(tài)特性添加屬性
E.原型鏈繼承存在的問題:
? ? ?1)無法傳遞參數(shù)給父構(gòu)造函數(shù);
? ? ? 2)繼承過來的屬性和方法會成為原型屬性和方法,存在共享問題
4.Object.create()方法
Object.create會創(chuàng)建一個新的對象,并且設(shè)置該對象的原型對象是傳入的對象(ES5才支持)
兼容性處理:
方法一
方法二:如果有create方法就直接用,如果沒有就自己添加一個方法
函數(shù)封裝
5.call和apply函數(shù)
1).在ES3中,系統(tǒng)給Function的原型添加了2個方法
? ? ?Function.prototype.call
? ? ?Function.prototype.apply
? ? 作用:借用其他對象的方法
? 參數(shù):(1)第一個參數(shù):實際調(diào)用方法的對象(函數(shù)內(nèi)部this的綁定對象);
? ? ? ? ? ?(2)后面的參數(shù): a:call,參數(shù)1,參數(shù)2..... ? ? 參數(shù)列表
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? b:apply,[參數(shù)1,參數(shù)2.....] ? ?參數(shù)數(shù)組
6.借用構(gòu)造函數(shù)繼承 經(jīng)典繼承 偽對象繼承
1)借用構(gòu)造函數(shù)繼承的基本寫法,解決了無法傳遞參數(shù)給父構(gòu)造函數(shù)的問題
存在的問題:無法獲取原型屬性和方法
7.組合繼承
1).借用構(gòu)造函數(shù)繼承---->只能獲取實例屬性和方法
2).原型式繼承---->獲取原型屬性和方法
問題:共享同一個原型對象
8.淺拷貝和深拷貝
1)淺拷貝:地址拷貝(指針拷貝),存在數(shù)據(jù)共享問題
2)深拷貝:內(nèi)容拷貝(完全拷貝)
? ? ? (1)提供一個函數(shù)封裝深拷貝,有兩個參數(shù),第一個是目標(biāo)參數(shù),第二個參數(shù)是要拷貝屬性的對象;
? ? ? (2)判斷第一個參數(shù),如果沒有值就自己初始化
? ? ? (3)for...in遍歷第二個參數(shù)
? ? ? ? ? ? ? ? a.如果是值類型或者是函數(shù),直接賦值
? ? ? ? ? ? ? ? b.如果不是值類型的數(shù)據(jù),就再一次調(diào)用這個方法拷貝內(nèi)部存儲的內(nèi)容
通過深拷貝實現(xiàn)繼承
借用構(gòu)造函數(shù)----->獲取實例屬性
深拷貝------>獲取原型屬性
Array.isArray(ES5才支持)
作用:判斷對象時候是個數(shù)組
二.基本包裝類型
1.基本包裝類型:String ?Number ?Boolean
1)創(chuàng)建字符串對象
2)創(chuàng)建數(shù)值對象
3)創(chuàng)建布爾對象
4)特殊的方式創(chuàng)建
2.基本包裝類型注意點
? ?1)在比較是否相等的時候
基本數(shù)據(jù)類型怎么會有屬性?
?2)內(nèi)部實現(xiàn):
字符串 布爾 數(shù)值在訪問屬性或者調(diào)用方法的時候
?1).內(nèi)部會默認(rèn)創(chuàng)建一個對象
?2).通過這個對象訪問屬性或調(diào)用方法
?3).得到結(jié)果后返回結(jié)果
?4).銷毀該對象