1

背景

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

最近,我开始使用 CoffeeScript 并查找了一个CoffeeScript jQuery 插件模板,我在这里找到了它。

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

  • 轻量级样板中不存在的私有对象
  • CoffeeScript 模板中不同的命名空间块。(尽管我对Lightweight Boilerplatemethods[method].apply this, Array::slice.call(arguments, 1)的命名空间块有所了解,但我完全不知道他做了什么。
  • 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

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

尽管如此,我有一些非常具体的问题。

问题

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

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

  3. 我不完全明白prototype。是init()和本身destroy()的属性Plugin()吗?为什么要引用 as if 并在其自身的上下文中定义的属性......init()如果我有一个定义为的对象怎么办?对象内部的功能是什么?destroy()optionsPlugin()this.optionsinit()destroy()Plugin()Plugin.prototype.methodsthismethods


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

4

1 回答 1

0

当你做这样的事情时:

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

JavaScript 版本如下所示:

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

特别是,Pancakes它是匿名自执行函数的本地函数,因此不能从函数外部访问。另请注意,CoffeeScript 编译器会将每个.coffee文件包装在一个自执行函数中以避免范围蔓延,即:

Pancakes = 6

最终(或多或少):

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

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

那应该回答12

至于你的原型问题,你应该写:

Plugin::init = -> ...

它们不是直接引用prototype,而是相同的东西,但::更多的是 CoffeeScripty

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

class Pancakes

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

这和说的一样:

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

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

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

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

您可以通过一个简单的示例来验证这一点:

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

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

希望这会照顾3

于 2013-08-12T02:47:47.033 回答