OOP里耳胎,class和interface是很有用的兩個東西奖年,廢話细诸。
在JS/ES中,class被prototype取代陋守,而interface則完全沒影震贵。
那么,class和interface到底有什么區(qū)別呢水评?
如果只是將class和interface看做是定義了一套方法的話屏歹,那么class和interface之間的區(qū)別大概只能看做是前者實現(xiàn)了方法(abstract的當(dāng)然就沒實現(xiàn)了),而后者沒實現(xiàn)這套方法了之碗。
所以class可以用作代碼復(fù)用蝙眶,而interface顯然不能。
從這個角度來看的話褪那,兩者的區(qū)別的確不大幽纷。
不過這其實不是重點。
重點在于博敬,從C++時代后開始友浸,class不能多重繼承就(C++里當(dāng)然還是可以的),但interface卻可以多重實現(xiàn)偏窝。
因此收恢,class和interface的區(qū)別就體現(xiàn)了出來:class的作用更多的想是設(shè)計藍(lán)圖,而interface則是不同對象之間互動的協(xié)議祭往。
也就是說伦意,class規(guī)范了object的性質(zhì),而interface規(guī)范了object之間的交互硼补。
interface給出了在一個上下文環(huán)境中一個對象可以提供的服務(wù)驮肉,并且對于超出的部分不予理睬。
好了已骇,明白了這點离钝,就可以來搞一套雖然完全沒什么意義但還是很好玩的ES6的實現(xiàn)了——
其實這套方案ES5里也能玩票编。
var ClassTest;
(function () {
var id = 0;
ClassTest = class {
constructor (name) {
var _id = id;
this.name = name;
Object.defineProperty(this, 'id', {
configurable: false,
enumerable: true,
get: function () {
return _id;
},
set: function (nouse) {},
});
id ++;
this.value = 0;
}
toString () {
return "I'm " + this.name + ", the " + this.id + "nth child of THE DARK LORD!";
}
add (value) {
this.value += value;
return this;
}
minus (value) {
this.value -= value;
return this;
}
time (value) {
this.value *= value;
return this;
}
divide (value) {
this.value /= value;
return this;
}
Add (value) {
this.value += value;
return this.value;
}
Minus (value) {
this.value -= value;
return this.value;
}
Time (value) {
this.value *= value;
return this.value;
}
Divide (value) {
this.value /= value;
return this.value;
}
};
})();
var test1 = new ClassTest('Aloha'), test2 = new ClassTest('Kosmos');
class ClassOther {
constructor () {
this.name = "MiaoWu~~~";
this.id = 0;
}
toString () {
return "I'm Nothing...";
}
}
var other = new ClassOther();
class Interface {
constructor (kernel, options) {
options = options || {};
if (!!options.changable) {
Object.defineProperty(this, 'kernel', {
configurable: false,
enumerable: false,
writable: true,
value: kernel,
});
}
else {
Object.defineProperty(this, 'kernel', {
configurable: false,
enumerable: false,
get: function () {
return kernel;
},
set: function (nouse) {},
});
}
if (!!options.frozen) {
Object.freeze(this);
}
}
get value () {
if (isNaN(this.kernel.value)) return 0;
else return this.kernel.value;
}
set value (nouse) {}
get description () {
if (!!this.kernel.toString) return this.kernel.toString();
else return "EMPTY";
}
set description (nouse) {}
add (value) {
if (!!this.kernel.add) return this.kernel.add(value);
else return this;
}
minus (value) {
if (!!this.kernel.minus) return this.kernel.minus(value);
else return this;
}
time (value) {
if (!!this.kernel.time) return this.kernel.time(value);
else return this;
}
divide (value) {
if (!!this.kernel.divide) return this.kernel.divide(value);
else return this;
}
}
var int1 = new Interface(test1, { changable: true });
var int2 = new Interface(test2, { frozen: true });
在上面的例子中,我們先定義了兩個類(ES6中的類基本可以看做Syntactic Sugar)卵渴,然后構(gòu)造了一個接口慧域。
這個接口的作用非常簡單,就是將真正的數(shù)據(jù)與操作行為分離開浪读,從而操作層的錯誤操作不會影響到真正的數(shù)據(jù)吊趾。
事實上,這里我們完全可以再定義一個接口只實現(xiàn)Add瑟啃、Minus论泛、Time和Divide這四個函數(shù)。
從而我們可以看到蛹屿,通過不同的接口屁奏,我們只能操作特定的方法、訪問特定的屬性错负,且任何在接口上的操作都不會影響到真正的數(shù)據(jù)——除非提供了方法讓你去修改坟瓢。
從而,這個模型就可以實現(xiàn)M與C的隔離犹撒。
其中還提供了兩個參數(shù)折联,一個用來控制接口實例是否可以替換真正的數(shù)據(jù),而另一個則控制接口實例是否可以擁有自己的屬性识颊。
從某種程度來說诚镰,這個Interface就是給一個真正的Data穿上了一件衣服,只露出那些想要露出的祥款,而將那些不想露出的部分遮掩起來清笨。
當(dāng)然啦,最后還是要說:這套方案其實并沒有什么真正的大用處——我直接訪問Interface實例的kernel對象不就好了(當(dāng)然這樣的話一個很雞賊的方式就是直接把所有方法與屬性全部寫在constructor里從而這個Interface沒有prototype從而可以保證你訪問不到kernel)刃跛。
畢竟ES不是OOP抠艾,硬將OOP中的東西弄到ES中很多時候是沒必要的,反而破壞了ES本身Prototype Chain的美好——所以當(dāng)我看到ES6里OOP的味道加重后總是感覺很不適應(yīng)……(大家別理我這枚異端)
最后PS一下:上面所說的方案其實和ES6半毛錢關(guān)系都沒有桨昙,在ES5里都能做到毫無障礙检号,科科。