资讯专栏INFORMATION COLUMN

CoffeeScript—面向对象

lscho / 1992人阅读

摘要:要知道,面向对象只是一种手段,最终目的是为了提高我们项目的重用性灵活性和扩展性。两个参数分别是子类和父类,第一段代码这段代码就是将父类上面的属性拷贝到子类上,因为当中函数也是对象,可以扩展属性的。

概述

自从面向对象的编程思想出现以来,这个概念已经被炒烂了,只要编程开发大家都会拿面向对象来说事,好像只要跟面向对象沾边就会显得逼格很高一样,不过确实逼格提高了。要知道,面向对象只是一种手段,最终目的是为了提高我们项目的重用性、灵活性和扩展性。

为了迎合面向对象的程序设计思想,JavaScript也通过自己的语法实现了自己的一套面向对象机制。不过我想问下,前端开发当中有多少人使用过面向对象当中的继承?

JavaScript面向对象的实现确实有点不伦不类的感觉。下面先简单说明下JavaScript当中面向对象的实现,涉及的东西比较深,要对constructor、prototype有一定的理解,不然看起来会很吃力,或者你也可以跳开这部分内容,直接看CoffeeScript面向对象的实现。

JavaScript面向对象编程

JavaScript的实现一个类,可以采用下面的方式:

</>复制代码

  1. function Animal(name) {
  2. this.name = name;
  3. }
  4. Animal.prototype.printName = function () {
  5. console.log(this.name);
  6. };
  7. var animal = new Animal("animal");
  8. animal.printName();

C++、Java...某些程序员可能就吐槽了,我TM都连个关键字class都没看到,这就是类了?

作为一个前端开发,我竟无言以对。。。

继承

选取JavaScript当中几种继承方式,作一个简单的说明,想要学习更深的内容,请通过搜索引擎吧。

对象冒充

</>复制代码

  1. function Animal(name) {
  2. this.name = name;
  3. this.printName = function () {
  4. console.log(this.name);
  5. };
  6. }
  7. function Cat(name) {
  8. this.inherit = Animal;
  9. this.inherit(name);
  10. //Animal.call(this, name);
  11. //Animal.apply(this, [name]);
  12. }
  13. var cat = new Cat("cat");
  14. cat.printName();//cat

注释是通过call和apply实现的方式,其实本质是一样的。继承实现了,闲着无聊,我们来打印下:

</>复制代码

  1. console.log(cat instanceof Animal);//false

这次别说后端开发看不下去,我都忍不了了。这种方式只能说是通过JavaScript的语法机制,模拟实现继承,看起来好像是那么回事,不然怎么叫对象冒充呢。

原型链实现

</>复制代码

  1. function Animal(name) {
  2. this.name = name;
  3. }
  4. Animal.prototype.printName = function () {
  5. console.log(this.name);
  6. };
  7. function Cat() {
  8. }
  9. Cat.prototype = new Animal("cat");
  10. var cat = new Cat();
  11. cat.printName();//cat

打印:

</>复制代码

  1. console.log(cat instanceof Animal);//true

这次对了,cat也是Animal类的实例了,有点面向对象的的意思了。我又闲着无聊了(约么?),再来打印

</>复制代码

  1. console.log(cat.constructor); //[Function: Animal]

咦,又不对了,为啥cat的constructor指向Animal,不应该指向Cat么?

问题出在Cat.prototype = new Animal("cat")上,直接给prototype赋值,改变了constructor的指向,这个时候,我们还要做个处理

</>复制代码

  1. function Animal(name) {
  2. this.name = name;
  3. }
  4. Animal.prototype.printName = function () {
  5. console.log(this.name);
  6. };
  7. function Cat() {
  8. }
  9. Cat.prototype = new Animal("cat");
  10. Cat.prototype.constructor = Cat;
  11. var cat = new Cat();
  12. console.log(cat.constructor); //[Function: Cat]

