【问题标题】:jQuery plugin authoring in CoffeeScript, with conventionally "private" objects and "prototype" callsCoffeeScript 中的 jQuery 插件创作,通常使用“私有”对象和“原型”调用
【发布时间】:2013-08-12 10:47:47
【问题描述】:

背景

所以,几个月前我看到了一篇文章Essential jQuery Plugin Patterns。我正在尝试编写一个简单的 jQuery 插件,我发现这篇文章非常有用。它包含很多信息,其中大部分超出了我对 JavaScript 或 jQuery 的专业知识。主要感兴趣的是第一个插件模板,称为 jQuery Lightweight Plugin Boilerplate,几个月前我在 another question 中引用了它。

最近,我开始使用 CoffeeScript 并查找了一个 CoffeeScript jQuery 插件模板,我找到了 here

这两者都实现了几乎相同的概念。这里有一些重要的不同之处:

  • Lightweight Boilerplate 中没有的 private 对象
  • CoffeeScript 模板中不同的命名空间块。 (我完全不知道他对 methods[method].apply this, Array::slice.call(arguments, 1) 做了什么,虽然我有点理解 Lightweight Boilerplate 的命名空间块。
  • Lightweight Boilerplate 中,可在命名空间块中处理对象的链接性和迭代,而在 CoffeeScript 模板 中,method.init() 需要 return $(this) 以及这样做$(this).each()

研究

所以我继续拼接这两个。我写了自己的模板。就是这样:

(($, window, document) ->

  # ---------------------------------------------------------------------------
  # Conventionally private variables
  # ---------------------------------------------------------------------------
  _PluginName = "FooBar"

  _Defaults   =
    property: 'value' # etc. etc.

  # ---------------------------------------------------------------------------
  # Private methods
  # ---------------------------------------------------------------------------
  _Debug      = (msg) ->
    window.console.log(msg)
    return

  # ---------------------------------------------------------------------------
  # Plugin Constructor
  # ---------------------------------------------------------------------------
  Plugin = (element, options) ->
    @element = element
    @options = $.extend true, {}, _Defaults, options

    # TODO: Call methods to do stuff
    return

  # ---------------------------------------------------------------------------
  # Plugin Methods
  # ---------------------------------------------------------------------------
  Plugin.prototype.init = () ->
    # TODO: Plugin initializiation logic
    return

  Plugin.prototype.destroy = () ->
    # TODO: Cleanup, unbind and eject
    return

  # ---------------------------------------------------------------------------
  # Actual plugin body
  # ---------------------------------------------------------------------------
  $.fn[_PluginName] = (options) ->
    return @.each () ->
      ($.data @, 'plugin_' + _PluginName
      new Plugin @, options
      ) unless $.data @, 'plugin_' + _PluginName
  return

) jQuery, window, document

我并不是要对这两个插件进行比较。而且我的插件还不够完美。我从对another question 的回答中发现,使用($, window, document) 闭包是一种矫枉过正。可能还有其他问题,欢迎大家指出并讨论。

不过,我有一些非常具体的问题。

问题

  1. 这些传统上的“私有”对象/方法有多安全。如果有人故意打电话给Plugin() 而不是正确使用插件怎么办? _Defaults 可以在这个闭包之外的任何范围内访问吗?

  2. 这些“私有”对象的具体范围是什么?它们是否会随意漂浮在 jQuery 命名空间中?他们能干涉任何事情吗?使用这些“私有”变量如何帮助改进代码?

  3. 我不完全理解prototypeinit()destroy()Plugin() 本身的属性吗?为什么init()destroy()Plugin()options 属性引用为this.options,就好像init()destroy() 是在Plugin() 本身的上下文中定义的......如果我有一个对象定义为Plugin.prototype.methodsthisinside methods 对象的函数是什么?


注意:如果任何人都难以通过链接查看代码,请告诉我。我将编辑此问题以包含代码。我没有包括在内,因为那样问题会变得太长。

【问题讨论】:

    标签: design-patterns jquery-plugins coffeescript


    【解决方案1】:

    当你做这样的事情时:

    (->
        Pancakes = ...
        ...
    )()
    

    JavaScript 版本如下所示:

    (function() {
      var Pancakes;
      Pancakes = ...
      ...
    })();
    

    特别是,Pancakes 是匿名自执行函数的本地函数,因此无法从函数外部访问它。另请注意,CoffeeScript 编译器会将每个 .coffee 文件包装在 self-executing function to avoid scope creep 中,即:

    Pancakes = 6
    

    最终(或多或少):

    (function() {
        var Pancakes = 6;
    })();
    

    因此,即使您不手动添加某种范围包装器,CoffeeScript 也会为您添加一个。当然,如果有人自己编译 CoffeeScript,他们可以通过运行coffee --bare 来抑制外部函数包装器来编译 CoffeeScript。 OTOH,每个人都有权使用脚枪,如果需要,欢迎他们从自己的脚上射击。

    这应该回答 12

    就你的原型问题而言,你应该写:

    Plugin::init = -> ...
    

    它们不是直接引用prototype,而是:: is more CoffeeScripty

    回到手头的问题。当你这样说时:

    class Pancakes
    
    Pancakes::m = (where_is) -> 'house?'
    

    这和说的一样:

    class Pancakes
        m: (where_is) -> 'house?'
    

    所以分配一些东西给prototype 只是向“类”添加一个方法。这意味着@(又名this)将(通常)成为对象:

    pancakes = new Pancakes
    pancakes.m() # `@` will be `pancakes` inside `m`
    

    当然,任何 CoffeeScript 函数中 @ 的值取决于(就像在 JavaScript 中一样)函数的调用方式以及函数是否已绑定到对象。

    您可以通过simple example 验证这一点:

    class C
        constructor: ->
            @p = Math.random()
            console.log(@p)
    C::m = -> console.log(@p)
    (new C).m()
    

    这将在您的控制台中按预期为您提供两个相同随机数的副本。

    希望能照顾到3

    【讨论】:

      猜你喜欢
      • 2013-08-09
      • 1970-01-01
      • 1970-01-01
      • 2013-10-15
      • 1970-01-01
      • 1970-01-01
      • 2011-11-17
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多