将函数的实在参数转换成数组的主意,特殊对象

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 方法将 arguments
对象转换成真正的数组:
var args = Array.prototype.slice.call(arguments);
对此slice 方法,ECMAScript 262 中 15.4.4.10 Array.prototype.slice
(start, end) 章节有备注:

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_INTEGER(感谢 @HangYang 同学指出)
,因为那是 JavaScript 中能精确表示的最大数字。

合计还有怎么着同时能满意上述条件的?NodeList,HTML
Collections,仔细揣摩,甚至还有字符串,或者有所 length
属性的目的,函数(length 属性值为形参数量),等等。

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

复制代码 代码如下:

复制代码 代码如下:

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_INTEGER(感谢 @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.

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.

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 Diaz 曾提议:

《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]

复制代码 代码如下:

复制代码 代码如下:

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

亚洲必赢官网 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); // 怿飞注:下称方法二

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

至于作者:韩子迟

亚洲必赢官网 2

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

亚洲必赢官网 3

但双方的属性差别真的留存呢?经过个人简单测试发现:

但两岸的习性差别真的存在呢?经过个人简单测试发现:

在 arguments.length
较小的时候,方法二特性上稍有一点点优势,而在arguments.length
较大的时候,方法一却又稍有优势。

在 arguments.length
较小的时候,方法二属性上稍有一点点优势,而在arguments.length
较大的时候,方法一却又稍有优势。

最后附上方法三,最老土的不二法门:

说到底附上方法三,最老土的法子:

复制代码 代码如下:

复制代码 代码如下:

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

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

但是对此日常来说,个人提议如故采取第两种艺术,但别的缓解方案,没有最好的,唯有最合适:

但是对于平日来说,个人提议照旧采纳第二种格局,但任何缓解方案,没有最好的,唯有最合适:

复制代码 代码如下:

复制代码 代码如下:

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

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

貌似的函数的 arguments.length 都在 10 以内,方法二有优势;
主意二的代码量上也比第一种少,至少可以减小一点字节 ^^

诚如的函数的 arguments.length 都在 10 以内,方法二有优势;
主意二的代码量上也比第一种少,至少能够减小一点字节 ^^

哪些将 NodeList
(比如:document.getElementsByTagName(‘div’))转换成数组呢?

如何将
NodeList
(比如:document.getElementsByTagName(‘div’))转换成数组呢?

化解方案大致如下:

解决方案大致如下:

复制代码 代码如下:

复制代码 代码如下:

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

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

缘何 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.

何以 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.

slice 方法将
arguments 对象转换成真正的数组: var args =
Array.prototype.slice.call(arguments); 对于slice 方法,E…

网站地图xml地图