看到好多書評和讀書筆記都說《JavaScript語言精粹》字字珠璣,名不虛傳。。固然,要看得懂才行javascript
其實我的認爲函數化部分不是很好,舉的例子不是十分恰當,以前看不懂是由於被成功誤導了,就像《Head First》設計模式第一章《策略模式》同樣,做者有些偏離章節主題,讀者容易被誤導html
聲明:姑且把函數化部分給出的用來建立對象的函數稱爲「創造函數」吧,爲了與「構造函數」區分開。。不是很好聽,將就着用吧java
很容易就能拿到源碼,和中文版書上的代碼同樣,仔細看了一遍發現了一個很精妙的地方,固然,不是很好理解設計模式
P.S.源碼有點小問題:「創造函數」cat花括號不匹配,中文版54頁,return that;
以前少了};
安全
Object.method('superior', function (name) { var that = this, method = that[name]; return function ( ) { return method.apply(that, arguments); }; });
亮點就是最後一句的arguments,看似無意,實際上是有意爲之的,代表用superior調用父類方法時也能夠傳參。固然,傳參的話須要修改調用方式,測試代碼以下:app
Function.prototype.method = function (name, func) { this.prototype[name] = func; return this; }; var mammal = function (spec) { var that = {}; that.get_name = function ( ) { return spec.name; }; that.says = function ( ) { return spec.saying || ''; }; return that; }; var cat = function (spec) { spec.saying = spec.saying || 'meow'; var that = mammal(spec); that.purr = function (n) { var i, s = ''; for (i = 0; i < n; i += 1) { if (s) { s += '-'; } s += 'r'; } return s; }; that.get_name = function ( ) { alert("cat.get_name :" + arguments.length);/// return that.says( ) + ' ' + spec.name + ' ' + that.says( ) + "[" + arguments.length + "]"; }; return that; }; Object.method('superior', function (name) { var that = this, method = that[name]; return function ( ) { alert("superior :" + arguments.length);/// return method.apply(that, arguments); }; }); var coolcat = function (spec) { var that = cat(spec), super_get_name = that.superior('get_name'); that.get_name = function () { alert("coolcat.get_name :" + arguments.length);/// return 'like ' + super_get_name.apply(this, arguments) + ' baby'; }; return that; }; var myCoolCat = coolcat({name: 'Bix'}); var name = myCoolCat.get_name(1, 2, 3); // 'like meow Bix meow baby' alert(name); // 'like meow Bix meow[3] baby'
P.S.開始覺得superior函數最後的arguments是做者的錯誤,以爲應該須要把外面的arguments對象傳給method而不是裏面的,繞了一大圈發現是本身錯了,道行不夠,沒能秒懂道格拉斯大爺的意思。。函數
函數化部分開篇就說明了初衷:爲了實現私有屬性,建立最後提到的「防僞對象」學習
目的無可厚非,實現私有屬性太有必要了。但舉的例子mammal -> cat -> coolcat太不合適了,做者想說明用函數化的方式能夠實現繼承測試
固然,不是嚴格意義上的繼承,由於函數化方式沒有用到自定義類型,子類實例與父類實例的is-a關係也就無從談起了this
P.S.看第一遍的時候cat的例子就把我帶到溝裏去了,覺得函數化就是要拋棄new,徹底用函數來實現繼承。。天然是在溝裏越走越深了
直接看代碼,代碼本身會說話:
/* * 函數化的思想: * 1.建立對象 * 2.添加私有屬性 * 3.公開接口(添加公有屬性) * 4.返回該對象 */ /* * method: getSuper * @param spec 規格說明對象,提供建立對象所需的基本數據 * @param my 「創造函數」之間共享數據的容器 */ function getSuper(spec, my){ var obj; // 要返回的對象 var my = my || {}; // 沒傳入就建立一個 // 私有屬性 var attr = spec.value; // 從規格說明對象取數據 var fun = function(){ alert(attr); } // [可選]把須要與其它「創造函數」共享的數據裝入my // 建立對象,能夠用任意方式,好比new、字面量、調用其它「創造函數」 obj = { name: "SuperObject" }; // 公開接口 obj.fun1 = fun; // 返回obj return obj; } /* * method: getSub * 參數同上 */ function getSub(spec, my){ var obj; var my = my || {}; // 私有屬性 var attr = spec.value + 1; var fun = function(){ alert(attr); } // [可選]共享 // 建立對象 obj = getSuper(spec, my); // 能夠直接傳過去,固然也能夠改一改再傳,或者傳別的什麼 // 公開接口 obj.fun2 = fun; // 返回obj return obj; } // 測試 var spec = { value: 1 }; var sub = getSub(spec); // 不用傳入my,my只應該在「創造函數」之間用 sub.fun1(); // 1 sub.fun2(); // 2
P.S.又是「建立對象 -> 加強 -> 返回新對象」這個套路,不就是尼古拉斯所說的由道格拉斯發明的「模塊模式」嗎?
函數化部分的核心就是它了,注意上面例子中公開接口的方式:
// 私有屬性 var myFun = function(){/* ... */}; // 公開接口 obj.fun = myFun;
而不直接用:
// 公開接口 obj.fun = function(){/* ... */};
第一種方式更安全,由於即使從外界修改了fun,內部其它調用了myFun的方法仍然能夠正常工做,這樣的函數對象就是所謂的防僞對象了
完整定義:
防僞對象的屬性能夠被替換或者刪除,但該對象的完整性不會受到損害
也被稱爲持久性的對象,一個持久性對象就是一個簡單功能函數的集合
到這裏《JavaScript語言精粹》的學習筆記就告一段落了,補好了[函數化]的空缺,學習筆記的其它部分請查看黯羽輕揚:《JavaScript語言精粹》學習筆記