slice 并不需要 this 为 array必威手机官网 类型,我

JavaScript 特殊目的 Array-Like Objects 安详严整

2016/06/26 · JavaScript · Javascript, underscore

本文小编: 伯乐在线 - 韩子迟 。未经小编许可,避免转发!
应接参加伯乐在线 专栏审核人。

那篇文章拖了有两周,几日前来跟我们聊聊 JavaScript 中生龙活虎类特殊的对象 -> Array-Like Objects。

(本文节选自 underscore 源码解读连串文章,完整版请关切 )

那篇作品拖了有两周,前天来跟大家拉家常 JavaScript 中风度翩翩类特别的指标 -> Array-Like Objects。

值得庆幸的是,大家得以经过数组的 slice 方法将 arguments 对象调换来真正的数组:
var args = Array.prototype.slice.call(arguments);
对此slice 方法,ECMAScript 262 中 15.4.4.10 Array.prototype.slice (start, end) 章节有备注:

除此而外健康用法,slice 平常用来将 array-like 对象调换为 true array.

Array-Like

JavaScript 中整整皆为目的,那么什么样是 Array-Like Objects?看名就能够猜到其意义,正是像数组的靶子,当然,数组本人正是指标嘛!微微有一点底蕴的同校,一定精晓arguments 便是 Array-Like Objects 的生龙活虎种,能像数组同样用 [] 去访问 arguments 的元素,有 length 属性,然则却无法用一些数组的不二秘技,如 push,pop,等等。

那便是说,什么样的要素是 Array-Like Objects?大家来走访 underscore 中对其的概念。

JavaScript

var MAX_ARRAY_INDEX = Math.pow(2, 53) - 1; var getLength = property('length'); var isArrayLike = function(collection) { var length = getLength(collection); return typeof length == 'number' && length >= 0 && length <= MAX_ARRAY_INDEX; };

1
2
3
4
5
6
var MAX_ARRAY_INDEX = Math.pow(2, 53) - 1;
var getLength = property('length');
var isArrayLike = function(collection) {
  var length = getLength(collection);
  return typeof length == 'number' && length >= 0 && length <= MAX_ARRAY_INDEX;
};

