因为我发现如果类似数组的对象(即参数数组)是或不是JavaScript数据类型,我在漫游的材料中会出现一些不一致的情况?通常我们会谈论数据类型,如下所示:String,Number,Boolean,Array,Object,Null,Undefined。但是我想也是预先定义了类似阵列的对象,所以我不知道它们为什么不被包含在内。
答案 0 :(得分:1)
"类似数组的对象"是任何具有数字索引和length
属性的对象,表示它包含多少个值。
"类似数组的对象"不是数据类型,而只是适合该描述的某些对象的类别。例如,以下是类似于数组的对象,它直接来自Object
,而不是更具体的:
var alo = {
0: "hello",
1: 3,
length: 2
};
您通常可以在类似数组的对象上使用某些数组操作,它们仍然可以像数组一样工作。特别是,您可以使用slice()
方法将类似数组的对象转换为实际数组:
var a = Array.prototype.slice.call(alo); // a is an actual array with the values
// "hello" and 3
并且您可以直接在类似数组的对象上使用某些数组方法,而无需先将它们转换为数组。以下打印出"你好"和" 3":
Array.prototype.forEach.call(alo,function(v){console.log(v);})
答案 1 :(得分:0)
不,类似于数组的对象被调用,因为它们只是一个带有整数键的Object。例如:
var myArraylike = {
0: "someValue",
1: "moreValues",
"length": 2
};
myArraylike[0] == "someValue"; //true
它们不被视为自己的数据类型,您可以通过运行来注意到:
typeof myArraylike; //returns "object"
请注意,由于原型概念,其他“对象”本身并不是它们自己的数据类型:
typeof Array; //returns "function"
构造函数只不过是函数,它们的产品是一个对象:
typeof new Array(); //returns "object"
但是那些对象(Array
,Date
等的实例)如何被认为是他们自己的类型?答案是上面提到的“原型”概念。让我们定义自己的“类型”!
function CoolType() {
this.y = 10;
}
CoolType.prototype.doCoolStuff = function() {
console.log(this.y);
}
我们创建了一个引用this
的函数,这是一个解析为当前对象的特殊关键字。我们还在doCoolStuff
的特殊prototype
属性中定义了一个名为CoolType
的函数。
当我们实例化CoolType
(使用new
)时,它的原型被复制到新创建的对象中,然后执行CoolType
函数体:
var x = new CoolType();
x.doCoolStuff(); //prints 10
对象上不存在的任何属性都将从其原型中检索(如果它没有这样的属性,它将检查其原型)。这样,您就可以继承对象的行为:
function AwesomeType() {
this.y = 42;
}
AwesomeType.prototype = CoolType;
var x = new AwesomeType();
x.doCoolStuff(); //prints 42
您可能想知道“所有这些与数组类对象有什么关系?”,原因是:类似数组的对象是行为类似于数组的对象(具有长度和数字键属性,如见上文),但其原型不是Array
。
答案 2 :(得分:0)
javascript类型系统有点不一致。存在哪种类型取决于你的要求。获取值类型的最基本方法是使用typeof
运算符:
typeof(2) // 'number'
typeof('foo') // 'string'
typeof(true) // 'boolean'
typeof(undefined) // 'undefined'
typeof(null) // 'object'
typeof([]) // 'object'
typeof({}) // 'object'
typeof((function(){return arguments;})()) // 'object'
正如您所看到的,typeof
运算符将arguments
视为一个对象,但它也将正常数组视为对象,并且就此而言为null。 (出于微不足道的兴趣,null实际上是一个对象,因为早期锁定在规范中的语言的原始实现中存在错误)。还有其他方法可以告诉值有什么类型。一种常见的技巧是使用Object.prototype.toString.call()
:
Object.prototype.toString.call(2) // '[object Number]'
Object.prototype.toString.call('foo') // '[object String]'
Object.prototype.toString.call(true) // '[object Boolean]'
Object.prototype.toString.call(undefined) // '[object Undefined]'
Object.prototype.toString.call(null) // '[object Null]'
Object.prototype.toString.call([]) // '[object Array]'
Object.prototype.toString.call({}) // '[object Object]'
Object.prototype.toString.call((function(){return arguments;})()) // '[object Arguments]'
正如您所看到的,这种方法更有效。它确实有局限性。具体是用户定义的类:
Object.prototype.toString.call(new (function Foo(){})()) // '[object Object]'
查找对象类名称的最佳方法是.constructor
:
(2).constructor.name // 'Number'
('foo').constructor.name // 'String'
(true).constructor.name // 'Boolean'
(undefined).constructor.name // TypeError
(null).constructor.name // TypeError
([]).constructor.name // 'Array'
({}).constructor.name // 'Object'
((function(){return arguments;})()).constructor.name // 'Object'
(new (function Foo(){})()).constructor.name // 'Foo'
正如您所看到的,这对于参数,null或undefined不起作用。当Chrome控制台显示带有用户定义类的值时,可能会感兴趣使用constructor.name
:
// (Chrome only)
> ({a: 1})
<- Object {a: 1}
> new (function Foo(){this.a = 1;})()
<- Foo {a: 1}
> ({constructor: {name: 'Bar'}})
<- Bar {constructor: Object}
在实践中,我倾向于使用下划线中定义的类型方法进行大多数类型检查。
在许多实际方法中,参数也与数组不同。具体来说,虽然数组的长度属性在被修改时会被更新,但是参数并不存在,而且数组中内置的方法也没有内置在参数中:
[1,2,3,4,5].slice(2,4) // [3, 4]
x = (function(){return arguments})(1,2,3,4,5)
x.slice(2, 4) // TypeError
但有一种解决方法:
[].slice.call(x, 2, 4) // [3, 4]
(上述内容已在Node.js,Chrome和Firefox中测试过) (互联网浏览器明显偏离此)
答案 3 :(得分:-3)
数组是存储数据类型和其他对象的对象。