coffeescript_在客户端上使用CoffeeScript

coffeescript

CoffeeScript是一种基于JavaScript的新编程语言。 CoffeeScript提供了一种干净的语法,该语法应吸引喜欢Python或Ruby的任何人,并且还提供了许多受Haskell和Lisp等语言启发的功能性编程功能。

在本系列的第1部分中,您了解了使用CoffeeScript而不是仅使用JavaScript的好处。 您设置了开发环境并运行了脚本。 在第2部分中 ,您通过尝试许多功能同时解决了数学问题,探索了CoffeeScript编程语言。

在本文中,您将创建一个示例CoffeeScript应用程序。 客户端和服务器端代码都将完全用CoffeeScript编写。 您还可以下载本文中使用的源代码。

由CoffeeScript支持的搜索

您将创建的示例应用程序使用户可以输入搜索词,同时搜索Google和Twitter,然后显示合并的结果。 应用程序的客户端获取用户输入的数据,并将其发送到服务器以获取结果。 从服务器返回结果后,客户端将为结果创建UI元素并将其显示在屏幕上。 现在,不必担心服务器端如何工作。

首先定义应用程序的数据模型。 该应用程序将显示搜索结果,因此定义一个SearchResult类。 清单1显示了定义。

清单1.基本SearchResult
class SearchResult
    constructor: (data) ->
        @title = data.title
        @link = data.link
        @extras = data
    
    toHtml: -> "<a href='#{@link}'>#{@title}</a>"
    toJson: -> JSON.stringify @extras

SearchResult类非常简单。 它:

  • 从定义两个成员变量的构造函数开始: titlelink
  • 在传递给构造函数的数据对象中查找这两个值。
  • 存储传递给成员变量extras的其余数据。

    这将很方便,因为您知道应用程序中将有两种不同类型的搜索结果(来自Google的搜索结果和来自Twitter的搜索结果)。

  • SearchResult类定义两个方法:
    • toHtml ,它利用CoffeeScript的字符串插值功能从SearchResult实例中创建一个简单HTML字符串。
    • toJson ,用于将SearchResult对象转换为JSON字符串。

清单1中的类提供了搜索结果的基本功能。 您将从Google和Twitter的搜索结果中获取更多数据。 通过为每种类型的搜索结果创建子类来对此建模。 清单2显示了Google搜索结果的类型。

清单2. GoogleSearchResult
class GoogleSearchResult extends SearchResult
    constructor: (data) ->
        super data
        @content = @extras.content
    toHtml: ->
        "#{super} <div class='snippet'>#{@content}</div>"

清单2显示了CoffeeScript中如何轻松进行面向对象的编程。 GoogleSearchResult扩展了清单1中的基本SearchResult类。 它的构造函数调用超类的构造函数。 如果您曾经用JavaScript完成类样式的继承,那么您就会知道这是多么棘手。 清单3显示了生成JavaScript。

清单3. GoogleSearchResult JavaScript
GoogleSearchResult = (function() {
  __extends(GoogleSearchResult, SearchResult);
  function GoogleSearchResult(data) {
    GoogleSearchResult.__super__.constructor.call(this, data);
    this.content = this.extras.content;
  }
  GoogleSearchResult.prototype.toHtml = function() {
    return "" + GoogleSearchResult.__super__.toHtml.apply(this, arguments) 
+ " <div class='snippet'>" + this.content + "</div>";
  };
  return GoogleSearchResult;
})();

要调用超类的构造函数,必须在__super__变量中保留超类的实例(名称可以是任何东西),然后显式调用构造函数。 回到清单2 ,您可以看到CoffeeScript简化了这件事。 请注意,该示例在GoogleSearchResult类中定义了一个名为content的新实例变量。 这基本上是搜索结果所指向的网页HTML片段。 GoogleSearchResult具有此功能并不奇怪,但基类却没有。 最后,请注意toHtml方法的重写。 该示例使用超类的toHtml方法,但还使用内容片段附加了一个额外的div 。 再次查看清单3 ,以了解如何完成对超类的toHtml方法的调用。 因为您有一个GoogleSearchResult子类,所以还需要一个TwitterSearchResult子类,如清单4所示。

清单4. TwitterSearchResult
class TwitterSearchResult extends SearchResult
    constructor: (data) ->
        super data
        @source = @extras.from_user
        @link = "http://twitter.com/#{@source}/status/#{@extras.id_str}"
        @title = @extras.text
    toHtml: ->
        "<a href='http://twitter.com/#{@source}'>@#{@source}</a>: #{super}"

TwitterSearchResult类遵循与清单2中GoogleSearchResult类相同的模式。 它的构造函数利用了其超类的构造函数。 它也是:

  • 定义自己的成员变量,称为source
  • 使用字符串模板及其成员变量构造link成员变量。
  • title成员变量重置为与输入数据不同的字段。
  • 覆盖超类的toHtml方法,并向创建推文的用户添加链接。

