如何为插件的默认设置提供对最终设置的访问权限?

Nat*_*ong 12 javascript jquery

我正在研究一个jQuery插件.当插件运行时,它首先要确定它的设置.它通过采用一些默认设置并使用用户传入的任何内容覆盖部分或全部设置来实现此目的.

这是一个简化版本:

(function( $ ) {
  $.fn.somePlugin = function(userOptions) {
    // Short name for internal use - exposed below for external modification
    var defaults = $.fn.somePlugin.defaults;

    // Decide settings
    // User settings overrule defaults, but merge both into an empty 
    // hash so that original defaults hash isn't modified
    var settings = $.extend(true, {}, defaults, userOptions);

    settings.alerter.call();

    // More code, etc.
  }

  $.fn.somePlugin.defaults = {
    name: 'Captain Slappy von Martinez, Esquire, DDS',
    favoriteColor: 'red',
    alerter: function(){alert("I got bones!");}        
  }

})( jQuery );
Run Code Online (Sandbox Code Playgroud)

所以,如果你像这样调用插件:

    $('div').somePlugin({alerter: function(){alert('No bones here!');}});
Run Code Online (Sandbox Code Playgroud)

...您覆盖默认alerter功能,但使用默认值favoriteColor.

我在插件本身之外定义默认值,以便它们可以公开访问.因此,如果您想更改默认favoriteColor,您可以这样做:

$.fn.somePlugin.defaults.favoriteColor = 'blue';
Run Code Online (Sandbox Code Playgroud)

......之后,这会改变页面上每个实例的内容.

所有这一切都很好.

这是我的问题:在其中一个默认函数中,我需要参考settings.像这样的东西:

  $.fn.somePlugin.defaults = {
    name: 'Captain Slappy von Martinez, Esquire, DDS',
    favoriteColor: 'red',
    alerter: function(){alert("Paint me " + settings.favoriteColor);}        
  }
Run Code Online (Sandbox Code Playgroud)

但是当我尝试这个时,我在声明默认警报器功能的行上得到一个Javascript错误:"设置未定义".确实如此:当解析器命中该行时,它尚未定义.它将由函数运行的时间定义,但这似乎并不重要.

所以我的问题是:如何以可访问的方式将我的默认函数导入插件settings

  • 有没有办法延迟评估settings直到实际调用函数?
  • 如果是这样,有没有办法确保它可以访问插件的本地范围,即使我假设,作为一个对象,这个函数是通过引用传递的?我知道我可以this通过使用来改变函数内部的值someFunction.call(valueToUseForThis),但我不知道是否可以在事后更改其范围.

一些不起作用的东西

  • 最初,似乎如果我settings在外部,自动执行函数中声明,那将使其可用于默认值.但是在那里声明它会导致问题:如果我在页面上多次使用我的插件,则实例会将其设置混淆.

Ale*_*dev 6

任何事后改变范围的企图都注定要失败.JavaScript中没有动态范围.

解决方法1. 明确地将设置传递给警报器:

$.fn.somePlugin = function(userOptions) {
  var settings = $.extend(...);
  settings.alerter(settings)
}

$.fn.somePlugin.defaults = {
  favoriteColor: 'red',
  alerter: function(settings) { alert("Paint me " + settings.favoriteColor) }
}
Run Code Online (Sandbox Code Playgroud)

解决方法2.隐式将设置传递给警报器:

$.fn.somePlugin = function(userOptions) {
  var settings = $.extend(...);
  settings.alerter()
}

$.fn.somePlugin.defaults = {
  favoriteColor: 'red',
  alerter: function() { alert("Paint me " + this.favoriteColor) }
}
Run Code Online (Sandbox Code Playgroud)

两种解决方案都经过测试,并且可以很好地使用插件.如果您没有计划this在警报器中使用关键字,则可以将其用于引用设置.

你和fudgey提到的第三个有效的解决方案是将设置对象附加到DOM元素本身:

$.fn.somePlugin = function(userOptions) {
  var settings = $.extend(...);
  $(this).data('somePlugin', {settings: settings})
  settings.alerter.call(this)
}

$.fn.somePlugin.defaults = {
  favoriteColor: 'red',
  alerter: function() {
      alert("Paint me " + $(this).data('somePlugin').settings.favoriteColor)
  }
} 
Run Code Online (Sandbox Code Playgroud)

额外的乐趣.模拟动态范围,又名不要这样做

function dynamic(fn) {
  var parts = fn.toString().split('{')
  fn = parts.shift() + '{ with (args) { ' + parts.join('{') + '}'
  return {bind: function(args) { return eval('(' + fn + ')') }}
}

a = b = c = 0

function adder(c) {
  alert(a + b + c)
}

dynamic(adder).bind({a: 1, b: 2})(3) // alert(6)
Run Code Online (Sandbox Code Playgroud)

插件中的用法:

$.fn.somePlugin = function(userOptions) {
  var settings = $.extend(...);
  dynamic(settings.alerter).bind({settings: settings})()
}

$.fn.somePlugin.defaults = {
  favoriteColor: 'red',
  alerter: function() { alert("Paint me " + settings.favoriteColor) }
}
Run Code Online (Sandbox Code Playgroud)