澳门新萄京特殊对象,将函数的实际参数转换成
分类:澳门新萄京最大平台

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_INTEGEWrangler(多谢 @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),若无 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_INTEGETiguan(感激 @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- 会有标题)。

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 迪亚兹 曾建议:

复制代码 代码如下:

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卡塔尔(英语:State of Qatar) 再次来到 0.

至于作者:韩子迟

澳门新萄京 2

a JavaScript beginner 个人主页 · 笔者的稿子 · 9 ·    

澳门新萄京 3

但两个的属性差距真的留存呢?经过个人轻松测量检验发现:

对此标准浏览器,上边已经将 slice 的法规解释清楚了。可是讨厌的 ie, 总是给大家添乱子:

在 arguments.length 超小的时候,方法二性格上稍有一丝丝优势,而在arguments.length 异常的大的时候,方法风度翩翩却又稍有优势。

复制代码 代码如下:

最终附上方法三,最老土的法子:

var slice = Array.prototype.slice;
slice.call(); // => IE: Object expected.
slice.call(document.childNodes); // => IE: JScript object expected.

复制代码 代码如下:

以上代码,在 ie 里报错。可恨 IE 的 Trident 引擎不开源,那我们唯有预计了:

var args = [];
for (var i = 1; i < arguments.length; i ) {
args.push(arguments[i]);
}

复制代码 代码如下:

可是对于平时来讲,个人建议照旧利用第三种办法,但其余缓和方案,未有最棒的,独有最合适:

function ie_slice(start, end) {
var len = ToUint32(this.length), result = [];

澳门新萄京特殊对象,将函数的实际参数转换成数组的方法。复制代码 代码如下:

if(__typeof__ this !== 'JScript Object') throw 'JScript object expected';
if(this === null) throw 'Oject expected';

var args = [].slice.call(arguments, 0);
理由有二:

for(var i = start; i < end; i ) {
result.push(this[i]);
}
return result;
}

貌似的函数的 arguments.length 都在 10 以内,方法二有优势;
情势二的代码量上也比第生机勃勃种少,最少能够减小一点字节 ^^

由来,把猥琐的 ie 十全十美完结。

什么将 NodeList (比方:document.getElementsByTagName('div'卡塔尔(英语:State of Qatar))转变来数组呢?

关于 slice, 还或许有三个话题:用 Array.prototype.slice 如故 [].slice ? 从理论上讲,[] 须求创设三个数组,品质上会比 Array.prototype 稍差。但骨子里,这两个大致,就好像循环里用 i 依然 i 同样,纯属个人习于旧贯。

缓和方案大概如下:

最后贰个话题,有关质量。对于数组的筛选来讲,有一个阵亡色相的写法:

复制代码 代码如下:

复制代码 代码如下:

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;
}
}

var ret = [];
for(var i = start, j = 0; i < end; i ) {
ret[j ] = arr[i];
}

干什么 IE 中 NodeList 无法动用 [].slice.call(nodes卡塔尔(قطر‎ 方法转换呢?
In Internet Explorer it throws an error that it can't run Array.prototype.slice.call(nodes) because a DOM NodeList is not a JavaScript object.

用空间换时间。去掉 push, 对于大数组来讲,质量升高依然比较领悟的。

slice 方法将 arguments 对象转换来真正的数组: var args = Array.prototype.slice.call(arguments卡塔尔(英语:State of Qatar); 对于slice 方法,E...

凌晨写博,心思不是很好,得留个难点给我们:

复制代码 代码如下:

var slice = Array.prototype.slice;
alert(slice.call({0: 'foo', length: 'bar'})[0]); // ?
alert(slice.call(NaN).length); // ?
alert(slice.call({0: 'foo', length: '100'})[0]); // ?

平日用来将 array-like 对象调换为 true array. 名词解释:array-like object – 具备 length 属性的对象,例如 { 0: ‘foo', length: 1...

本文由澳门新萄京发布于澳门新萄京最大平台,转载请注明出处:澳门新萄京特殊对象,将函数的实际参数转换成

上一篇:澳门新萄京:Es6学习笔记,Array数组的基本操作 下一篇:没有了
猜你喜欢
热门排行
精彩图文