但是又有人吐槽了,new Cat()为啥把名称放到new Animal()里面,看起来太奇怪了,综合一下就有了第三中——混合型。

</>复制代码

  1. 实际上instanceof的判断原理是跟原型链是相关的。大家自行脑洞!

混合实现

</>复制代码

  1. function Animal(name) {
  2. this.name = name;
  3. }
  4. Animal.prototype.printName = function () {
  5. console.log(this.name);
  6. };
  7. function Cat(name) {
  8. Animal.call(this, name);
  9. }
  10. Cat.prototype = new Animal();
  11. Cat.prototype.constructor = Cat;
  12. var cat = new Cat("cat");
  13. cat.printName();//cat

看起来舒服点了,也就是舒服那么一点点。

多态

直接拿混合型的继承来说明了,这个比较简单

</>复制代码

  1. function Animal(name) {
  2. this.name = name;
  3. }
  4. Animal.prototype.printName = function () {
  5. console.log(this.name);
  6. };
  7. function Cat(name) {
  8. Animal.call(this, name);
  9. }
  10. Cat.prototype = new Animal();
  11. Cat.prototype.constructor = Cat;
  12. Cat.prototype.printName = function () {
  13. console.log("The name is:" + this.name);
  14. };
  15. var cat = new Cat("cat");
  16. cat.printName();//The name is:cat
CoffeeScript面向对象编程

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

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

</>复制代码

  1. #编译前
  2. class Animal
  3. constructor: (name)->
  4. @name = name
  5. printName: ->
  6. console.log(@name)
  7. animal = new Animal "animal"
  8. animal.printName() #animal
  9. #编译后
  10. var Animal, animal;
  11. Animal = (function () {
  12. function Animal(name) {
  13. this.name = name;
  14. }
  15. Animal.prototype.printName = function () {
  16. return console.log(this.name);
  17. };
  18. return Animal;
  19. })();
  20. animal = new Animal("animal");
  21. animal.printName();

constructor是构造函数,就上面的例子来说,还可以简写,实际上效果是一样的

</>复制代码

  1. class Animal
  2. constructor: (@name)->
  3. printName: ->
  4. console.log(@name)
  5. animal = new Animal "animal"
  6. animal.printName() #animal

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

继承

继承使用的是extends关键字

</>复制代码

  1. #编译前
  2. class Animal
  3. constructor: (@name)->
  4. printName: ->
  5. console.log(@name)
  6. class Cat extends Animal
  7. cat = new Cat "cat"
  8. cat.printName() #cat
  9. #编译后
  10. var Animal, Cat, cat,
  11. extend = function (child, parent) {
  12. for (var key in parent) {
  13. if (hasProp.call(parent, key)) child[key] = parent[key];
  14. }
  15. function ctor() {
  16. this.constructor = child;
  17. }
  18. ctor.prototype = parent.prototype;
  19. child.prototype = new ctor();
  20. child.__super__ = parent.prototype;
  21. return child;
  22. },
  23. hasProp = {}.hasOwnProperty;
  24. Animal = (function () {
  25. function Animal(name) {
  26. this.name = name;
  27. }
  28. Animal.prototype.printName = function () {
  29. return console.log(this.name);
  30. };
  31. return Animal;
  32. })();
  33. Cat = (function (superClass) {
  34. extend(Cat, superClass);
  35. function Cat() {
  36. return Cat.__super__.constructor.apply(this, arguments);
  37. }
  38. return Cat;
  39. })(Animal);
  40. cat = new Cat("cat");
  41. cat.printName();
extend函数解析

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

</>复制代码

  1. for (var key in parent) {
  2. if (hasProp.call(parent, key)) child[key] = parent[key];
  3. }

这段代码就是将父类上面的属性拷贝到子类上,因为JavaScript当中函数也是对象,可以扩展属性的。什么意思?看代码