超粗略,不是数组,然而有 length 属性,且属性值为非负 Number 类型就可以。至于 length 属性的值,underscore 给出了多个上限值 MAX_ARRAY_INDEX,其实是 MAX_SAFE_INTEGE奥迪Q7(谢谢 @HangYang 同学提出卡塔 尔(阿拉伯语:قطر‎,因为这是 JavaScript 中能准确表示的最大数字。

思维还宛如何同期能满意以上原则的?NodeList,HTML Collections,反复推敲,以至还大概有字符串,可能具备 length 属性的对象,函数(length 属性值为形参数量卡塔尔,等等。

(本文节选自 underscore 源码解读种类文章,完整版请关怀 https://github.com/hanzichi/underscore-analysis)

复制代码 代码如下:

名词解释:array-like object – 具备 length 属性的靶子,比方 { 0: ‘foo', length: 1 }, 以至 { length: ‘bar' }. 最不乏先例的 array-like 对象是 arguments 和 NodeList.

Array-Like to Array

风姿洒脱对时候,需求将 Array-Like Objects 转为 Array 类型,使之能用数组的部分方法,一个特别轻易粗暴而且包容性出色的情势是新建个数组,然后循环存入数据。

我们以 arguments 为例。

function fn() { // Uncaught TypeError: arguments.push is not a function // arguments.push(4); var arr = []; for (var i = 0, len = arguments.length; i < len; i++) arr[i] = arguments[i]; arr.push(4); // [1, 2, 3, 4] } fn(1, 2, 3);

1
2
3
4
5
6
7
8
9
10
11
12
function fn() {
  // Uncaught TypeError: arguments.push is not a function
  // arguments.push(4);
 
  var arr = [];
  for (var i = 0, len = arguments.length; i < len; i++)
    arr[i] = arguments[i];
 
  arr.push(4); // [1, 2, 3, 4]
}
 
fn(1, 2, 3);

唯独那不是最高雅的,更加高贵的解法我们明确都理解了,use Array.prototype.slice(IE9- 会有标题卡塔 尔(阿拉伯语:قطر‎。

function fn() { var arr = Array.prototype.slice.call(arguments); arr.push(4); // arr -> [1, 2, 3, 4] } fn(1, 2, 3);

1
2
3
4
5
6
function fn() {
  var arr = Array.prototype.slice.call(arguments);
  arr.push(4); // arr -> [1, 2, 3, 4]
}
 
fn(1, 2, 3);

还能够用 [] 替代 Array.prototype 节省多少个字节。

function fn() { var arr = [].slice.call(arguments); arr.push(4); // arr -> [1, 2, 3, 4] } fn(1, 2, 3);

1
2
3
4
5
6
function fn() {
  var arr = [].slice.call(arguments);
  arr.push(4); // arr -> [1, 2, 3, 4]
}
 
fn(1, 2, 3);

譬喻非得追求质量,用 [] 会新建个数组,品质鲜明未有前面三个,可是由于汽油发动机的优化,这一点间隔基本得以忽视不计了(所以广大框架用的正是继任者卡塔尔国。

干什么如此能够转移?我们简要询问下,重要的通首至尾的经过是 slice 方法只需求参数有 length 属性就能够。首先,slice 方法赢得的结果是一个 新的数组,通过 Array.prototype.slice.call 传入的参数(假诺为 a卡塔 尔(英语:State of Qatar),若无 length 属性,可能 length 属性值不是 Number 类型,可能为负,那么直接回到贰个空数组,不然返回a[0]-a[length-1] 组成的数组。(具体能够看下 v8 源码 )

自然,ES6 提供了更方便的方法。

var str = "helloworld"; var arr = Array.from(str); // ["h", "e", "l", "l", "o", "w", "o", "r", "l", "d"]

1
2
3
var str = "helloworld";
var arr = Array.from(str);
// ["h", "e", "l", "l", "o", "w", "o", "r", "l", "d"]

小结下,假使要把 Array-Like Objects 转为 Array,首荐Array.prototype.slice,但是由于 IE 下 Array.prototype.slice.call(nodes) 会抛出荒谬(because a DOM NodeList is not a JavaScript object卡塔 尔(阿拉伯语:قطر‎,所以包容的写法如下。(但还也有少数要留神的是,固然是 arguments 转为 Array,最佳别用 Array.prototype.slice,V8 下会极慢,具体能够看下 防止订正和传递 arguments 给别的方法 — 影响优化 )

function nodeListToArray(nodes){ var arr, length; try { // works in every browser except IE arr = [].slice.call(nodes); return arr; } catch(err){ // slower, but works in IE arr = []; length = nodes.length; for(var i = 0; i < length; i++){ arr.push(nodes[i]); } return arr; } }

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
function nodeListToArray(nodes){
  var arr, length;
 
  try {
    // works in every browser except IE
    arr = [].slice.call(nodes);
    return arr;
  } catch(err){
    // slower, but works in IE
    arr = [];
    length = nodes.length;
 
    for(var i = 0; i < length; i++){
       arr.push(nodes[i]);
     }  
 
    return arr;
  }
}

Array-Like

JavaScript 中全部皆为对象,那么哪些是 Array-Like Objects?从名称想到所满含的意义,正是像数组的指标,当然,数组自个儿就是指标嘛!微微有一些幼功的同桌,一定知道 arguments 正是 Array-Like Objects 的黄金年代种,能像数组同样用 [] 去访问 arguments 的元素,有 length 属性,可是却无法用一些数组的章程,如 push,pop,等等。

那么,什么样的因素是 Array-Like Objects?大家来看看 underscore 中对其的概念。

var MAX_ARRAY_INDEX = Math.pow(2, 53) - 1;
var getLength = property('length');
var isArrayLike = function(collection) {
  var length = getLength(collection);
  return typeof length == 'number' && length >= 0 && length <= MAX_ARRAY_INDEX;
};

很简短,不是数组,可是有 length 属性,且属性值为非负 Number 类型就可以。至于 length 属性的值,underscore 给出了三个上限值 MAX_ARRAY_INDEX,其实是 MAX_SAFE_INTEGEENCORE(感激 @HangYang 同学提议卡塔尔国,因为那是 JavaScript 中能正确表示的最大数字。

沉思还会有何同不时间能满意以上标准的?NodeList,HTML Collections,反复推敲,以致还应该有字符串,可能有所 length 属性的靶子,函数(length 属性值为形参数量卡塔 尔(阿拉伯语:قطر‎,等等。

The slice function is intentionally generic; it does not require that its this value be an Array object. Therefore it can be transferred to other kinds of objects for use as a method. Whether the slice function can be applied successfully to a host object is implementation-dependent.

查阅 V8 引擎 array.js 的源码,能够将 slice 的中间得以达成简化为:

Others

无数时候,有些方法您认为选择的参数是数组,其实类数组也是能够的。

Function.prototype.apply() 函数选拔的第一个参数,其实也能够是类数组。

var obj = {0: 4, length: 2}; var arr = [1, 2, 3]; Array.prototype.push.apply(arr, obj); console.log(arr); // [1, 2, 3, 4, undefined]

1
2
3
4
var obj = {0: 4, length: 2};
var arr = [1, 2, 3];
Array.prototype.push.apply(arr, obj);
console.log(arr); // [1, 2, 3, 4, undefined]

Array-Like to Array

意气风发部分时候,要求将 Array-Like Objects 转为 Array 类型,使之能用数组的风度翩翩对情势,二个比较轻便狠毒况兼宽容性特出的艺术是新建个数组,然后循环存入数据。

我们以 arguments 为例。

function fn() {
  // Uncaught TypeError: arguments.push is not a function
  // arguments.push(4);

  var arr = [];
  for (var i = 0, len = arguments.length; i < len; i++)
    arr[i] = arguments[i];

  arr.push(4); // [1, 2, 3, 4]
}

fn(1, 2, 3);

唯独那不是最温婉的,越来越高雅的解法我们自然都明白了,use Array.prototype.slice(IE9- 会相当卡塔 尔(英语:State of Qatar)。

function fn() {
  var arr = Array.prototype.slice.call(arguments);
  arr.push(4); // arr -> [1, 2, 3, 4]
}

fn(1, 2, 3);

抑或能够用 [] 取代 Array.prototype 节省多少个字节。

function fn() {
  var arr = [].slice.call(arguments);
  arr.push(4); // arr -> [1, 2, 3, 4]
}

fn(1, 2, 3);

固然非得追求质量,用 [] 会新建个数组,质量料定不及后边三个,不过由于发动机的优化,那点间距基本得以忽视不计了(所以重重框架用的便是后人卡塔尔国。

为啥那样能够转换?大家差十分少精通下,首要的缘故是 slice 方法只需求参数有 length 属性就可以。首先,slice 方法拿到的结果是二个 新的数组,通过 Array.prototype.slice.call 传入的参数(要是为 a卡塔 尔(阿拉伯语:قطر‎,若无 length 属性,恐怕 length 属性值不是 Number 类型,大概为负,那么直接回到一个空数组,不然返回a[0]-a[length-1] 组成的数组。(具体能够看下 v8 源码 https://github.com/v8/v8/blob/master/src/js/array.js#L621-L660)

当然,ES6 提供了更省事的不二诀窍。

var str = "helloworld";
var arr = Array.from(str); 
// ["h", "e", "l", "l", "o", "w", "o", "r", "l", "d"]

小结下,要是要把 Array-Like Objects 转为 Array,首荐Array.prototype.slice,不过出于 IE 下 Array.prototype.slice.call(nodes) 会抛出错误(because a DOM NodeList is not a JavaScript object卡塔 尔(阿拉伯语:قطر‎,所以包容的写法如下。(但还可能有某个要小心的是,假若是 arguments 转为 Array,最佳别用 Array.prototype.slice,V8 下会相当的慢,具体能够看下 制止改善和传递 arguments 给任何格局 — 影响优化 )

function nodeListToArray(nodes){
  var arr, length;

  try {
    // works in every browser except IE
    arr = [].slice.call(nodes);
    return arr;
  } catch(err){
    // slower, but works in IE
    arr = [];
    length = nodes.length;

    for(var i = 0; i < length; i++){
       arr.push(nodes[i]);
     }  

    return arr;
  }
} 

《Pro JavaScript Design Patterns》(《JavaScript 设计形式》卡塔尔国的编辑者Dustin Diaz 曾建议:

复制代码 代码如下:

Read More

  • How to convert a array-like object to array?
  • Advanced Javascript: Objects, Arrays, and Array-Like objects
  • JavaScript quirk 8: array-like objects
  • 怎么样将函数的实际上参数转变到数组
  • how does Array.prototype.slice.call() work?

打赏援助我写出更加的多好小说,多谢!

打赏小编

Others

有的是时候,某些方法您感觉接纳的参数是数组,其实类数组也是能够的。

Function.prototype.apply() 函数选用的首个参数,其实也得以是类数组。

var obj = {0: 4, length: 2};
var arr = [1, 2, 3];
Array.prototype.push.apply(arr, obj);
console.log(arr); // [1, 2, 3, 4, undefined]

复制代码 代码如下:

function slice(start, end) {
var len = ToUint32(this.length), result = [];
for(var i = start; i < end; i++) {
result.push(this[i]);
}
return result;
}

打赏扶助本人写出越来越多好小说,谢谢!

必威手机官网 1

1 赞 3 收藏 评论

Read More

  • How to convert a array-like object to array?
  • Advanced Javascript: Objects, Arrays, and Array-Like objects
  • JavaScript quirk 8: array-like objects
  • 怎么将函数的其实参数转变来数组
  • how does Array.prototype.slice.call() work?

instead of…
var args = Array.prototype.slice.call(arguments); // 怿飞注:下称方法少年老成
do this…
var args = [].slice.call(arguments, 0); // 怿飞注:下称方法二

能够见到,slice 并无需 this 为 array 类型,只须要有 length 属性就能够。何况 length 属性能够不为 number 类型,当无法调换为数值时,ToUnit32(this.length) 重返 0.

本文由必威发布于必威-前端,转载请注明出处:slice 并不需要 this 为 array必威手机官网 类型,我

相关阅读