首頁 > web前端 > js教程 > 理解JavaScript創建對象與透過原型創建對象

理解JavaScript創建對象與透過原型創建對象

巴扎黑
發布: 2017-08-09 11:21:39
原創
915 人瀏覽過


一、建立物件的幾種方式

1、各自獨立宣告模式

var box1 = new Object();	//声明第一个对象并给各属性赋值
box1.name = 'Lee';
box1.age = 100;
box1.run = function () {
	return this.name + this.age + '运行中...';
};
alert(box.run());

var box2 = new Object();	//声明第二个对象并给属性赋值
box2.name = 'Jack';
box2.age = 200;
box2.run = function () {
	return this.name + this.age + '运行中...';
};
alert(box2.run());
登入後複製

此時box2和box1是互相獨立的,不會混淆。

但是這樣子每聲明一個結構相同的對象,都得加一段程式碼,特別不方便,所以有了下面的工廠模式。

2、工廠模式

function createObject(name, age) { //集中实例化的函数
	var obj = new Object();
	obj.name = name;
	obj.age = age;
	obj.run = function () {
		return this.name + this.age + '运行中...';
	};
	return obj;
}
登入後複製

這樣子每次new物件時只需呼叫createObject()方法即可,同時,也可以傳參初始化物件。
但由於new出來的物件都從屬於Object,當我要讓new出來的物件在本質做一些區分的時候,就不行了,此時就有了更簡便的建構子模式。

3、建構函式模式

function Box(name, age) {
	this.name = name;
	this.age = age;
	this.run = function () {
		return this.name + this.age + '运行中...';
	};
}
var box1 = new Box('Lee', 100);
var box2 = new Box('Jack', 200);
alert(box1.run());
alert(box1 instanceof Box); //很清晰的识别他从属于Box
登入後複製

建構子模式很大程度上解決了物件重複使用及傳參初始化問題,是最常用的new物件的模式。
注意: 

此處box1.run != box2.run, 因為他們判斷的是引用位址,由此可知,兩個物件的方法分別儲存在不同的地方,是兩個不同的方法。
box1.run() == box2.run(),因為它們傳回值一樣。
當有了物件以後,自然而然就會涉及到物件屬性及方法的共享問題(例如,在java中子類別們共享父類別的成員變數及方法)。
建構函式模式建立出來的物件說白了還是互相獨立的(例如上面的box1.run != box2.run),如果我要在兩個物件之間共用某些屬性的話,就必須採用原型prototype了。

二、透過原型建立物件

1、原型模式

function Box() {} //声明一个构造函数
Box.prototype.name = 'Lee'; //在原型里添加属性
Box.prototype.age = 100;
Box.prototype.arr = ['aaa','bbb'];
Box.prototype.run = function () { //在原型里添加方法
	return this.name + this.age + '运行中...';
};
var box1 = new Box();
var box2 = new Box();

//修改普通属性,看下会不会影响prototype
alert(box1.name);	//Lee
box1.name = 'Rinima';
alert(box1.name);	//Rinima
alert(box2.name);	//Lee,修改box1的普通属性,相当于直接在box1中添加一个属性,是不会牵扯到原型中的属性的。
					//这一点非常好。但是如果是引用对象(数组)的话,就有问题了。

//修改引用属性,看下会不会影响prototype
alert(box1.arr);	//aaa,bbb
box1.arr.push('ccc');
alert(box1.arr);	//aaa,bbb,ccc
alert(box2.arr);	//aaa,bbb,ccc,修改box1的引用属性,却牵扯到了原型中的属性。
			//这是因为arr只是个引用地址,指向数组真实存储的位置,修改box1中的引用属性就是修改引用所指向的数组,所以原型也被修改了
			//这是我们不希望看到的!
登入後複製

此模式的優點: 

1、所new出來的物件在prototype中的屬性是共享的,此時box1.run == box2.run
2、能保證所new的物件實例的屬性完全統一(和缺點2相對)
該模式的缺點: 

