什么叫做面向?qū)ο螅?/h2>
面向?qū)ο笫且环N編程思想宫患,JavaScript本身就是基于面向?qū)ο髽?gòu)建出來的聊训,例如:JavaScript中有很多內(nèi)置類(Array,Object焕刮,Number注益,F(xiàn)unction碴巾,Promise....)等等,使用最簡單的例子來說Array丑搔,我們可以基于new Array來創(chuàng)建一個屬于Array的實例厦瓢,來使用Array的一些原型上的方法,比如sort低匙,slice旷痕,splice等等,平常開發(fā)的時候都是創(chuàng)建他們的實例來進行操作的顽冶。
JavaScript中的面向?qū)ο蠛推渌幊陶Z言還是有略微不同的欺抗,JS中類和實例是基于原型和原型鏈機制來處理的。
面向?qū)ο蟀裁矗?/h2>
面向?qū)ο蟀祟惖姆庋b强重,繼承和多態(tài)绞呈,下面會一一解答
封裝-低耦合高內(nèi)聚
就是可以將復(fù)用的代碼塊單獨提煉出來作為一個方法,避免了代碼的復(fù)雜程度以及多重使用時的ctrl c+ctrl v
繼承->子類使用父類的方法和屬性(目的是讓子類的實例可以使用父類的屬性和方法)
1间景、原型繼承->讓父類中的方法在子類的實例的原型鏈上
就是可以將復(fù)用的代碼塊單獨提煉出來作為一個方法,避免了代碼的復(fù)雜程度以及多重使用時的ctrl c+ctrl v
CHILD.prototype = new PARENT()
CHILD.constructor = CHILD
function Parent (x){
this.parentX = x
}
Parent.prototype.getParentX = function (){
console.log(this.parentX)
}
function Child (y){
this.childY = y
}
// 將子類的原型作為父類的實例
Child.prototype = new Parent(200)
// 可以不寫佃声,但是為了保證原型鏈的完整性,最好讓子類的原型上添加一個constructor
Child.constructor = Child;
Child.prototype.getChildY = function (){
console.log(this.childY)
}
// 缺點 -> 子類直接往父類的原型上加了一個addfun()的方法倘要,其他子類也可以調(diào)用
Child.prototype.__proto__.addfun= function (){}
var child1 = new Child(100)
console.log(child1.childY,child1.parentX) //->輸出100圾亏,200
總結(jié):
1.不是拷貝方法供子類使用,父類如果修改私有方法和屬性封拧,子類使用的屬性和方法同樣會改變
2.子類可以重寫父類的方法志鹃,會導(dǎo)致父類其他實例也受到影響
3.父類中私有和共有的屬性方法,最后都會變?yōu)樽宇惖墓袑傩院头椒?/strong>
2泽西、Call繼承->在子類中將父類當做普通函數(shù)執(zhí)行曹铃,讓父類的this指向子類的實例,相當于給子類的實例設(shè)置了很多私有的屬性和方法
function Parent (x){
this.parentX = x
}
Parent.prototype.getParentX = function (){
console.log(this.parentX)
}
function Child (y){
// 使用call將父類的this指向指到子類中捧杉,那父類的私有屬性和方法就成為了子類的私有屬性和方法
Parent.call(this,200)
this.childY = y
}
Child.prototype.getChildY = function (){
console.log(this.childY)
}
var child1 = new Child(100)
console.log(child1.childY,child1.parentX) //->輸出100陕见,200
總結(jié):
1.只能繼承父類私有的屬性和方法(因為是把父類當做普通函數(shù)來執(zhí)行,和其原型上的屬性和方法沒有關(guān)系)
2.父類私有的屬性和方法變成子類的私有的屬性和方法
3味抖、寄生組合繼承->Call繼承+類似于原型繼承
function Parent (x){
this.parentX = x
}
Parent.prototype.getParentX = function (){
console.log(this.parentX)
}
function Child (y){
// 使用call將父類的this指向指到子類中评甜,那父類的私有屬性和方法就成為了子類的私有屬性和方法
Parent.call(this,200)
this.childY = y
}
// Object.create() 創(chuàng)建一個空對象,讓空對象的原型鏈(__proto__)指向第一個參數(shù)
Child.prototype = Object.create(Parent.prototype)
Child.prototype.constructor = Child;
Child.prototype.getChildY = function (){
console.log(this.childY)
}
var child1 = new Child(100)
console.log(child1.childY,child1.parentX) //->輸出100,200
但是問題同樣來了仔涩,如果不考慮IE瀏覽器的話這樣是沒問題的忍坷,但是如果要考慮IE瀏覽器就會發(fā)現(xiàn)有問題,因為IE瀏覽器并沒有proto,所以我們的Object.create()方法就不能用了承匣,所以就需要自己重寫一個create方法
Object.create = function (obj) {
function Fn (){};
Fn.prototype = obj;
return new Fn()
}
總結(jié):
父類私有和共有的分別是子類實例的私有和共有屬性方法
4、ES6中的繼承->//ES6中繼承使用extends
語法 class Child extends Parent{} 實際結(jié)果相當于Child.prototype.proto = Parent.prototype
class Parent {
constructor (x){
this.x = x;
}
getx() {
return this.x;
}
}
// 然后constructor中需要加入一個super
class Child extends Parent{
// 子類繼承父類可以不寫constructor,一旦寫了constructor中的第一句話必須是super
// 如果不寫constructor,瀏覽器會自己默認創(chuàng)建
// constructor(...args){super(...args)}
constructor (y){
super(y) // 相當于Parent.call(this,200)
this.y = y
}
gety() {
return this.y
}
getx(){
return 0
}
}
// Child.prototype = Object.create(Parent.prototype) 不允許重定向原型的指向
let child1 = new Child(100)
console.log(child1.x,child1.y,child1.gety(),child1.getx());
總結(jié):
父類私有和共有的分別是子類實例的私有和共有屬性方法
多態(tài)->類的重載和重寫
重載->java的定義就是方法名稱相同锤悄,但是根據(jù)參數(shù)的不同去拆分一些復(fù)雜代碼韧骗。而js中的重載是方法名字一樣,但是根據(jù)參數(shù)的不同在當前作用域中進行代碼的處理零聚。
實際上js中是不存在真正意義上的重載比如:
function sum(x,y){
console.log('1')
}
function sum(x,y,z){
console.log('2');
}
sum() //->輸出打印 2
因為js中是有變量提升這個概念的袍暴,所以當方法名字一樣的時候下面的方法會將上面方法覆蓋掉。所以在js中進行重載的話需要用到 arguments 這個參數(shù)或者es6中的擴展運算符 ...arg隶症,然后根據(jù)arguments中的參數(shù)進行判斷操作
function fn(){
for( let i= 0;i<arguments.length;i++){
if(typeof(arguments[i])=='string'){
console.log(arguments[i])
}
}
}
function fn1(...arg){
arg.forEach(item=>{
if(typeof(item)=='string'){
console.log(item)
}
})
}
fn(1,2,'a') // ->輸出a
fn1(1,2,'b')// ->輸出b
文采不好政模,請見諒,有錯誤的請及時留言聯(lián)系我修改蚂会。望大家批評指正淋样!