[英]Is array-like object a datatype
正如我发现,如果类数组对象(即arguments数组)是JavaScript数据类型还是不是JavaScript数据类型,我在徘徊的材料中存在一些不一致之处? 通常,我们谈论数据类型的原因如下:字符串,数字,布尔值,数组,对象,空值,未定义。 但是我想像数组一样的对象也是预定义的,所以我不知道为什么不包括它们。
“类数组对象”是具有数字索引和length
属性(指示其包含多少个值)的任何对象。
“类似数组的对象”不是数据类型,而只是适合该描述的某些对象的类别。 例如,以下是一个类似数组的对象,它直接从Object
派生,而不是更具体的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
您可以直接在类似数组的对象上使用某些数组方法,而无需先将它们转换为数组。 以下显示“ hello”和“ 3”:
Array.prototype.forEach.call(alo,function(v){console.log(v);})
不,类似数组的对象之所以这样称呼,是因为它们只是一个带有整数键的对象。 例:
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
的函数,这是一个可解析为当前对象的特殊关键字。 我们还在CoolType
的特殊prototype
属性中定义了一个名为doCoolStuff
的函数。
当我们实例化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
。
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。 这可能是该镀铬控制台使用兴趣constructor.name
当它显示与用户定义的类值:
// (Chrome only)
> ({a: 1})
<- Object {a: 1}
> new (function Foo(){this.a = 1;})()
<- Foo {a: 1}
> ({constructor: {name: 'Bar'}})
<- Bar {constructor: Object}
在实践中,我倾向于使用下划线中定义的类型方法进行大多数类型检查。
参数在许多实际方面也与数组不同。 具体来说,虽然数组的length属性在被修改时会更新,但参数不会被更新,但是数组中内置的方法也不会在参数上内置:
[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中进行了测试)(互联网浏览器明显与此不同)
数组是用于存储数据类型和其他对象的对象。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.