1、當含有引用型別的屬性時,引用型別所指向的屬性是存在prototype中,直接在物件中修改引用屬性就把所有物件的引用屬性都修改了
2、該種模式省略了初始化傳參,使得new出來的所有屬性都是一樣的

1.1、原型字面量模式

(原型模式的另一個模式,大體上差別不大,都屬於原型模式)

function Box() {};
Box.prototype = { //使用字面量的方式
	constructor : Box,
	name : 'Lee',
	age : 100,
	run : function () {
		return this.name + this.age + '运行中...';
	}
};
登入後複製

此模式繼承了原型模式的所有優缺點,但是也有自己特有的優缺點
優點: 更好的體現了封裝性
缺點: constructor沒有指向自身,必須手動強制指向

2、建構子+原型模式

function Desk(name, age) { //不共享的使用构造函数
	this.name = name;
	this.age = age;
	this.family = ['aaa', 'bbb', 'ccc'];
};
Desk.prototype = { //共享的使用原型模式
	constructor : Desk,
	run : function () {
		return this.name + this.age + this.family;
	}
};

var desk1 = new Desk('Lee',100);
var desk2 = new Desk('Jack',200);
alert(desk1.family);	//aaa,bbb,ccc
desk1.family.push('ddd');
alert(desk1.family);	//aaa,bbb,ccc,ddd
alert(desk2.family);	//aaa,bbb,ccc
登入後複製

優點: 這種模式完美解決了共享屬性與不共享屬性的問題,而且可以精確控制,是非常不錯的模式。
缺點: 但是此種辦法,原型與建構子相分離,讓人感覺很怪異,體現不了封裝。

3、動態原型模式

function Box(name ,age) { //将所有信息封装到函数体内
	this.name = name;		//不共享的属性
	this.age = age;
	
	if (typeof this.arr != 'object') {		//共享的属性
		alert('在第一次调用的时候...arr');
		Box.prototype.arr = ['aaa','bbb'];
	}
	if (typeof this.run != 'function') {
		alert('在第一次调用的时候...run');
		Box.prototype.run = function () {
			return this.name + this.age + '运行中...';
		};
	}
}
var box1 = new Box();
var box2 = new Box();
alert( box1.arr );		//aaa,bbb
box1.arr.push('ccc');
alert( box1.arr );		//aaa,bbb,ccc
alert( box2.arr );		//aaa,bbb
登入後複製


優點:這個模式繼承了上一個模式(建構+原型)的所有優點,同時也完美解決了封裝性問題
注意:此種模式書寫原型時不可用字面量模式,會切斷實例和新原型之間的聯繫的。 ? ? ?

基本上到這裡,以上兩種模式已經能處理大多數問題,而且是比較好的模式了。
但是,還是有一些比較特定的需求,需要用到以下兩種比較另類的模式。


4、寄生建構子模式(工廠模式+建構子模式)

function Box(name, age) {
	var obj = new Object();
	obj.name = name;
	obj.age = age;
	obj.run = function () {
		return this.name + this.age + '运行中...';
	};
	return obj;
}
登入後複製

5、穩健建構子模式

function Box(name , age) {
	var obj = new Object();
	obj.run = function () {
		return name + age + '运行中...'; //直接打印参数即可
	};
	return obj;
}
登入後複製

穩做建構函式模式,是當建構函式裡不允許使用this,外部實例化時不準用new時,才需要用到的模式。
我也不知道為啥會出現這樣那麼奇葩的需求。不過這麼多的創建物件模式,確實比Java眼花撩亂多了。

#

以上是理解JavaScript創建對象與透過原型創建對象的詳細內容。更多資訊請關注PHP中文網其他相關文章!

相關標籤:
來源:php.cn
本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn
熱門教學
更多>
最新下載
更多>
網站特效
網站源碼
網站素材
前端模板