JavaScript之类数组对象

类数组对象

拥有一个length属性和若干索引属性的对象。
让我们从三个方面来观察这个类数组

读写

1
2
3
4
5
6
7
8
9
var arr = {
0: 1,
1: 2,
2: 3,
length: 3
}
console.log(arr[0]) // 1
console.log(arr[1]) // 2
console.log(arr[2]) // 3

长度

1
2
3
4
5
6
7
var arr = {
0: 1,
1: 2,
2: 3,
length: 3
}
console.log(arr.length) = 3

遍历

1
2
3
4
5
6
7
8
9
10
var arr = {
0: 1,
1: 2,
2: 3,
length: 3
}

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

从上面来看和数组似乎是一样的,接下来试试能不能使用数组的方法

调用数组方法

1
2
3
4
5
6
7
8
 var arr = {
0: 1,
1: 2,
2: 3,
length: 3
}
arr.push(4)
Uncaught TypeError: arr.push is not a function

并不能直接使用到数组的方法,可以尝试使用回调

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
var arr = {
0: 1,
1: 2,
2: 3,
length: 3
}

Array.prototype.push.call(arr,4)
console.log(arr) // {0: 1, 1: 2, 2: 3, 3: 4, length: 4}
console.log(Array.prototype.slice.call(arr)) // [1, 2, 3, 4]
console.log(Array.prototype.join.call(arr,"|"))//1|2|3|4
console.log(
Array.prototype.map.call(arr,function(item){
return item
})
) // [1, 2, 3, 4]

类数组转数组

1
2
3
4
5
6
7
8
9
10
11
12
13
14
var arr = {
0: 1,
1: 2,
2: 3,
length: 3
}
// 1. slice
console.log(Array.prototype.slice.call(arr)) //[1, 2, 3]
// 2. splice
console.log(Array.prototype.splice.call(arr,0)) //[1, 2, 3]
// 3. ES6 Array.from
console.log( Array.from(arr)) //[1, 2, 3]
// 4. apply
console.log(Array.prototype.concat.apply([], arr)) // [1, 2, 3]

Argument对象

Argument对象只定义在函数体中,包括了函数的参数和其他属性。在函数体中,argument指代函数的Arguments对象。

1
2
3
4
5
6
7
8
9
function arr(){
console.log(arguments)
}
arr()
--------------console.log-------
callee: ƒ arr()
length: 0
Symbol(Symbol.iterator): ƒ values()
__proto__: Object

除了类数组的索引属性和lenght属性之外,还有一个callee属性

callee属性

Arguments对象的callee属性,通过它可以调用函数自身

1
2
3
4
5
6
7
8
//arguments.callee 函数自身
var test = (function(x){
console.log(x);
return arguments.callee;
}
)(0);
test(1)(2)(3);
// 0 ,1 , 2, 3
1
2
3
4
5
6
7
8
9
10
11
12
// 利用callee解决闭包问题
var data = [];
for(var i = 0; i < 3; i ++){
(data[i] = function(){
console.log(arguments.callee.i) // 0,1,2
console.log("i === " , i) //3
}).i = i
}

data[0]();
data[1]();
data[2]();

arguments的应用场景

  1. 参数不定长
  2. 函数柯里化

    柯里化,英语:Currying,把接受多个参数的函数变换成接受一个单一参数(最初函数的第一个参数)的函数,并且返回接受余下的参数而且返回结果的新函数的技术。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    // 普通的add函数
    function add(x, y) {
    return x + y
    }

    // Currying后
    function curryingAdd(x) {
    return function (y) {
    return x + y
    }
    }

    console.log(add(1, 2)) // 3
    console.log(curryingAdd(1)(2)) // 3

实际上就是把add函数的x,y两个参数变成了先用一个函数接收x然后返回一个函数去处理y参数。
那么使用它的好处在哪?

  • 参数复用

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    // 正常正则验证字符串 reg.test(txt)

    // 函数封装后
    function check(reg, txt) {
    return reg.test(txt)
    }

    check(/\d+/g, 'test') //false
    check(/[a-z]+/g, 'test') //true

    // Currying后
    function curryingCheck(reg) {
    return function(txt) {
    return reg.test(txt)
    }
    }

    var hasNumber = curryingCheck(/\d+/g)
    var hasLetter = curryingCheck(/[a-z]+/g)

    hasNumber('test1') // true
    hasNumber('testtest') // false
    hasLetter('21212') // false
  • 延迟运行

    1
    2
    3
    4
    5
    6
    7
    8
    Function.prototype.bind = function (context) {
    var _this = this
    var args = Array.prototype.slice.call(arguments, 1)

    return function() {
    return _this.apply(context, args)
    }
    }

js中经常使用的bind,实现的机制就是Currying.

  1. 递归调用
  2. 函数重载