Js類的構建與繼承案例詳解

JS裡類的定義和繼承實在五花八門,所以單獨開一個筆記本記錄。

定義

派生於Object的方式

1.new Object:在創建對象後動態定義屬性、方法
var Car = new Object;
Car.color = "red";
Car.showColor = function(){
	console.log(this.color);
}
//想要繼承就要先構造空對象然後用__proto__原型鏈來繼承
var Car1 = new Object; //或者 = {}
Car1.__proto__ =  Car;

使用函數構造

1.工廠函數:在函數內生成類,好處是不用再構造空對象+繼承原型鏈,直接返回一個對象的復制,類似於構造函數
function createCar(){ //也可以為此函數傳遞參數creatCar(color)
	let car = new Object;
	car.color = "red"; //傳遞參數:car.color = color
	car.showColor = function(){
		console.log(this.color);
	}
	return car;
}

var newCar = createCar(); //傳遞參數:createCar("red")
//但是使用工廠函數,每構造一個函數就會構建一次showColor方法,很不劃算
//所以可以在類的工廠函數之前為所有類統一確定一個用於繼承的方法
function showColor(){
	console.log(this.color);
}
function createCar(){
...
	car.showColor = showColor;
...
}

2.構造函數方法:類似於工廠函數方法,使用構造函數方法。不同的是構造函數內屬性隻能為this.attr
function Car(color,num){
	this.color = color;
	this.num = num;
	this.showColor = function(){
		console.log(this.color);
	}
	this.drivers = new Array("mike");
}
var car1 = new Car("red",1); //註意,此時Car本身的屬性和方法不能被訪問,隻能實例化之						 後訪問
					 //比如:console.log(new Car("red",1).color)
					 //這表示,構造函數真的是類似類的構造函數而非實例化對象,js也					  //有傳統意義的對象而不是隻有函數對象
//和方式1一樣Car的類內函數showColor將在每次構造時被構造出來,占據瞭沒必要的空間
var car2 = new Car("green",1);
car1.drivers.push("kiki");
console.log(car2.drivers); //不存在引用同一個數組的現象

3.原型方法:類似於Object派生,形成基於Object的原型鏈,再綁定方法和屬性
function Car(){};
Car.prototype.color = "red";
Car.prototype.showColor = function(){
		console.log(this.color);
}
//Car.prototyoe = { //把多個綁定的函數放進一個匿名的類來寫
//	mathod1:function(){...};
//	mathod2:function(){...};
//}
Car.prototype.drivers = new Array("mike","jhon");
var car1 = new Car(); //一定要創建實例才能調用方法訪問屬性
var car2 = new Car();
car1.drivers.push("bill");
console.log(car1.color);
console.log(car2.drivers);
//這樣綁定arry的屬性全部都指向同一個數組對象,屬於引用。當改變一個實例的color,所有的color都一起變瞭

混合方法:

1.構造函數+原型:構造函數內隻構造屬性和類內數組,而用原型的方式聲明類內函數
function Car(color){
	this.color = color;
	this.drivers = new Array("mike");
}
Car.prototype.showColor = function(){
	console.log(this.color);
}
var car1 = new Car(); //一定要創建實例才能調用方法訪問屬性
var car2 = new Car();
car1.drivers.push("bill");
console.log(car2.drivers); //避免瞭原型方法的缺點

2.使用class關鍵字定義類:不能在類外直接定義屬性,仍需要使用prototype方法在類外綁定函數對象。
class Car{
           constructor(color) {
                this.color = color;
           }
           drivers = new Array("mike","jhon");
           hello = function(){
           		return "Di Di"+ this.color; 
           }
           
        }

Car.prototype.hello = function (){ //類外綁定方法
            return "Di Di";
}

var car1 = new Car("red");
var car2 = new Car("green");
car1.drivers.push("kiki");
console.log(car1.color);
console.log(car2.hello());

