CoffeeScript对象

2018-08-25 14:09 更新

CoffeeScript 中对象的绑定


有时候你需要一个函数运行在特定的上下文对象中,而不管它在哪里被调用。比如有类似这样一个函数:
callback = (message) –> @v.push message


当直接调用这个函数时 @(this)所代表的就是全局对象,如果通过 call 或者 apply 指定了其他的上下文对象,@ 则代表了其他上下文对象。有什么办法使 @ 绑定为特定的上下文对象呢?


在 CoffeeScript 中有一个非常方便的方式,只要用 => 代替 –> 定义需要绑定特定上下文对象的函数即可,比如以上 callback 函数:
callback = (message) => @v.push message


此时的 @ 指代的就是该函数定义时所在的上下文对象。以上函数解析成 javascript 就是:


var callback, 
  _this = this;
callback = function(message) { 
  _this.v.push(message); 
};


那为什么不直接用 => 代替 –> 呢?
增加了代码量以及运行时间,并且这是没有必要的
为了适应复杂的上下文对象,可以提供更加优雅的代码编写方式
在你定义函数的时候一定要非常认真考虑使用 this/@ 指定正确的上下文对象。同时使用绑定和 call/apply 方法编写更优雅的代码。



CoffeeScript面向对象编程


CoffeeScript的面向编程的语法同JavaScript比较起来,真是天上地下。一个阳春白雪,一个下里巴人。但是有一点我们要记住:CoffeeScript只是编译到JavaScript,它只是在JavaScript的基础上进行了语法的抽象,本质上还是JavaScript。



CoffeeScript采用class关键字声明类,整个语法看起来更加简明流畅。


#编译前
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是构造函数,就上面的例子来说,还可以简写,实际上效果是一样的


class Animal
  constructor: (@name)->
  printName: ->
    console.log(@name)


animal = new Animal 'animal'


animal.printName() #animal
CoffeeScript将我们习惯性的书写方式变成丰富的语法糖。说到这里我就想说一句了,能不能把构造函数换个字符,constructor丫太长了。


继承
继承使用的是extends关键字




#编译前
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函数解析
我们简单分析下编译后的extend函数,对JavaScript原型链不是很熟的可以跳过这段。两个参数分别是子类child和父类parent,第一段代码:


for (var key in parent) {
    if (hasProp.call(parent, key)) child[key] = parent[key];
}
这段代码就是将父类上面的属性拷贝到子类上,因为JavaScript当中函数也是对象,可以扩展属性的。什么意思?看代码


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();
可能大家看不大明白,我稍微改动下,换种写法


child.prototype = new parent();
child.prototype.constructor=child;
这里就是我们上面提到的原型链继承。再看最后段代码:


child.__super__ = parent.prototype;
这里是为了在子类中调用父类的方法,实现多态,看下面的例子就知道了。


多态
编译后的代码太长,就不粘贴了,看CoffeeScript代码更易于学习。


直接重写父类方法
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
重写父类方法,在重写的方法中调用父类方法
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

以上内容是否对您有帮助:
在线笔记
App下载
App下载

扫描二维码

下载编程狮App

公众号
微信公众号

编程狮公众号