CoffeeScript的字符串插值再次使创建新类时使用超类的toHtml方法变得容易。 要调用超类的toHtml方法,只需调用super 。 您可能很想调用super.toHtml ,但是没有必要,这样做实际上会导致错误。 CoffeeScript表示您想在超类上调用相同的方法,从而使您的生活变得更加轻松。

现在,您已经拥有了应用程序所需的数据结构,并且可以开始编写一些客户端逻辑。 使用工作后端测试代码会容易得多。 因为没有,所以我们使用下一个最好的东西:模拟数据。

使用模拟数据

在构建像现代Web应用程序这样的客户端服务器应用程序时,通常需要在应用程序的两个部分相遇之处创建共享接口,然后创建模拟数据。 这使您可以并行开发应用程序的客户端和服务器部分。 该方法在CoffeeScript上特别有效,因为您可以在客户端和服务器上使用相同的编程语言。 清单5显示了来自Google的模拟搜索结果。

清单5.模拟Google搜索结果
mockGoogleData = [
        GsearchResultClass:"GwebSearch",
        link:"http://jashkenas.github.com/coffee-script/",
        url:"http://jashkenas.github.com/coffee-script/",
        visibleUrl:"jashkenas.github.com",
        cacheUrl:"http://www.google.com/search?q\u003dcache:nuWrlCK4-v4J:jashkenas
.github.com",
        title:"\u003cb\u003eCoffeeScript\u003c/b\u003e",
        titleNoFormatting:"CoffeeScript",
        content:"\u003cb\u003eCoffeeScript\u003c/b\u003e is a little language that 
compiles into JavaScript. Underneath all of   those embarrassing braces and 
semicolons, JavaScript has always had a \u003cb\u003e...\u003c/b\u003e"
    ,
        GsearchResultClass:"GwebSearch",
        link:"http://en.wikipedia.org/wiki/CoffeeScript",
        url:"http://en.wikipedia.org/wiki/CoffeeScript",
        visibleUrl:"en.wikipedia.org",
        cacheUrl:"http://www.google.com/search?q\u003dcache:wshlXQEIrhIJ
:en.wikipedia.org",
        title:"\u003cb\u003eCoffeeScript\u003c/b\u003e - Wikipedia, the free 
encyclopedia",
        titleNoFormatting:"CoffeeScript - Wikipedia, the free encyclopedia",
        content:"\u003cb\u003eCoffeeScript\u003c/b\u003e is a programming language 
that transcompiles to JavaScript. The   language adds syntactic sugar inspired by 
Ruby, Python and Haskell to enhance \u003cb\u003e...\u003c/b\u003e"
    ,
        GsearchResultClass:"GwebSearch",
        link:"http://codelikebozo.com/why-im-switching-to-coffeescript",
        url:"http://codelikebozo.com/why-im-switching-to-coffeescript",
        visibleUrl:"codelikebozo.com",
        cacheUrl:"http://www.google.com/search?q\u003dcache:VDKirttkw30J:
codelikebozo.com",
        title:"Why I\u0026#39;m (Finally) Switching to \u003cb\u003eCoffeeScript
\u003c/b\u003e - Code Like Bozo",
        titleNoFormatting:"Why I\u0026#39;m (Finally) Switching to CoffeeScript - 
Code Like Bozo",
        content:"Sep 5, 2011 \u003cb\u003e...\u003c/b\u003e You may have already heard
about \u003cb\u003eCoffeeScript\u003c/b\u003e and some of the hype surrounding it
but you still have found several reasons to not make the \u003cb\u003e...
\u003c/b\u003e"   
]

显然,使用CoffeeScript的简单语法,甚至可以轻松创建模拟数据。 该示例显示CoffeeScript中的对象文字。 清单5是一个数组。 额外的缩进用于指示对象,并且该对象的每个属性都再次缩进。 此代码与JSON相比具有优势。 空白代替大括号。 它们就像JavaScript文字一样,其中的属性不在引号中。 使用JSON时,这些属性也必须加引号。

清单6显示了Twitter搜索结果的类似模拟数据。

清单6.模拟Twitter搜索结果
mockTwitterData = [
        created_at:"Wed, 09 Nov 2011 04:18:49 +0000",
        from_user:"jashkenas",
        from_user_id:123323498,
        from_user_id_str:"123323498",
        geo:null,
        id:134122748057370625,
        id_str:"134122748057370625",
        iso_language_code:"en",
        metadata:
            recent_retweets:4,
            result_type:"popular"
        profile_image_url:"http://a3.twimg.com/profile_images/1185870726/gravatar
_normal.jpg",
        source:"<a href="http://itunes.apple.com/us/app/twitter/id409789998?mt
=12&quot; rel="nofollow">Twitter for Mac</a>",
        text:""CoffeeScript [is] the closest I felt to the power I had twenty 
years ago in Smalltalk" - Ward Cunningham (http://t.co/2Wve2V4l) Nice.",
        to_user_id:null,
        to_user_id_str:null
]