綜上,當在類內定義變量時,在構造實例時會隨之一起調用構造函數進行構造,而類外綁定的方法、屬性將會是一種引用的形式不參與構造直接調用。同時,也便於保密,隱藏信息。

繼承

1.偽裝繼承:把類作為新類的構造函數來繼承,有點神奇,js裡類可以當成函數對象的奇特屬性
function Car1(color){
	this.color = color;
	this.showColor = function(){
		console.log("this car is "+this.color);
	}
	this.drivers = new Array("mike");
}

function Car2(){
	this.makeSound = function(){
		console.log("Di Di");
	}
}

function Car3(color){
	this.newConstruct = Car1; //作為構造函數傳入
	this.newConstruct(color); //調用構造函數
	delete this.newConstruct;
	this.newConstruct2 = Car2; //多重繼承,但是由於閉包機制,要用不同的構造函數名
	this.newConstruct2(); 
	delete this.newConstruct2;
}//同樣,偽裝繼承也可以用.prototype來綁定構造函數

var car1 = new Car3("red");
var car2 = new Car3("green");
car1.drivers.push("kiki");
console.log(car1.color);
car1.showColor();
car1.makeSound();
console.log(car2.drivers);

2.用父類的方法call和apply進行繼承
function Car1(color){
	this.color = color;
	this.showColor = function(){
		console.log("this car is"+this.color);
	}
}
function Car2(num){
	this.num = num;
	this.makeSound = function(){
		console.log("Di Di");
	}
}

function Car3(color,num){
	Car1.call(this, color);
	Car2.apply(this, augments);//augments為一個數組,包含所需的參數
}

var car1 = new Car3("red",1);
var car2 = new Car3("green",2);
console.log(car1.color);
console.log(car2.num);
car1.showColor();
car1.makeSound();

//也可以把.apply和.call寫在類外,但隻能對實例進行操作,不能用於構成類

3.用原型鏈進行繼承:使用__proto__和.prototype構成原型鏈,缺點是不能實現多重繼承,隻能通過綁定成構造函數或者再創造幾個類用鏈式方式繼承來來實現多重繼承
function Car1(color){
	this.color = color;
	this.showColor = function(){
		console.log("this car is"+this.color);
	}
}
function Car3(){};
Car3.prototype = new Car1();

4.用class...extends...,也可以實現繼承,但是不能實現多重繼承,也隻能像原型鏈一樣用多個類作為節點的方式來實現多重繼承,屬於是ES6的特性瞭。ES6還引入瞭let、public、private、protected關鍵字但是不能實現多重繼承,也沒有什麼包的概念也是挺奇葩的
class Car2 extends Car1{
           constructor(color) {
                super(); //類似java,super本身可以代表父類,此處是用瞭代表父類的
                		 //構造函數
                this.color = color;
           }
           drivers = new Array("mike","jhon");
           hello = function(){
           		return "Di Di"+ this.color; 
           }  
        }

5.使用參數可變的封裝函數extend(需要自己實現)實現多個類的按順序繼承extend(A,B,C)的鏈式繼承,B節點繼承A,C繼承B(實際上還是鏈式方式,但是封裝瞭好理解,是知乎大佬曉宏和csdn大佬浴盆的答案,https://blog.csdn.net/sysuzhyupeng/article/details/54846949知乎那個寫法不容易理解)。主要還是利用類可以為函數並可作為返回值的特性

所以,正常情況下:創建類用class或者構造函數+原型的方式;繼承類用class...extends...或者call方法。瞭解工廠方法和偽裝繼承。

重載就不細究瞭,和class一樣不完善,隻能自己用augments.length去實現。

到此這篇關於Js類的構建與繼承案例詳解的文章就介紹到這瞭,更多相關Js類的構建與繼承內容請搜索WalkonNet以前的文章或繼續瀏覽下面的相關文章希望大傢以後多多支持WalkonNet!

推薦閱讀: