理解javascript函數的關鍵就是拋棄主流物件導向語言中“類”的觀念。
主流的物件導向語言,例如C++,先寫好“類”的定義。當需要對象時,用new關鍵字去划出一片記憶體來,賦上初值,就有了一個對象(“類”的“執行個體”)。混淆的來源是javascript語言模仿了物件導向的文法,看到Object,new之類的關鍵字,很難不讓人去聯想那些傳統的物件導向的經典概念。
我們可以優雅的模仿“類”的觀念,但是始終要提醒自己,javascript只有對象,沒有類。
//Animal是一個對象 Animal = { createNew: function( bundle ) { var animal = {}; var protect = bundle || {};//bundle傳遞的是指標,修改protect時外面對象會跟著變(除非不傳) protect.sound = 'growl'; protect.makeSound = function(){ return protect.sound; } return animal; } } //Cat也是一個對象 Cat = { createNew: function(mySound) { var protect = {}; var cat = Animal.createNew( protect );//protect會被修改,然後返回空白對象{}給cat protect.sound = mySound; cat.meow = function(){ return protect.makeSound(); };//cat要調用protect中的方法 return cat; } } //javascript區分大小寫,通過Cat物件建構一個新的對象賦值給cat var cat = Cat.createNew("meow!"); pt("cat.sound");//cat不能直接存取sound pt("cat.meow()");//通過函數可以訪問sound var bigCat = Cat.createNew("meow!meow!meow!"); pt("bigCat.sound");//bigCat也不能直接存取sound pt("bigCat.meow()");//通過函數可以訪問sound
調試資訊:
cat.sound undefined
cat.meow() meow!
bigCat.sound undefined
bigCat.meow() meow!meow!meow!
[備忘] 如果希望大貓(bigCat)小貓(cat)有公用的屬性,因為Cat本身也是一個對象,所以可以在Cat中定義對象作為公用屬性,並在createNew中增加操縱此公用屬性的函數。
模仿“類”的觀念讓我聯想到了東施效顰的典故。東施模仿西施優雅的舉止肯定是不能達到西施的水準,但是東施難道就沒有自己的特長嗎?例如,做家務會不會比西施更能幹呢?javascript函數最大的好處就是可以賦值給變數,因而我們可以編寫“函數的函數”,或者,把函數當參數傳來傳去,函數也可以有自己的方法,諸如此類。還記得在學習早期結構化的程式設計語言(例如Fortran和C)時,被糾正說不能傳遞函數當參數嗎?
Function.prototype.run=function(){ return "run~~"; } pt("cat.meow.run()");//函數也可以有方法
調試資訊:
cat.meow.run() run~~