javascript - 本守则的作用是什么?

标签 javascript jquery

我正在通读 jQuery's "Plugins/Authoring"虽然我已经写了一些 jQuery 插件。现在我看到 jQuery 有一种特殊的方法来确定方法和调用的范围:

(function( $ ){

  var methods = {
    init : function( options ) { // THIS },
    show : function( ) { // IS   },
    hide : function( ) { // GOOD },
    update : function( content ) { // !!! }
  };

  $.fn.tooltip = function( method ) {

    // Method calling logic
    if ( methods[method] ) {
      return methods[ method ].apply( this, Array.prototype.slice.call( arguments, 1 ));
    } else if ( typeof method === 'object' || ! method ) {
      return methods.init.apply( this, arguments );
    } else {
      $.error( 'Method ' +  method + ' does not exist on jQuery.tooltip' );
    }    

  };

})( jQuery );

我理解最终会发生什么的概念……但究竟如何?这部分让我感到困惑:

    // Method calling logic
    if ( methods[method] ) {
      return methods[ method ].apply( this, Array.prototype.slice.call( arguments, 1 ));
    } else if ( typeof method === 'object' || ! method ) {
      return methods.init.apply( this, arguments );
    }

为什么 Array.prototype.slide.call(argumetns, 1)?变量“参数”突然从哪里来?非常感谢任何简短或更深入的解释。据说,这就是应该编写插件的方式……所以我想知道为什么。

谢谢!

最佳答案

参数

arguments 是 JavaScript 语言的一部分。当我第一次遇到它时,我对完全感到困惑;不仅仅是你。 :-) 它是每个函数中的一个自动局部变量,并且是一个类似数组的结构,为您提供所有参数(参见 the spec 的第 10.6 节),例如:

function foo() {
    var index;

    for (index = 0; index < arguments.length; ++index) {
        alert(arguments[index]);
    }
}
foo("one", "two"); // alerts "one", then alerts "two"

当我说arguments 是类数组时,我是认真的——它不是数组。它对参数的引用是实时的(和双向的)。例如:

function foo(namedArg, anotherNamedArg) {
    alert(namedArg === arguments[0]);        // alerts true, of course
    alert(anotherNamedArg === arguments[1]); // also alerts true
    namedArg = "foo";
    alert(arguments[0]);                     // alerts "foo"
    arguments[0] = "bar";
    alert(namedArg);                         // alerts "bar"
}

请注意,当为 namedArg 赋值时,结果反射(reflect)在 arguments[0] 中,反之亦然。

arguments 真的很酷,但只有在需要时才使用它——一些实现通过不 Hook 来加速调用函数,直到/除非函数实际上首先尝试访问它,这可能会减慢功能下降(非常轻微)。

arguments 还有一个名为 callee 的属性,它是对函数本身的引用:

function foo() {
    alert(foo === arguments.callee); // alerts true
}

但是,出于多种原因,最好避免使用 arguments.callee。一个原因是在许多实现中,它真的很慢(我不知道为什么,但给你一个想法,函数调用开销可以增加一个数量级 如果你使用 arguments.callee)。另一个原因是您不能在 ECMAScript5 新的“严格”模式下使用它。

(一些实现也有 arguments.caller - shudder - 但幸运的是它从未广泛传播并且在任何地方都没有标准化[也不可能]。)

slice 调用和apply

关于

return methods[ method ].apply( this, Array.prototype.slice.call( arguments, 1 ));

它所做的是使用 Array#slice 方法将参数复制到一个数组中(减去第一个参数,这是要调用的方法),然后将结果数组传递到 Function#apply 函数在它调用的函数实例上。 Function#apply 使用给定的 this 对象和作为数组提供的参数调用函数实例。代码不只是使用 arguments.slice 因为(再次)arguments 不是真正的数组,所以你不能依赖它拥有所有的数组函数,但是该规范特别指出(在第 15.4.4.10 节中)您可以将 Array.prototype.slice 函数应用于任何类似数组的对象,这就是他们正在做的事情。

Function#applyFunction#call 也是 JavaScript 的内置部分(参见第 15.3.4.3 和 15.3.4.4 节)。以下是每个示例的更简单示例:

// A function to test with
function foo(msg, suffix) {
    alert(this.prefix + ": " + msg + suffix);
}

// Calling the function without any `this` value will default `this`
// to the global object (`window` on web browsers)
foo("Hi there", "!"); // Probably alerts "undefined: Hi there!" because the
                      // global object probably doesn't have a `prefix` property

// An object to use as `this`
var obj = {
    prefix: "Test"
};

// Calling `foo` with `this` = `obj`, using `call` which accepts the arguments
// to give `foo` as discrete arguments to `call`
foo.call(obj, "Hi there", "!"); // alerts "Test: Hi there!"
      // ^----^-----------^---- Three discrete args, the first is for `this`,
      //                        the rest are the args to give `foo`

// Calling `foo` with `this` = `obj`, using `apply` which accepts the arguments
// to give `foo` as an array
foo.apply(obj, ["Hi there", "!"]); // alerts "Test: Hi there!"
            // ^---------------^---- Note that these are in an array, `apply`
            //                       takes exactly two args (`this` and the
            //                       args array to use)

关于javascript - 本守则的作用是什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4123341/

相关文章:

jquery - Bootstrap 轮播冲突 flexslider

javascript - 带有加载通知的跨浏览器 xmlhttprequest 响应

javascript - 如何检查 Vue 中是否存在 prop?

jquery - 如何使用 jquery 设置选择下拉列表的 'selected option'

javascript - Getconnection() 不适用于状态机

Javascript ES6 代码优化

jquery - 如何删除网页上特定字符之前或之后的文本

javascript - 为什么我的 AJAX 函数多次调用回调?

javascript - DIV 内文本的内联 CSS

javascript - Node.js 桌面应用程序的源代码是否受到保护?