</>复制代码

  1. class Animal
  2. constructor: (@name)->
  3. printName: ->
  4. console.log(@name)
  5. Animal.prop = "Animal prop"
  6. class Cat extends Animal
  7. console.log Cat.prop #Animal prop

第二段代码:

</>复制代码

  1. function ctor() {
  2. this.constructor = child;
  3. }
  4. ctor.prototype = parent.prototype;
  5. child.prototype = new ctor();

可能大家看不大明白,我稍微改动下,换种写法

</>复制代码

  1. child.prototype = new parent();
  2. child.prototype.constructor=child;

这里就是我们上面提到的原型链继承。再看最后段代码:

</>复制代码

  1. child.__super__ = parent.prototype;

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

多态

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

直接重写父类方法

</>复制代码

  1. class Animal
  2. constructor: (@name)->
  3. printName: ->
  4. console.log(@name)
  5. class Cat extends Animal
  6. printName: ->
  7. console.log "Cat name:" + @name
  8. cat = new Cat "cat"
  9. cat.printName() #Cat name:cat
重写父类方法,在重写的方法中调用父类方法

</>复制代码

  1. class Animal
  2. constructor: (@name)->
  3. move: (meter)->
  4. console.log(meter)
  5. class Cat extends Animal
  6. move: ->
  7. console.log "Cat move"
  8. super 4
  9. cat = new Cat "cat"
  10. cat.move() #Cat move 4

</>复制代码

  1. 有任何问题,欢迎大家批评指出,我们共同进步。

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/85565.html

相关文章

  • SegmentFault 技术周刊 Vol.32 - 七夕将至,你的“对象”还好吗?

    摘要:很多情况下,通常一个人类,即创建了一个具体的对象。对象就是数据,对象本身不包含方法。类是相似对象的描述,称为类的定义,是该类对象的蓝图或原型。在中,对象通过对类的实体化形成的对象。一类的对象抽取出来。注意中,对象一定是通过类的实例化来的。 showImg(https://segmentfault.com/img/bVTJ3H?w=900&h=385); 马上就要到七夕了,离年底老妈老爸...

    李昌杰 评论0 收藏0
  • SegmentFault 技术周刊 Vol.32 - 七夕将至,你的“对象”还好吗?

    摘要:很多情况下,通常一个人类,即创建了一个具体的对象。对象就是数据,对象本身不包含方法。类是相似对象的描述,称为类的定义,是该类对象的蓝图或原型。在中,对象通过对类的实体化形成的对象。一类的对象抽取出来。注意中,对象一定是通过类的实例化来的。 showImg(https://segmentfault.com/img/bVTJ3H?w=900&h=385); 马上就要到七夕了,离年底老妈老爸...

    Lyux 评论0 收藏0
  • SegmentFault 技术周刊 Vol.32 - 七夕将至,你的“对象”还好吗?

    摘要:很多情况下,通常一个人类,即创建了一个具体的对象。对象就是数据,对象本身不包含方法。类是相似对象的描述,称为类的定义,是该类对象的蓝图或原型。在中,对象通过对类的实体化形成的对象。一类的对象抽取出来。注意中,对象一定是通过类的实例化来的。 showImg(https://segmentfault.com/img/bVTJ3H?w=900&h=385); 马上就要到七夕了,离年底老妈老爸...

    AaronYuan 评论0 收藏0
  • 初识 CoffeeScript

    摘要:而造成一些莫名其妙的错误。写一个文件打印出编译命令会在同级目录下生成一个同名的文件。将包裹在了一个匿名函数当中,并用调用,这样使得代码隔离,不会和外部混淆。其中的表示的就是为了方便使用,可以使用双冒号来替代。 很早就知道这CoffeeScript一门语言,但是一直没有机会系统的学习下,那天趁在公司没有什么要紧的项目做,就根据CoffeeScript首页的例子学了一下。 引用Coffe...

    骞讳护 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<