JavaScript 深入之类数组对象与 arguments

2019-12-04 02:01栏目:龙电竞官网
TAG:

JavaScript 浓重之类数组对象与 arguments

2017/05/27 · JavaScript · arguments

最初的稿件出处: 冴羽   

JavaScript 长远之call和apply的比葫芦画瓢达成

2017/05/25 · JavaScript · apply, call

原稿出处: 冴羽   

类数组对象

所谓的类数组对象:

不无贰个 length 属性和若干索引属性的指标

举个例证:

var array = ['name', 'age', 'sex']; var arrayLike = { 0: 'name', 1: 'age', 2: 'sex', length: 3 }

1
2
3
4
5
6
7
8
var array = ['name', 'age', 'sex'];
 
var arrayLike = {
    0: 'name',
    1: 'age',
    2: 'sex',
    length: 3
}

纵然如此,为啥叫做类数组对象啊?

那让大家从读写、获取长度、遍历多少个方面看看这多个目的。

call

一句话介绍 call:

call(卡塔尔国 方法在使用二个钦命的 this 值和多少个钦定的参数值的前提下调用有个别函数或艺术。

例如:

var foo = { value: 1 }; function bar() { console.log(this.value); } bar.call(foo); // 1

1
2
3
4
5
6
7
8
9
var foo = {
    value: 1
};
 
function bar() {
    console.log(this.value);
}
 
bar.call(foo); // 1

专心两点:

  1. call 改变了 this 的指向,指向到 foo
  2. bar 函数施行了

读写

console.log(array[0]); // name console.log(arrayLike[0]); // name array[0] = 'new name'; arrayLike[0] = 'new name';

1
2
3
4
5
console.log(array[0]); // name
console.log(arrayLike[0]); // name
 
array[0] = 'new name';
arrayLike[0] = 'new name';

依傍完毕率先步

那么大家该怎么模拟完成那四个功能啊?

试想当调用 call 的时候,把 foo 对象改产生如下:

var foo = { value: 1, bar: function() { console.log(this.value) } }; foo.bar(); // 1

1
2
3
4
5
6
7
8
var foo = {
    value: 1,
    bar: function() {
        console.log(this.value)
    }
};
 
foo.bar(); // 1

本条时候 this 就照准了 foo,是或不是超级粗略吗?

也才那样却给 foo 对象自己增加了贰特性质,那可非常啊!

但是也不用顾虑,我们用 delete 再删除它不就好了~

所以大家模拟的手续能够分为:

  1. 将函数设为对象的习性
  2. 实行该函数
  3. 删去该函数

以上个例证为例,正是:

// 第一步 foo.fn = bar // 第二步 foo.fn() // 第三步 delete foo.fn

1
2
3
4
5
6
// 第一步
foo.fn = bar
// 第二步
foo.fn()
// 第三步
delete foo.fn

fn 是指标的属性名,反正最终也要刨除它,所以起成什么都不在乎。

基于这一个思路,大家得以尝尝着去写第风度翩翩版的 call2 函数:

// 第生龙活虎版 Function.prototype.call2 = function(context卡塔尔 { // 首先要拿走调用call的函数,用this能够收获 context.fn = this; context.fn(卡塔尔(قطر‎; delete context.fn; } // 测验一下 var foo = { value: 1 }; function bar(卡塔尔(英语:State of Qatar) { console.log(this.value卡塔尔; } bar.call2(foo卡塔尔国; // 1

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// 第一版
Function.prototype.call2 = function(context) {
    // 首先要获取调用call的函数,用this可以获取
    context.fn = this;
    context.fn();
    delete context.fn;
}
 
// 测试一下
var foo = {
    value: 1
};
 
function bar() {
    console.log(this.value);
}
 
bar.call2(foo); // 1

赶巧能够打字与印刷 1 哎!是否非常高兴!(~ ̄▽ ̄卡塔尔国~

长度

console.log(array.length); // 3 console.log(arrayLike.length); // 3

1
2
console.log(array.length); // 3
console.log(arrayLike.length); // 3

宪章达成第二步

最大器晚成开端也讲了,call 函数还可以够给定参数实践函数。譬喻:

var foo = { value: 1 }; function bar(name, age) { console.log(name) console.log(age) console.log(this.value); } bar.call(foo, 'kevin', 18); // kevin // 18 // 1

1
2
3
4
5
6
7
8
9
10
11
12
13
14
var foo = {
    value: 1
};
 
function bar(name, age) {
    console.log(name)
    console.log(age)
    console.log(this.value);
}
 
bar.call(foo, 'kevin', 18);
// kevin
// 18
// 1

潜心:传入的参数并不明确,那可咋做?

不急,我们能够从 Arguments 对象中取值,抽取第贰个到终极八个参数,然后放到叁个数组里。

比方那样:

// 以上个例子为例,当时的arguments为: // arguments = { // 0: foo, // 1: 'kevin', // 2: 18, // length: 3 // } // 因为arguments是类数组对象,所以能够用for循环 var args = []; for(var i = 1, len = arguments.length; i len; i++) { args.push('arguments[' + i + ']'); } // 执行后 args为 [foo, 'kevin', 18]

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// 以上个例子为例,此时的arguments为:
// arguments = {
//      0: foo,
//      1: 'kevin',
//      2: 18,
//      length: 3
// }
// 因为arguments是类数组对象,所以可以用for循环
var args = [];
for(var i = 1, len = arguments.length; i  len; i++) {
    args.push('arguments[' + i + ']');
}
 
// 执行后 args为 [foo, 'kevin', 18]

不定长的参数难题一举成功了,我们跟着要把这么些参数数组放到要进行的函数的参数里面去。

// 将数组里的因素作为几个参数放进函数的形参里 context.fn(args.join(','卡塔尔(قطر‎卡塔尔国// (O_o卡塔尔(قطر‎?? // 那个办法自然是非常的啊!!!

1
2
3
4
// 将数组里的元素作为多个参数放进函数的形参里
context.fn(args.join(','))
// (O_o)??
// 这个方法肯定是不行的啦!!!

大概有人想到用 ES6 的措施,可是 call 是 ES3 的艺术,大家为了模仿完结叁个ES3 的不二等秘书籍,要用到ES6的不二等秘书籍,好像……,嗯,也得以啊。不过大家本次用 eval 方法拼成二个函数,雷同于那般:

eval('context.fn(' + args +')')

1
eval('context.fn(' + args +')')

此间 args 会自动调用 Array.toString(卡塔尔国 这些情势。

于是我们的第二版克制了七个大题目,代码如下:

// 第二版 Function.prototype.call2 = function(context) { context.fn = this; var args = []; for(var i = 1, len = arguments.length; i len; i++) { args.push('arguments[' + i + ']'卡塔尔(قطر‎; } eval('context.fn(' + args +'卡塔尔'卡塔尔(قطر‎; delete context.fn; } // 测验一下 var foo = { value: 1 }; function bar(name, age卡塔尔(قطر‎ { console.log(name卡塔尔(英语:State of Qatar) console.log(age卡塔尔(قطر‎console.log(this.value卡塔尔(英语:State of Qatar); } bar.call2(foo, 'kevin', 18卡塔尔(قطر‎; // kevin // 18 // 1

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
// 第二版
Function.prototype.call2 = function(context) {
    context.fn = this;
    var args = [];
    for(var i = 1, len = arguments.length; i  len; i++) {
        args.push('arguments[' + i + ']');
    }
    eval('context.fn(' + args +')');
    delete context.fn;
}
 
// 测试一下
var foo = {
    value: 1
};
 
function bar(name, age) {
    console.log(name)
    console.log(age)
    console.log(this.value);
}
 
bar.call2(foo, 'kevin', 18);
// kevin
// 18
// 1

(๑•̀ㅂ•́)و✧

遍历

for(var i = 0, len = array.length; i len; i++) { …… } for(var i = 0, len = arrayLike.length; i len; i++) { …… }

1
2
3
4
5
6
for(var i = 0, len = array.length; i  len; i++) {
   ……
}
for(var i = 0, len = arrayLike.length; i  len; i++) {
    ……
}

是否很像?

那类数组对象能够应用数组的方法吗?比方:

arrayLike.push('4');

1
arrayLike.push('4');

而是上述代码会报错: arrayLike.push is not a function

进而终归还是类数组呐……

依傍完成第三步

模仿代码已经完毕 八成,还应该有几个小点要介怀:

1.this 参数能够传 null,当为 null 的时候,视为指向 window

举个例证:

var value = 1; function bar() { console.log(this.value); } bar.call(null); // 1

1
2
3
4
5
6
7
var value = 1;
 
function bar() {
    console.log(this.value);
}
 
bar.call(null); // 1

固然如此那一个例子本身不采用 call,结果依旧相近。

2.函数是能够有重临值的!

比如:

var obj = { value: 1 } function bar(name, age) { return { value: this.value, name: name, age: age } } console.log(bar.call(obj, 'kevin', 18)); // Object { // value: 1, // name: 'kevin', // age: 18 // }

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
var obj = {
    value: 1
}
 
function bar(name, age) {
    return {
        value: this.value,
        name: name,
        age: age
    }
}
 
console.log(bar.call(obj, 'kevin', 18));
// Object {
//    value: 1,
//    name: 'kevin',
//    age: 18
// }

但是都很好清除,让大家直接看第三版也正是最终意气风发版的代码:

// 第三版 Function.prototype.call2 = function (context) { var context = context || window; context.fn = this; var args = []; for(var i = 1, len = arguments.length; i len; i++) { args.push('arguments[' + i + ']'卡塔尔(قطر‎; } var result = eval('context.fn(' + args +'卡塔尔'卡塔尔(英语:State of Qatar); delete context.fn return result; } // 测量检验一下 var value = 2; var obj = { value: 1 } function bar(name, age卡塔尔(英语:State of Qatar) { console.log(this.value卡塔尔; return { value: this.value, name: name, age: age } } bar.call(null卡塔尔国; // 2 console.log(bar.call2(obj, 'kevin', 18卡塔尔(英语:State of Qatar)卡塔尔(英语:State of Qatar); // 1 // Object { // value: 1, // name: 'kevin', // age: 18 // }

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
// 第三版
Function.prototype.call2 = function (context) {
    var context = context || window;
    context.fn = this;
 
    var args = [];
    for(var i = 1, len = arguments.length; i  len; i++) {
        args.push('arguments[' + i + ']');
    }
 
    var result = eval('context.fn(' + args +')');
 
    delete context.fn
    return result;
}
 
// 测试一下
var value = 2;
 
var obj = {
    value: 1
}
 
function bar(name, age) {
    console.log(this.value);
    return {
        value: this.value,
        name: name,
        age: age
    }
}
 
bar.call(null); // 2
 
console.log(bar.call2(obj, 'kevin', 18));
// 1
// Object {
//    value: 1,
//    name: 'kevin',
//    age: 18
// }

到此,大家做到了 call 的效仿达成,给本身一个赞 b( ̄▽ ̄)d

调用数组方法

若果类数组正是即兴的想用数组的章程如何是好吧?

既是无法直接调用,大家能够用 Function.call 直接调用:

var arrayLike = {0: 'name', 1: 'age', 2: 'sex', length: 3 } Array.prototype.join.call(arrayLike, '&'); // name&age&sex Array.prototype.slice.call(arrayLike, 0); // ["name", "age", "sex"] // slice能够成功类数组转数组 Array.prototype.map.call(arrayLike, function(item卡塔尔(英语:State of Qatar){ return item.toUpperCase(卡塔尔(英语:State of Qatar); }卡塔尔; // ["NAME", "AGE", "SEX"]

1
2
3
4
5
6
7
8
9
10
11
var arrayLike = {0: 'name', 1: 'age', 2: 'sex', length: 3 }
 
Array.prototype.join.call(arrayLike, '&'); // name&age&sex
 
Array.prototype.slice.call(arrayLike, 0); // ["name", "age", "sex"]
// slice可以做到类数组转数组
 
Array.prototype.map.call(arrayLike, function(item){
    return item.toUpperCase();
});
// ["NAME", "AGE", "SEX"]

apply的效仿实现

apply 的贯彻跟 call 相通,在这里处直接给代码,代码来自于网易 @郑航的兑现:

Function.prototype.apply = function (context, arr) { var context = Object(context) || window; context.fn = this; var result; if (!arr) { result = context.fn(); } else { var args = []; for (var i = 0, len = arr.length; i len; i++) { args.push('arr[' + i + ']'); } result = eval('context.fn(' + args + ')') } delete context.fn return result; }

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
Function.prototype.apply = function (context, arr) {
    var context = Object(context) || window;
    context.fn = this;
 
    var result;
    if (!arr) {
        result = context.fn();
    }
    else {
        var args = [];
        for (var i = 0, len = arr.length; i  len; i++) {
            args.push('arr[' + i + ']');
        }
        result = eval('context.fn(' + args + ')')
    }
 
    delete context.fn
    return result;
}

类数组转对象

在地方的事例中已经涉嫌了风流罗曼蒂克体系数组转数组的主意,再补偿多少个:

var arrayLike = {0: 'name', 1: 'age', 2: 'sex', length: 3 } // 1. slice Array.prototype.slice.call(arrayLike); // ["name", "age", "sex"] // 2. splice Array.prototype.splice.call(arrayLike, 0); // ["name", "age", "sex"] // 3. ES6 Array.from Array.from(arrayLike); // ["name", "age", "sex"] // 4. apply Array.prototype.concat.apply([], arrayLike)

1
2
3
4
5
6
7
8
9
var arrayLike = {0: 'name', 1: 'age', 2: 'sex', length: 3 }
// 1. slice
Array.prototype.slice.call(arrayLike); // ["name", "age", "sex"]
// 2. splice
Array.prototype.splice.call(arrayLike, 0); // ["name", "age", "sex"]
// 3. ES6 Array.from
Array.from(arrayLike); // ["name", "age", "sex"]
// 4. apply
Array.prototype.concat.apply([], arrayLike)

那么为什么会讲到类数组对象啊?以至类数组有如何应用吗?

要谈到类数组对象,Arguments 对象正是二个类数组对象。在客商端 JavaScript 中,一些 DOM 方法(document.getElementsByTagName(卡塔尔(قطر‎等卡塔尔(英语:State of Qatar)也回到类数组对象。

重在参照

网易难题 不可能采纳call、apply、bind,怎么样用 js 达成 call 也许 apply 的功用?

Arguments对象

接下去注重讲讲 Arguments 对象。

Arguments 对象只定义在函数体中,满含了函数的参数和别的质量。在函数体中,arguments 指代该函数的 Arguments 对象。

举个例证:

function foo(name, age, sex) { console.log(arguments); } foo('name', 'age', 'sex')

1
2
3
4
5
function foo(name, age, sex) {
    console.log(arguments);
}
 
foo('name', 'age', 'sex')

打字与印刷结果如下:

图片 1

咱俩得以看出除了类数组的索引属性和length属性之外,还会有三个callee属性,接下去我们一个贰个介绍。

深刻连串

JavaScript深切连串目录地址:。

JavaScript深刻连串猜想写十一篇左右,目的在于帮大家捋顺JavaScript底层知识,着眼讲授如原型、效能域、推行上下文、变量对象、this、闭包、按值传递、call、apply、bind、new、世襲等苦衷概念。

假设有荒谬或然不战战惶惶的地点,请必得赋予指正,十三分感激。尽管钟爱如故持有启示,接待star,对笔者也是豆蔻梢头种鞭挞。

本系列:

  1. JavaScirpt 浓烈之从原型到原型链
  2. JavaScript 深切之词法成效域和动态成效域
  3. JavaScript 深入之执行上下文栈
  4. JavaScript 深远之变量对象
  5. JavaScript 深刻之成效域链
  6. JavaScript 浓重之从 ECMAScript 标准解读 this
  7. JavaScript 深远之实行上下文
  8. JavaScript 深切之闭包
  9. JavaScript 深远之参数按值传递

    1 赞 收藏 评论

图片 2

版权声明:本文由龙竞技官网发布于龙电竞官网,转载请注明出处:JavaScript 深入之类数组对象与 arguments