CoffeeScript 中對(duì)象的綁定
有時(shí)候你需要一個(gè)函數(shù)運(yùn)行在特定的上下文對(duì)象中,而不管它在哪里被調(diào)用。比如有類(lèi)似這樣一個(gè)函數(shù):
callback = (message) –> @v.push message
當(dāng)直接調(diào)用這個(gè)函數(shù)時(shí) @(this)所代表的就是全局對(duì)象,如果通過(guò) call 或者 apply 指定了其他的上下文對(duì)象,@ 則代表了其他上下文對(duì)象。有什么辦法使 @ 綁定為特定的上下文對(duì)象呢?
在 CoffeeScript 中有一個(gè)非常方便的方式,只要用 => 代替 –> 定義需要綁定特定上下文對(duì)象的函數(shù)即可,比如以上 callback 函數(shù):
callback = (message) => @v.push message
此時(shí)的 @ 指代的就是該函數(shù)定義時(shí)所在的上下文對(duì)象。以上函數(shù)解析成 javascript 就是:
var callback,
_this = this;
callback = function(message) {
_this.v.push(message);
};
那為什么不直接用 => 代替 –> 呢?
增加了代碼量以及運(yùn)行時(shí)間,并且這是沒(méi)有必要的
為了適應(yīng)復(fù)雜的上下文對(duì)象,可以提供更加優(yōu)雅的代碼編寫(xiě)方式
在你定義函數(shù)的時(shí)候一定要非常認(rèn)真考慮使用 this/@ 指定正確的上下文對(duì)象。同時(shí)使用綁定和 call/apply 方法編寫(xiě)更優(yōu)雅的代碼。
CoffeeScript面向?qū)ο缶幊?/strong>
CoffeeScript的面向編程的語(yǔ)法同JavaScript比較起來(lái),真是天上地下。一個(gè)陽(yáng)春白雪,一個(gè)下里巴人。但是有一點(diǎn)我們要記住:CoffeeScript只是編譯到JavaScript,它只是在JavaScript的基礎(chǔ)上進(jìn)行了語(yǔ)法的抽象,本質(zhì)上還是JavaScript。
類(lèi)
CoffeeScript采用class關(guān)鍵字聲明類(lèi),整個(gè)語(yǔ)法看起來(lái)更加簡(jiǎn)明流暢。
#編譯前
class Animal
constructor: (name)->
@name = name
printName: ->
console.log(@name)
animal = new Animal 'animal'
animal.printName() #animal
#編譯后
var Animal, animal;
Animal = (function () {
function Animal(name) {
this.name = name;
}
Animal.prototype.printName = function () {
return console.log(this.name);
};
return Animal;
})();
animal = new Animal('animal');
animal.printName();
constructor是構(gòu)造函數(shù),就上面的例子來(lái)說(shuō),還可以簡(jiǎn)寫(xiě),實(shí)際上效果是一樣的
class Animal
constructor: (@name)->
printName: ->
console.log(@name)
animal = new Animal 'animal'
animal.printName() #animal
CoffeeScript將我們習(xí)慣性的書(shū)寫(xiě)方式變成豐富的語(yǔ)法糖。說(shuō)到這里我就想說(shuō)一句了,能不能把構(gòu)造函數(shù)換個(gè)字符,constructor丫太長(zhǎng)了。
繼承
繼承使用的是extends關(guān)鍵字
#編譯前
class Animal
constructor: (@name)->
printName: ->
console.log(@name)
class Cat extends Animal
cat = new Cat 'cat'
cat.printName() #cat
#編譯后
var Animal, Cat, cat,
extend = function (child, parent) {
for (var key in parent) {
if (hasProp.call(parent, key)) child[key] = parent[key];
}
function ctor() {
this.constructor = child;
}
ctor.prototype = parent.prototype;
child.prototype = new ctor();
child.__super__ = parent.prototype;
return child;
},
hasProp = {}.hasOwnProperty;
Animal = (function () {
function Animal(name) {
this.name = name;
}
Animal.prototype.printName = function () {
return console.log(this.name);
};
return Animal;
})();
Cat = (function (superClass) {
extend(Cat, superClass);
function Cat() {
return Cat.__super__.constructor.apply(this, arguments);
}
return Cat;
})(Animal);
cat = new Cat('cat');
cat.printName();
extend函數(shù)解析
我們簡(jiǎn)單分析下編譯后的extend函數(shù),對(duì)JavaScript原型鏈不是很熟的可以跳過(guò)這段。兩個(gè)參數(shù)分別是子類(lèi)child和父類(lèi)parent,第一段代碼:
for (var key in parent) {
if (hasProp.call(parent, key)) child[key] = parent[key];
}
這段代碼就是將父類(lèi)上面的屬性拷貝到子類(lèi)上,因?yàn)镴avaScript當(dāng)中函數(shù)也是對(duì)象,可以擴(kuò)展屬性的。什么意思?看代碼
class Animal
constructor: (@name)->
printName: ->
console.log(@name)
Animal.prop = 'Animal prop'
class Cat extends Animal
console.log Cat.prop #Animal prop
第二段代碼:
function ctor() {
this.constructor = child;
}
ctor.prototype = parent.prototype;
child.prototype = new ctor();
可能大家看不大明白,我稍微改動(dòng)下,換種寫(xiě)法
child.prototype = new parent();
child.prototype.constructor=child;
這里就是我們上面提到的原型鏈繼承。再看最后段代碼:
child.__super__ = parent.prototype;
這里是為了在子類(lèi)中調(diào)用父類(lèi)的方法,實(shí)現(xiàn)多態(tài),看下面的例子就知道了。
多態(tài)
編譯后的代碼太長(zhǎng),就不粘貼了,看CoffeeScript代碼更易于學(xué)習(xí)。
直接重寫(xiě)父類(lèi)方法
class Animal
constructor: (@name)->
printName: ->
console.log(@name)
class Cat extends Animal
printName: ->
console.log 'Cat name:' + @name
cat = new Cat 'cat'
cat.printName() #Cat name:cat
重寫(xiě)父類(lèi)方法,在重寫(xiě)的方法中調(diào)用父類(lèi)方法
class Animal
constructor: (@name)->
move: (meter)->
console.log(meter)
class Cat extends Animal
move: ->
console.log 'Cat move'
super 4
cat = new Cat 'cat'
cat.move() #Cat move 4
更多建議: