【问题标题】:How do you reference Array.prototype.slice.call()?你如何引用 Array.prototype.slice.call()?
【发布时间】:2011-10-13 16:48:34
【问题描述】:

我正在编写一个脚本,我需要在其中克隆许多不同位置的数组。出于这个原因,我想执行以下操作来模拟克隆功能:

var clone = [].slice.call;
var arr1 = [1,2,3,4,5,6,7,8,9,10];
var arr2 = clone(arr1, 0);

不幸的是,上面的代码导致:TypeError: object is not a function。我意识到有很多功能可以进行深度克隆和浅拷贝,但我只想使用内置方法。有趣的是,以下方法确实有效:

var clone = [].slice;
var arr1 = [1,2,3,4,5,6,7,8,9,10];
var arr2 = clone.call(arr1, 0);

有谁知道为什么第一个块不起作用而第二个块起作用?有什么方法可以在调用被引用函数时引用函数调用和应用函数而不抛出错误?

【问题讨论】:

    标签: javascript arrays slice


    【解决方案1】:

    甜美简单:

    slice = Function.prototype.call.bind(Array.prototype.slice);
    slice([1,2,3]); // [1,2,3]
    slice({length:3,0:1,1:2,2:3}); // [1,2,3]
    

    【讨论】:

      【解决方案2】:

      我必须绝对同意 Felix King 和 pimvdb。我认为使用 Function.protoytpe.bind() 函数的唯一缺点是它不是在所有浏览器(例如 IE6)中都可用的函数。另一种方法是使用提供 curry() 函数的 JavaScript 库。另一种选择是定义一个函数,使您能够检索任何其他函数的调用函数。这是我 posted on my blog 对我称之为 getCall() 的函数的定义:

      Function.prototype.getCall = function() {
        var realFn = this;
        return function(objThis) {
          return realFn.apply(objThis, Array.prototype.slice.call(arguments, 1));
        };
      };
      

      现在,有了这个定义,您可以执行以下操作来获取切片函数的调用函数的引用:

      var slice = [].slice.getCall();
      

      【讨论】:

      • 太棒了!这几乎正​​是我想要的。我很高兴您指出所有浏览器都缺少绑定功能。非常感谢!
      • +1 不错的小方法。只是为了记录,有一个.bind 替换:developer.mozilla.org/en/JavaScript/Reference/Global_Objects/…。不过,我更喜欢.getCall 解决方案:)
      • 请记住,.bind 替换只是部分解决方案,正如 Mozilla 所述。事实上,这就是为什么我不会在下一个版本的 jPaq 中包含它的主要原因。
      【解决方案3】:

      你可以通过直接调用slice来克隆一个数组:

      var arr2 = arr1.slice();
      

      如果你想要一个clone 函数,你可以这样做:

      var clone = function(arr) { return arr.slice(); };
      

      如果你真的想要原型函数(只要函数没有被覆盖就没有必要):

      var clone = function(arr) { return [].slice.call(arr); };
      

      为什么不能直接引用callapply

      它不起作用的原因与将对象的方法分配给变量“不起作用”的原因相同。

      如果您调用func.call(),那么this 内的call 将引用func,一个函数对象。

      如果将call 分配给变量,则上下文将丢失。您有对通用 call 函数的引用。因此,您必须再次将正确的上下文(您要应用 call 的方法)作为第一个参数传递给 call

      var clone = [].slice.call;
      var arr2 = clone.call([].slice, arr1);
      

      这并不是真正的改进,而且相当混乱。

      callapply 是每个函数都继承自 Function.prototype 的方法。函数没有自己的版本。 [].slice.call === [].splice.call 产生true

      【讨论】:

      • 感谢您的努力,但我并没有要求克隆函数,而是在问为什么我似乎不能使用对调用函数的引用或应用另一个函数的函数。
      • [].slice.call === [].splice.call 的出色测试。
      【解决方案4】:

      问题是whatever_function.call 等于Function.prototype.call。因此,您有效地保存了对Function.prototype.call 的引用,并且丢失了它是切片函数的信息。

      将其与自定义函数进行比较:

      Function.prototype.custom = function() { console.log(this) };
      
      [].slice.custom(); // logs slice function
      
      var ref = [].slice.custom;
      ref(); // logs window object
      

      防止this 值被更改的方法是使用Function.prototype.bind

      var ref = [].slice.call.bind([].slice);
      

      现在,

      ref([1,2,3], 1); // [2, 3]
      

      因为在调用.call 函数时,this 值被绑定到 slice 函数,一切都按预期工作。

      【讨论】:

      • 不应该Function.prototype.call.bind( Array.prototype.slice )表现更好吗?
      【解决方案5】:

      区别在于函数的范围,即“this”是什么。我不确定正确的技术术语是什么,但是当函数被称为“独立”或作为对象的属性时,“this”是不一样的。

      var myObj = {};
      myObj.foo = function () {
          console.log(this.bar);
      };
      myObj.bar = 1234;
      
      var fooRef = myObj.foo;
      
      myObj.foo(); // 1234
      fooRef(); // undefined
      

      但是,您可以创建一个函数来包装对该函数的调用并传递所有参数:

      var fooEncapsulated = function () {
          return myObj.foo.apply(myObj, arguments);
      }
      
      fooEncapsulated(); // 1234
      

      为了记录,最常见的做法是:

      Array.prototype.slice.call(myArray, other, arguments, here);
      

      【讨论】:

      • 感谢您的快速响应,但我真的很想知道如何引用另一个函数的调用函数。我已经知道 slice 函数了。
      • 刚刚更新了我的答案。要具体回答您的评论,您不能。你需要封装它。这是 JavaScript 中的一项功能。
      • 我认为答案基本上归结为“你不能”。从这个答案基本上你将函数保存到一个变量中,但它不会保存调用它的上下文。所以我认为你最好的选择是@felix 的第三个答案,将它包装在一个函数中。
      • @primvdb: bind 在大量浏览器中不受支持,并且在技术上无论如何都与手动包装它相同。
      猜你喜欢
      • 2011-10-26
      • 1970-01-01
      • 2013-10-06
      • 2011-07-05
      • 2015-02-10
      • 1970-01-01
      • 1970-01-01
      • 2013-11-27
      相关资源
      最近更新 更多