原文地址:http://blog.chinaunix.net/uid-15223977-id-2774362.html
在js中利用new、this和prototype三個關鍵字可以實現完備的面向對象特徵。而創建一個新的對象new關鍵字是不可缺少的。
只用new創建一個最簡單的對象:(1)
var t = new Object;
t.a = 'test' ;
t.b = function (){alert(t.a)};
t.b();
|
彈出“test”再利用new和this關鍵字改進:(2)
var t = new Object;
t.a = 'test'
t.b = function (){alert(this.a)};
t.b();
|
彈出“test”,但仍不能實現重複建立多個實例。改進:(3)
function test() {
this.a = 'test';
this.b = function (){alert(this.a)};
return 1; } var t = test(); alert(a);
b(); alert(t); alert(t.a);
t.b();
|
依次,彈出test、彈出test、彈出1、undefined、對象不支持此屬性或方法。可見,直接調用函數時,t只是函數的返回值,並不是需要的對象。由於test是由window對象調用的,this指代了window對象,把a和b賦給了window對象。加上new:(4)
function test() {
this.a = 'test';
this.b = function (){alert(this.a)};
return 1; } var t = new test(); alert(t); alert(t.a);
t.b(); alert(a);
b();
|
依次,彈出[object Object]、彈出test、彈出test、編譯錯誤'a'未定義、停止執行。可見,用new運算符時,調用test函數的對象被賦給了t,this指代t對象,函數返回值被忽略。a和b()在window上未定義。也可以採用函數返回值的方式建立對象:(5)
function test() {
var t = new Object;
t.a = 'test';
t.b = function (){alert(this.a)};
return t; } var t1 = test(); alert(t1); alert(t1.a);
t1.b();
var t2 = test();
t2.a = 'test2'; t2.b;
alert(Object.a); Object.b();
|
以上依次,彈出[object Object]、彈出test、彈出test、彈出test2、彈出undefined、編譯錯誤:對象不支持此屬性或方法,停止執行。可見,在函數內部new操作符新建了個基本對象並返回,兩個test實例不相互影響,也不影響Object對象。但是上面的4和5的例子都有個弊端就是b方法其實只是一個函數指針,兩個指針所指向的函數在調用構造函數時即時創建,並非爲同一個程序實例,造成存儲空間浪費。一種改進方案是:(6)
var test_b = function (){alert(this.a)}; function test() {
var t = new Object;
t.a = 'test';
t.b = test_b;
return t; } var t1 = test();
t1.b(); var t2 = test();
t2.a = 'test2';
t2.b();
|
這樣兩個實例的b屬性爲同一個值test_b指針,都指向同一個函數。除了這種方式還有一種辦法做到,那就是js內置於每個對象中的對象類型原型的引用prototype屬性。用prototype屬性提供對象的類的一組基本功能,對象的新實例“繼承”賦予該對象原型的操作。看示例:(7)
function test() {
this.a = 'test'; } test.prototype.b = function (){alert(this.a)}; test.prototype.c = new Array();
test.prototype.d = 5; var t1 = new test();
t1.b(); var t2 = new test();
t2.a = 'test2';
t2.b(); //////
t1.c = [1,2];
alert(t1.c);
t2.c[1] = 4;
alert(t2.c); alert(t1.c);
//////
t2.d = 6; alert(t2.d); alert(t1.d);
|
依次,彈出test、彈出test2、彈出1,2,彈出1,4,彈出1,2,彈出6,彈出5。可見,目的達到了,後面的示例說明:當prototype的屬性爲對象的引用時,它爲指向對象的指針,和普通變量一樣被每個實例繼承。另外,prototype屬性在對象被實例化前創建。也不可以放在函數內因爲那樣每次實例化對象時,都會爲prototype的屬性重新賦值,那樣仍然沒達到目地。在看下js中的繼承:(8)
function test() {
this.a = 'test';
this.b = function (){alert(this.a)}; } function subTest() {
this.peraP = test;
this.peraP();
this.subName = 'subTest'; } var t1 = new test();
t1.b(); var t2 = new subTest();
t2.b(); alert(t2.subName);
|
依次輸出:彈出test、彈出test、彈出subTest。在子類的構造函數內,用this調用父類構造函數,實現繼承。當類的構造函數不需要傳遞參數時,也可以使用原型鏈實現繼承。例:(9)
function test() {
this.a = 'test'; } test.prototype.b = function (){alert(this.a)};
function subTest() {
this.subName = 'subTest'; }
subTest.prototype = new test;
subTest.prototype.showName = function (){alert(this.subName)};
var t1 = new test();
t1.b(); var t2 = new subTest();
t2.b();
t2.showName();
|
依次輸出:彈出test、彈出test、彈出subTest。當父類的構造函數不需要傳遞參數時,可以用subClass.prototype = new ParentClass;
的方式覆蓋子類的prototype原型,子類的新原型屬性放在後面添加。
附錄:
new 運算符
new 運算符執行下面的任務:1、創建一個沒有成員的對象。2、爲那個對象調用構造函數,傳遞一個指針給新創建的對象作爲 this 指針。3、然後構造函數根據傳遞給它的參數初始化該對象。
this 語句
指當前對象。
this.property必選的 property 參數指的是對象的屬性。說明this 關鍵字通常在對象的構造函數中使用,用來引用對象。
對於 JScript 的客戶版本,如果在其他所有對象的上下文之外使用 this,則它指的是 window 對象。prototype 屬性
返回對象類型原型的引用。
objectName.prototype
objectName 參數是對象的名稱。
說明
用 prototype 屬性提供對象的類的一組基本功能。對象的新實例“繼承”賦予該對象原型的操作。所有 JScript 內部對象都有 prototype 屬性。