JavaScript-物件導向

  • 257
  • 0
  • JS
  • 2020-10-04

JS是物件導向語言,但與JAVA或C#等物件導向語言有一些差異,JS的物件實體化概念不是類別而是稱為原型(Prototype)

此種性質是以原型為基礎的物件導向


 

定義簡單的類別

var Member=function(){}
	var mem=new Member();//以Member類別實體化一個mem物件

建構子初始化

var Member=function(age,tel){//在建構子加入屬性初始化
		this.age=age;//this表示所建立的實體本身
		this.tel=tel;
		this.getData=function(){
			return this.age+' '+this.tel;
		}
	};
	var mem=new Member(20,'123456789');
	console.log(mem.getData());
//建構子不允許有回傳值

動態新增建構子內的方法

var Member=function(age,tel){
		this.age=age;
		this.tel=tel;
	};
	var mem=new Member(20,'123456789');
	mem.getData=function(){
		return this.age+' '+this.tel;
	}
	console.log(mem.getData());
//其他實體呼叫getData方法會出現錯誤訊息,因為此種方法並不是針對Member類別

prototype屬性

透過prototype所新增的成員類別所建立的方法,所有實體都可使用

var OpNumber=function(x,y,){
		this.x=x;
		this.y=y;
	};
	OpNumber.prototype.addNum=function(){//使用prototype屬性加入addNum方法
		return this.x+this.y;
	};
//建立兩個物件都呼叫addNum方法
	var sum=new OpNumber(3,4);
	console.log(sum.addNum());
	var sum2=new OpNumber(7,3);
	console.log(sum2.addNum());

使用原型物件有以下優點

  • 節省記憶體空間(使用參考的方式所以不會複製到實體中)
  • 能立即反應新增或刪除的成員(意思是即使新增或刪除的成員是在建立實體之後,也能正常操作)

使用protype設定屬性

var Seq=function(){};
	Seq.prototype.id='1';//使用prototype設定id屬性為1
	var seq1=new Seq();
	var seq2=new Seq();
	console.log(seq1.id+','+seq2.id);//1,1
	seq2.id='2';
	console.log(seq1.id+','+seq2.id);//1,2

從以上執行結果可以看出使用prototype所設定的屬性是參考值,也就是實體假如沒有id屬性將會參考到由prototype所建立的原型屬性

之後因為seq2已經有建立自己的id屬性值,所以就不再參考到原型屬性

定義原型的物件常值

如果需要設定的原型屬性有多個,使用物件常值設定會較簡潔,而且可增加程式可讀性(同一物件的成員都被定義在同一個區塊)

var OpNumber=function(x,y){
		this.x=x;
		this.y=y;
	};
	OpNumber.prototype={
		add:function(){//add方法
			console.log(this.x+this.y);
		},
		minus:function(){//minus方法
			console.log(this.x-this.y);		
		}
	};
	var num1=new OpNumber(9,5);
	var num2=new OpNumber(9,5);
	num1.add();
	num2.minus();

定義靜態屬性與方法

靜態屬性與方法不需透過建立實體就可直接用物件呼叫,但是不可在原型物件中定義

var OpNumber=function(){};
	OpNumber.num1=1;//定義兩個靜態屬性num1,num2
	OpNumber.num2=2;
	OpNumber.addNum=function(x,y){//定義靜態方法
		return x+y;
	};
	console.log('num1= '+OpNumber.num1);//呼叫靜態屬性
	console.log('num2= '+OpNumber.num2);
	console.log(OpNumber.addNum(9,9));//呼叫靜態方法
var op=new OpNumber();
op.num1//使用實體呼叫靜態方法或屬性會發生錯誤

靜態屬性的使用特點

基本上都使用在唯讀屬性

靜態方法中不可有this

物件繼承

使用物件繼承就不需要在多個類別中建立多個重複的方法

var OpNumber=function(){
	};
	OpNumber.prototype={
		add:function(){
			console.log(this.x+this.y);
		}
	};
	var Sum=function(x,y){
		this.x=x;
		this.y=y;
		OpNumber.call(this);//設定Sum物件實體參考到OpNumber
	};
	Sum.prototype=new OpNumber();//使用目前的this呼叫OpNumber建構子
	Sum.prototype.minus=function(){
		console.log(this.x-this.y);
	};
	var num1=new Sum(5,3);
	num1.add();
	num1.minus();

私有成員

私有成員只有類別內部的方法可以存取的屬性與方法

function Cal(){
        //在建構子內使用var定義私有成員與方法,不是使用this
		var _x;
		var _y;
		var _add=function(){
			return _x+_y;
		}
//因為私有成員無法直接透過外部存取,所以需要透過下面三個存取器來設定與取得屬性值
		this.set_xy=function(x,y){//設定器
			_x=x;
			_y=y;
		}
		this.get_xy=function(){//取得器
			return _x,_y;
		}
		this.get_add=function(){
			return _add();
		}
	}
	var num1=new Cal();
	num1.set_xy(6,5);
	console.log(num1.get_xy());
	console.log(num1.get_add());
	console.log(num1._x);//直接存取會出現undefined
	console.log(num1._y);//直接存取會出現undefined
//JS的私有成員無法像C#或JAVA等物件導向語言,可以在相同類別內存取,必須使用如閉包一樣的方式

定義類別-class

ES6之後JS導入了class指令,如同C#或JAVA的方式

class OpNumber{//建立OpNumber類別
		constructor(x,y){//建構子
			this.x=x;
			this.y=y;
		}
		getAdd(){//相加方法
			return this.x+this.y;
		}
		getMinus(){//相減方法
			return this.x-this.y;
		}
	}
	let num1=new OpNumber(10,5);
	console.log(num1.getAdd());
	console.log(num1.getMinus());

類別內定義靜態方法

class OpNumber{
//在類別內靜態方法與屬性要用static指令定義
		static x=10;//定義靜態屬性
		static y=5;//定義靜態屬性
		constructor(x,y){
			this.x=x;
			this.y=y;
		}
		static getAdd(){//靜態方法
			return OpNumber.x+OpNumber.y;//靜態方法不可使用this
		}
		getMinus(){
			return this.x-this.y;
		}
	}
	let num1=new OpNumber(10,5);
	console.log(OpNumber.getAdd());//使用類別名稱.屬性方式呼叫
	console.log(num1.getMinus());

繼承類別

class Son extends Father//使用extends指令繼承

模組功能

export class OpNumber{...}//設定要匯出模組的類別

import{OpNumber} form 'Url'//載入模組