var test = "Class01"; function Class01(privateValue, publicValue) { var _this = this; if (this.constructor.name !== 'Class01') { throw new Error('類只能被 ...
var test = "Class01";
function Class01(privateValue, publicValue) {
var _this = this;
if (this.constructor.name !== 'Class01') { throw new Error('類只能被實例化'); }
/*統計實例化次數的自執行函數*/
(function newClass() {
Class01.count++; /*統計實例化的次數*/
Class01.intances.push(_this); /*保存每個實例的引用*/
console.log(Class01.count);
})();
/*私有變數和私有方法*/
function privateMethod() { console.log('private method was called by publicMethod') } //
var privateVal = privateValue;
/*私有變數儲存介面*/
this.get = function () { return privateVal; };
this.set = function (v) { privateVal = v; return this; };
/*實例屬性和實例方法(一般並不會創建實例方法,如果一定要定義實例方法,實例化之後自行添加)*/
this.public = publicValue;
this.publicMethod = function () {
console.log('public method and then call private method');
privateMethod(); /*內部使用私有方法*/
return this;
};
/*實例方法可以使用類的靜態屬性和方法*/
this.callClassStaticMethod = function () {
console.log(Class01.staticValue);
Class01.staticMethod();
};
}
/* 原型屬性和方法
* 1、類被實例化次數和保存引用的數組也可以放在原型中
* 2、每個實例都擁有其他實例的引用和實例化次數
*/
Class01.prototype.proValue = 'this is Class01 prototype value';
Class01.prototype.proMethod = function () {
console.log('this is Class01 prototype method');
};
Class01.prototype.proArray = [1, 2, 3, 4, 5];
Class01.prototype.proObject = { a:'a' };
/* 靜態屬性和靜態方法
* 靜態屬性是否可用於儲存該類被實例化的次數,通過在類中加入一個自執行函數即可。
* 也可以在每次實例化的時候執行某種操作
* 1、比如當實例化的數量超過某個值的時候,拋出錯誤,告訴程式記憶體占用過高。
* 2、可以在類的靜態屬性中,保存每個實例的引用(肯定造成記憶體泄漏)。
*/
Class01.staticValue = 'this is class static value';
Class01.staticMethod = function () { console.log('this is class static method') };
Class01.count = 0;
Class01.intances = [];
/* 測試 Class01 */
if (test === "Class01") {
var instance01 = new Class01('private value1', 'public value1');
var instance02 = new Class01('private value2', 'public value2');
console.log(Class01.intances);
console.log('實例私有屬性');
console.log(instance01.get());
console.log(instance01.set('change private value1').get());
console.log(instance02.get());
console.log(instance02.set('change private value2').get());
console.log('實例屬性');
console.log(instance01.public);
console.log(instance02.public);
console.log('實例方法');
instance01.publicMethod();
instance02.publicMethod();
console.log(instance01.publicMethod === instance02.publicMethod);
console.log('實例原型屬性');
console.log(instance01.proValue);
instance01.proValue = 'instance01 change proto value';
console.log(instance01.proValue);
console.log(instance02.proValue);
/*instance01並沒有能夠修改原型屬性,而是在實例上創建了實例屬性*/
try {
/*無法在實例上改變原型上的屬性*/
instance01.prototype.proValue = 'class static value changed';
} catch (e) {
console.error(e);
}
try {
/*總之實例不允許使用prototype來使用屬性和方法*/
console.log(instance02.prototype.proValue);
} catch (e) {
console.error(e);
}
/*若原型屬性是數值/字元串/布爾值,實例是沒有手段可以修改。當原型屬性是引用時(數值/對象)時,便可以修改從而在所有的實例對象上會反應出來。*/
console.log(instance01.proArray);
instance01.proArray.push(6);
console.log(instance02.proArray);
console.log('類靜態方法');
instance01.callClassStaticMethod();
instance02.callClassStaticMethod();
try {
/*不能在實例上設置 prototype 方法(原因很簡單,十幾個人做一個項目,每個人都想往實例原型上添加方法,項目則無法完成)*/
instance01.prototype.print = function () {
console.log('prototype');
};
} catch (e) {
console.error(e);
}
try {
/*儘管 Class01 是 function 但是並不能執行*/
Class01();
} catch (e) {
console.error(e);
}
try {
/*顯然也不能採用 call 的方式。*/
var instance03 = {};
Class01.call(instance03, 'private value3', 'public value3');
} catch (e) {
console.error(e);
}
/*以下這種方法,能夠使用 Class01 進行函數式"實例化",但是原型都消失了。*/
function Class01_t() {
}
Class01_t.prototype.constructor = {name: 'Class01'};
var instance04 = new Class01_t();
Class01.call(instance04, 'private value4', 'public value4');
console.log(instance04);
/* 下麵這種方法能夠完美模擬 Class01 實例化
* 1、以下例子可以看出,在Class01_t2中,可以添加實例新的屬性和方法。
* 下麵從繼承的角度去看。
* 2、Class01_t2中定義的屬性和方法,顯然會被 Class01中的覆蓋掉。
* 3、在Class01_t2原型上添加方法和屬性,顯然會覆蓋Class01的。從而影響所有的由Class01創建的實例
* 4、無論如何,Class01靜態方法和屬性都在constructor中
* 目前的主題並不是類的繼承,關於function類的實例化和相關知識目前先介紹這麼多。
*/
function Class01_t2() {
console.log('Class01_t2 was called');
Class01.call(this, 'private value5', 'public value5');
/* 從此處開始可以劫持Class01的公有屬性和方法,無法劫持私有的屬性和方法(無法取得其引用,自然無法調用)。
* 使用 Function.prototype.after 的方式可以實現劫持各種方法。
*/
}
Class01_t2.prototype = Class01.prototype;
var instance05 = new Class01_t2();
console.log(instance05);
instance05.constructor.staticMethod();
console.log(instance05.constructor === Class01);
/*構造函數指向 Class01;*/
console.log(instance05.prototype);
/*undefined*/
console.log(instance04.prototype);
/*undefined*/
console.log(instance01.prototype);
/*undefined*/
console.log(Class01_t2.constructor === Class01.constructor);
/*構造函數相等*/
console.log(Class01_t2.__proto__ === Class01.__proto__);
/*true*/
console.log(instance05.__proto__ === instance01.__proto__);
/*true*/
console.log(instance05.constructor.name);
/*Class01*/
/*通過實例的 constructor 可以找到類。可以通過new constructor 從而可以從類實例化。*/
console.log(instance05.__proto__.constructor === Class01);
/*true*/
console.log(instance05.constructor === Class01);
/*true*/
var instance06 = new instance05.constructor('private value6', 'public value6');
console.log(instance06.get());
/* 總結
* 1、只有函數才能被實例化,實例化之後得到的變數是實例並不是函數,或者說是object
* 2、有一種可以不修改 Class01 也可以擴充變數或方法(公有或私有)的方式,上述 Class01_t2
* 對於這種方式,由相當多的內容可以想象:比如是否可以劫持Class01中的公有方法
*/
}