继续下学习coffeescript中学习到的一些小技巧。
构造函数的参数列表中可以直接指定类的成员变量
constructor: (@a,@b) ->
这段代码会被翻译为
function A(a, b) {
this.a = a;
this.b = b;
}
这样既指定了成员变量又进行了赋值,一举两得。
更复杂一点的用法如下:
constructor:({@a,@b}={},c,@d)->
这里结合使用了@
参数和普通参数,这是可以的。同时使用了默认参数与解构。编译后的代码:
function A(arg, c, d) {
var ref;
ref = arg != null ? arg : {}, this.a = ref.a, this.b = ref.b;
this.d = d;
}
在成员函数中引用所属于的类
这其实是一个javascript的tip。
引用所属类,那还不简单,叫啥就写啥呗:
class A
@static = 'A'
func: ->
console.log A.static
new A().func()
这样做会有一个不好的地方,就是如果A类重构的时候修改了名字的话,如果忘记了修改A类中所有调用自己的地方,就要出错咯。而别的语言中使用的多半是self
,static
这种与类名无关特殊变量,所以无此顾虑。
不过也不必顾虑,因为js中,方法的原型中的constructor
指向方法本身。而js中的类也不过就是方法本身。所以可以这么写:
class A
@static = 'A'
func: ->
console.log @constructor.static
new A().func()
coffeescript类继承实现原理
coffeescript作为javascript的高级语法糖,提供了同意的类继承方法:直接使用extend即可
TODO
coffeescript中如果定义了子类的构造函数,需要注意的地方
class A
constructor: ->
@name = 'A class'
getName: ->
console.log @name
class B extends A
a = new A
a.getName() # A class
b = new B
b.getName() # A class
B作为A的子类,继承了A的方法和成员变量name
。
但是如果B类明确定义了构造函数的话:
class B extends A
constructor: ->
# xxx
a = new A
a.getName() # A class
b = new B
b.getName() # undefined
可以看到,这时,B类中就没有A类的实力变量了。这时因为coffeescript使用的寄生组合式继承,需要在子类的构造函数中调用父类的构造函数,如果你不自定子类的构造函数,coffeescript会自动为你生成一个调用父类构造函数的构造函数,但是如果你自己定义了构造函数的话,coffeescript就无法这么做了。
看生成的js代码就明白了:
如果你没有为B书写构造函数,coffeescript自动生成了一个:
B = (function(superClass) {
extend(B, superClass);
function B() {
return B.__super__.constructor.apply(this, arguments);
}
return B;
})(A);
如果你为B定义了一个空的构造函数:
B = (function(superClass) {
extend(B, superClass);
function B() {}
return B;
})(A);
为了完整的继承,如果我们声明了子类的构造函数,需要在最开始显式地调用super()
以调用父类的构造函数。