清单6中的模拟数据与清单5中的模拟数据类似,但具有特定于Twitter的字段。 现在,您只需要创建一个返回此模拟数据的接口。 清单7显示了另一个完成该任务的类。

清单7.一个模拟搜索引擎类
class MockSearch
    search: (query, callback) ->
        results = 
            google: (new GoogleSearchResult obj for obj in mockGoogleData)
            twitter: (new TwitterSearchResult obj for obj in mockTwitterData)
        callback results

MockSearch类具有一个称为search方法。 它有两个参数:用于搜索的querycallback函数。 MockSearch快速返回结果,但是真正的搜索将需要通过网络与服务器对话。 要使用JavaScript处理此问题并确保您不会导致UI冻结,通常应使用回调函数。

下一步将创建一个名为results的对象。 您再次使用CoffeeScript的对象文字语法。 results对象具有两个字段: googletwitter 。 每个字段的值都使用数组理解表示。 该表达式将创建适当类型的SearchResult (对于Google来说是GoogleSearchResult ,对于Twitter来说是TwitterSearchResult )的数组。 最后,将callback函数与传递给它的results对象一起调用。

模拟搜索正在运行,因此您可以编写与UI相关的客户端代码。

将所有内容整合到浏览器中

在将UI粘贴到应用程序代码之前,请先查看将要使用的UI。 清单8显示了一个非常简单的网页。

清单8. CoffeeSearch网页
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN"
   "http://www.w3.org/TR/html4/strict.dtd">

<html lang="en">
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
    <title>CoffeeSearch</title>
    <script type="text/javascript" src="search.js"></script>
</head>
<body>
    <div>
        <label for="searchQuery">Keyword:</label>
        <input type="text" name="searchQuery" id="searchQuery"></input>
        <input type="button" value="Search" onclick="doSearch()"/>
    </div>
    <div class="goog" id="gr"/>
    <div class="twit" id="tr"/>
</body>
</html>

上面的网页具有用于输入关键字并将其传递给搜索引擎的基本形式。 它定义了两个部分,可以将搜索结果添加到其中。 该网页未定义JavaScript。 相反,所有内容都在一个名为search.js的文件中,该文件将为CoffeeScript的编译版本。 请注意,单击搜索按钮后,将调用一个名为doSearch的函数。 此函数必须在search.js文件中; 这是search.js文件中唯一尚未出现的内容。 清单9显示了CoffeeScript中的定义。

清单9.网页的doSearch函数
@doSearch = ->
    $ = (id) -> document.getElementById(id)
    kw = $("searchQuery").value
    appender = (id, data) ->
        data.forEach (x) -> 
            $(id).innerHTML += "<p>#{x.toHtml()}</p>"
    ms = new MockSearch
    ms.search kw, (results) ->
        appender("gr", results.google)
        appender("tr", results.twitter)

您可能会注意到该函数有一个@前面加上符号(快捷方式this )。 在脚本的顶层定义时, this成为全局对象。 对于网页中的脚本,全局对象是window对象,它将允许您在清单8中看到的网页中引用它。

doSearch函数仅用几行代码即可完成很多工作。 代码:

  • 定义一个称为$的本地函数,该函数基本上是对有用的document.getElementById函数的快捷方式。 使用它来获取在清单8的搜索表单中输入的关键字。
  • 定义另一个称为appender局部函数,它将使用DOM中的元素ID和数组。 然后,它将遍历数组,创建HTML字符串,并使用给定ID附加到元素。
  • 创建一个MockSearch对象并调用其search方法。
  • 从表单传递关键字并创建回调函数。

    回调函数使用appender将来自Google的搜索结果附加到一个div ,将来自Twitter的搜索结果附加到另一个div

现在,您可以简单地编译所有代码并进行部署。 图1显示了包含模拟数据的网页。

图1.包含模拟数据的搜索页面
搜索页面包含模拟数据

该示例可能看起来并不令人印象深刻,但它演示了客户端所需的所有功能。 尽管您尚未对服务器端进行编码,但是只要服务器端代码生成的数据像模拟数据一样,您就可以确信该应用程序将正常运行。

结论

在本文中,我将CoffeeScript带出实验室,并用它来开始构建真实的东西。 与node.js结合使用,CoffeeScript使您有机会使用相同的优美编程语言编写完整的应用程序,客户端和服务器。 在本系列的最后一部分中,当构建应用程序的服务器端时,您已准备好重用某些相同的代码。 敬请关注。


翻译自: https://www.ibm.com/developerworks/web/library/wa-coffee3/index.html

coffeescript

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值