[].slice.call()与Array.prototype.slice.call()

本文探讨了在ES6之前将伪数组转换为真正数组的两种常见方法:[].slice.call()和Array.prototype.slice.call()。这两种方法在本质上没有区别,但在调用上有差异,[].slice.call()在性能上可能稍优。slice()方法用于创建数组的浅拷贝,而call()则用于改变函数内部的this指向。通过Array.prototype.slice.call(),我们可以为不具备slice()方法的对象如arguments赋予转换能力。此外,文章还提供了一个自定义的Myslice()函数来解释这一过程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

[].slice.call()与Array.prototype.slice.call()将类数组转化为真正的数组

在ES6以前,将一个伪数组转换为真正数组通常情况下都是使用[ ].slice.call()方法
补充:ES6的方法为 Array.from()

1、区别
[].slice === Array.prototype.slice      // true

[]为创建数组,当[].slice的时候,自然会去找原型链

[].__proto__.slice === Array.prototype.slice   // true
  • Array.prototype.slice是定义的方法,可以被重写

  • [].silce是使用定义的方法

  • 自身的属性不同(因为原型与[]的区别)

Object.getOwnPropertyNames(Array.prototype)
// (33) ["length", "constructor", "concat", "copyWithin", "fill", "find", "findIndex", "lastIndexOf", "pop", "push", "reverse", "shift", "unshift", "slice", "sort", "splice", "includes", "indexOf", "join", "keys", "entries", "values", "forEach", "filter", "flat", "flatMap", "map", "every", "some", "reduce", "reduceRight", "toLocaleString", "toString"]

Object.getOwnPropertyNames([])   // ["length"]

所以在本质上[]和Array.prototype没有本质区别,但是调用上是有区别的,但是根据专业检测,[]要更快一点

2、slice

