Javascript 我怎样才能给出一个插件';s默认设置是否可以访问最终设置?

Javascript 我怎样才能给出一个插件';s默认设置是否可以访问最终设置?,javascript,jquery,Javascript,Jquery,我正在开发jQuery插件。当插件运行时,它要做的第一件事就是确定它的设置。它通过采用一些默认设置并用用户传入的内容覆盖部分或全部设置来实现这一点 以下是一个简化版本: (function( $ ) { $.fn.somePlugin = function(userOptions) { // Short name for internal use - exposed below for external modification var defaults = $.fn.som

我正在开发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 );
因此,如果您这样调用插件:

    $('div').somePlugin({alerter: function(){alert('No bones here!');}});
  $.fn.somePlugin.defaults = {
    name: 'Captain Slappy von Martinez, Esquire, DDS',
    favoriteColor: 'red',
    alerter: function(){alert("Paint me " + settings.favoriteColor);}        
  }
。。。您覆盖默认的
警报
功能,但使用默认的
收藏夹颜色

我在插件本身之外定义默认值,以便它们可以公开访问。因此,如果您想更改
favoriteColor
默认值,只需执行以下操作:

$.fn.somePlugin.defaults.favoriteColor = 'blue';
。。。之后页面上的每个实例都会发生变化

所有这些都很好

这是我的问题:在一个默认函数中,我需要参考
设置
。大概是这样的:

    $('div').somePlugin({alerter: function(){alert('No bones here!');}});
  $.fn.somePlugin.defaults = {
    name: 'Captain Slappy von Martinez, Esquire, DDS',
    favoriteColor: 'red',
    alerter: function(){alert("Paint me " + settings.favoriteColor);}        
  }
但是当我尝试这一点时,我在声明默认警报函数的行上得到了一个Javascript错误:“settings is not defined.”足够正确:当解析器点击该行时,它还没有定义。它将在函数运行时定义,但这似乎无关紧要

因此,我的问题是:如何将默认函数导入插件,使其能够访问
设置?

  • 有没有办法延迟
    设置的评估
    直到函数实际被调用
  • 如果是这样的话,有没有办法确保它可以访问插件的本地范围,即使我假设,作为一个对象,这个函数是通过引用传递的?我知道我可以通过使用
    someFunction.call(valueToUseForThis)
    在函数内部更改
    this
    的值,但我不知道是否可以在事后更改其范围
一些不起作用的东西
  • 最初,如果我在外部的自动执行函数中声明了
    settings
    ,那么默认值就可以使用它。但是在那里声明会产生问题:如果我在一个页面上多次使用我的插件,实例的设置就会混淆

设置变量的作用域是
$.fn.somePlugin
函数,因此它在该函数之外不可用,您正试图在
$.fn.somePlugin.defaults
中引用它。您不能简单地将默认对象移动到
$.fn.somePlugin
中并在其中声明它吗

尝试以下操作(未测试的代码):

编辑:根据您下面的评论,最简单的方法可能是将设置声明向上移动一个级别到外部函数中-由于该函数的作用域是本地的,因此它仍然是外部调用方私有的。修订代码如下:

(function( $ ) {

  var settings = {}

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

    settings.alerter.call();

    // More code, etc.
  }

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

})( jQuery );

$.fn.somePlugin.defaults.favoriteColor = 'blue';

$.fn.somePlugin(); // Should alert 'Paint me blue'

alert(settings.favoriteColour) // Will not work here;

任何在事实发生后改变范围的企图都是注定要失败的。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) }
}
解决方法2。隐式将设置传递给警报:

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

$.fn.somePlugin.defaults = {
  favoriteColor: 'red',
  alerter: function() { alert("Paint me " + this.favoriteColor) }
}
这两种解决方案都经过测试,并能与插件的多种用途一起很好地工作。如果您没有在alerter中使用
关键字的计划,则可以将其用于引用设置

您和福吉提到的第三个有效解决方案是将设置对象附加到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)
  }
} 

额外的乐趣。模拟动态范围,a.k.a不这样做

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)
插件中的用法:

$.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) }
}

只需将
设置
更改为

$.fn.somePlugin.defaults = {
    name: 'Captain Slappy von Martinez, Esquire, DDS',
    favoriteColor: 'red',
    alerter: function () { alert("Paint me " + this.favoriteColor); }        
}
就这样

编辑:哦!我刚刚注意到你的代码中有一些东西!不要使用
.call()
调用
设置.alerter
。这改变了
的含义。直接调用该方法即可。如果必须使用
.call()
,请传入
设置
作为
的参数

settings.alerter.call();         // this won't work.
settings.alerter();              // but this will!
settings.alerter.call(settings); // this works too

这里有一个基于您的代码的完整工作示例:

我想到的一个解决方法是使用
jQuery.data
在DOM上存储
设置
,但我希望有一个更优雅的解决方案也能教我更多关于Javascript的知识。我喜欢使用这种插件格式()因为它存储对DOM对象的反向引用(使用上面注释中暗示的jQuery.data)。因此,您只需使用类似于
$(el).data('somePlugin').options.favoriteColor
的内容即可获得设置。你可以在这里更多地了解这个设计模式()。@fudgey-wow,这是一个非常酷的工具。谢谢你的链接。对不起,我应该这么说:我在插件之外定义默认值,以便它们可以公开访问。见更新的问题。我已经为你们修改了我的答案:)好的。这无疑以一种非常简单的方式解决了我的问题Oops-事实证明,这实际上给我带来了另一个问题:即使我在默认设置中没有引用
设置
,在插件范围之外声明设置,即使它在自动执行的外部函数中,也会在同一页面上的插件的多个使用之间产生冲突。我将不得不寻找另一个解决方案。+1-我正要发布一个与您的第二个解决方案等效的解决方案,这时我发现了您的答案。@Luke,我刚刚提出了一个不切实际但有趣的解决方案。看额外的部分。很好!如果像你说的有点不切实际!我必须做一些研究来理解您的“模拟动态范围”示例,但我很满意,在这种情况下,显式传递设置是最好的解决方案。谢谢@Nathan,最后一个示例的工作方式是将原始函数转换为字符串,将函数体包装在“with(args){…}”构造中,然后将其转换回函数。关键字“with”用于将函数的变量绑定到设置对象。最后一个函数是这样的:function(){with(args){alert(“paintme”+settings.favoriteCo