slice()方法返回一个从开始到结束(不包括结束)选择的数组的一部分进行浅拷贝到一个新的数组对象,并且原对象不会被修改

  • 如果该元素是个对象引用 (不是实际的对象),slice 会拷贝这个对象引用到新的数组里。两个对象引用都引用了同一个对象。如果被引用的对象发生改变,则新的和原来的数组中的这个元素也会发生改变。
  • 对于字符串、数字及布尔值来说(不是 [String]、[Number] 或者 [Boolean]对象,slice 会拷贝这些值到新的数组里。在别的数组里修改这些字符串或数字或是布尔值,将不会影响另一个数组。

slice 这个方法在不接受任何参数的时候会返回 this 本身

arguments 是属于函数内部的变量,其值是函数参数列表,一个类数组对象,是具有长度属性的,但并不是数组,不具备slice()这个方法,那就意味着 arguments.slice()行不通

3、call

call() 是所有函数都具备的方法,其作用有两个,即调用函数并改变函数内部this指向。

通过call()将[].slice中的this指向了arguments,使其拥有了slice方法,就实现了对象转数组

function list() {
  console.log(arguments);  // Arguments(3) [1, 2, 3, callee: ƒ, Symbol(Symbol.iterator): ƒ]
  return Array.prototype.slice.call(arguments);
}
console.log(list(1, 2, 3));  // [1, 2, 3]
var arrayLike = {
  0: 'a',
  1: 'b',
  2: 'c',
  length: 3
}
console.log([].slice.call(arrayLike));  // ["a", "b", "c"]
Array.from(arrayLike); // ["a", "b", "c"]

为什么将arguments的call给slice就可以变成数组?内部到底发生了什么

我们可以实现一个自己的slice(),就明白了

4 、Myslice()
Array.prototype.Myslice = function (begin,end){
  var start = begin || 0;   //判断begin时候存在 不存在给0 这里判断可以加强
  var len = this;    //获取this.length  这里得到了call进来的对象
  start = (start >= 0) ? start : Math.max(0, len + start); //判断参数是不是是不是大于1,负数情况下的begin取值
  end = (typeof end == 'number') ? Math.min(end, len) : len;  //判断end是不是大于this.length的长度
  if(end<0){
    end = end + len  //判断负值的情况
  }
  var result = new Array(); 
  for (let i = 0; i < end.length; i++) {
    result.push(this[i])
  }
  return result;
}

JavaScript sclie的源码

Array.prototype.slice = function(begin, end) {
  end = typeof end !== 'undefined' ? end : this.length

  if (Object.prototype.toString.call(this) === '[object Array]') {
    return _slice.call(this, begin, end)
  }

  var i,
    cloned = [],
    size,
    len = this.length

  var start = begin || 0
  start = start >= 0 ? start : Math.max(0, len + start)

  var upTo = typeof end == 'number' ? Math.min(end, len) : len
  if (end < 0) {
    upTo = len + end
  }

  size = upTo - start

  if (size > 0) {
    cloned = new Array(size)
    if (this.charAt) {
      for (i = 0; i < size; i++) {
        cloned[i] = this.charAt(start + i)
      }
    } else {
      for (i = 0; i < size; i++) {
        cloned[i] = this[start + i]
      }
    }
  }

  return cloned
}
<think>嗯,我现在需要解释一下Array.prototype.slice.call()这个方法的用途和原理。首先,用户可能对JavaScript中的数组和类似数组的对象不太熟悉,所以应该从基础开始讲起。 首先,slice()方法本身是数组的一个方法,用于截取数组的一部分,返回一个新数组,而不修改原数组。比如,arr.slice(1,3)会返回从索引1到3(不包括3)的元素。 但问题在于,类似数组的对象(比如arguments对象、DOM元素集合等)并不是真正的数组,它们没有slice方法。这时候,如果直接调用arguments.slice()会报错,因为arguments没有这个方法。 这时候,Array.prototype.slice.call(arguments)的作用就体现出来了。通过使用call方法,可以改变slice方法的this指向,让slice方法在类似数组的对象上运行。因为slice方法内部只依赖于数字索引和length属性,而类似数组的对象正好具备这些特性,所以这样就可以将这类对象转换为真正的数组。 举个例子,假设有一个类似数组的对象: var arrayLike = {0: 'a', 1: 'b', length: 2}; var arr = Array.prototype.slice.call(arrayLike); 这样,arr就会变成['a', 'b'],一个真正的数组。 需要注意的是,在ES6之后,更推荐使用Array.from()方法来转换类数组对象,或者使用展开运算符[...arrayLike],但这两种方法需要对象是可迭代的,而Array.prototype.slice.call()则不需要可迭代,只需要有length属性和索引即可。 此外,如果类数组对象的length属性不准确,或者索引不连续,可能会导致转换后的数组不符合预期。因此,使用时需要确保类数组对象的结构正确。 总结一下,Array.prototype.slice.call()的作用是将一个类数组对象转换为真正的数组,通过借用数组的slice方法,并利用call改变this指向来实现。这在ES5及之前的环境中非常常见,但在现代代码中可能更倾向于使用ES6的新方法。</think>好的,我来逐步解释 `Array.prototype.slice.call()` 的作用和原理: ### 1. **基础知识点** - **`slice()` 方法**:数组的 `slice()` 方法用于截取数组片段,返回新数组,例如: ```javascript const arr = [1, 2, 3, 4]; console.log(arr.slice(1, 3)); // 输出:[2, 3] ``` - **`call()` 方法**:用于改变函数执行时的 `this` 指向,例如: ```javascript function showName() { console.log(this.name); } const obj = { name: "John" }; showName.call(obj); // 输出:John ``` --- ### 2. **问题场景** 类数组对象(如 `arguments`、DOM元素集合)有数字索引和 `length` 属性,但**没有数组方法**: ```javascript function example() { console.log(arguments.slice()); // 报错!arguments 没有 slice 方法 } example(1, 2, 3); ``` --- ### 3. **解决方案** 通过 `Array.prototype.slice.call(类数组对象)`: ```javascript function example() { const argsArray = Array.prototype.slice.call(arguments); console.log(argsArray); // 输出真正的数组:[1, 2, 3] } example(1, 2, 3); ``` --- ### 4. **原理拆解** - **`Array.prototype.slice`**:获取数组原型的 `slice` 方法。 - **`.call(arguments)`**:让 `slice` 方法在 `arguments` 对象上执行,此时: - `slice` 的 `this` 指向 `arguments` 对象 - `slice` 根据 `this.length` 和数字索引生成新数组 --- ### 5. **现代替代方案**(ES6+) - **`Array.from()`**: ```javascript const argsArray = Array.from(arguments); ``` - **展开运算符**: ```javascript const argsArray = [...arguments]; ``` --- ### 6. **注意事项** - **必须满足两个条件**: 1. 对象有 `length` 属性 2. 有连续的数字索引(例如 `{0: 'a', 1: 'b', length: 2}`) - **不适用于稀疏结构**: ```javascript const bad = { 0: 'a', 2: 'c', length: 3 }; console.log(Array.prototype.slice.call(bad)); // 输出:['a', empty, 'c'] ``` --- ### 总结表格 | 方法 | 适用场景 | 兼容性 | 是否需要迭代器 | |-------------------------------|----------------------------|------------|----------------| | `Array.prototype.slice.call()` | 类数组对象转数组 | 全浏览器 | 否 | | `Array.from()` | 类数组/可迭代对象转数组 | ES6+ | 是(可选) | | `[...类数组]` | 可迭代的类数组对象转数组 | ES6+ | 是 | 通过这种机制,`Array.prototype.slice.call()` 成为了早期 JavaScript 中将类数组对象转换为标准数组的标准做法。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值