数组原型toString()vs Object toString()

时间:2015-11-17 23:36:40

标签: javascript arrays

var d = [];
console.log(typeof d); // weird!
console.log(d.toString()); //Prints nothing since there are no elements in the array
console.log(Object.prototype.toString.call(d)); // better!

当我在上面运行代码时,第一个console.log打印对象,这是预期的,因为数组是一个对象,第二个console.log打印[object Array]。我对Object.prototype.toString.call(d)的工作方式感到有些困惑。

所以我知道数组原型上的toString方法只是试图打印出数组中的元素。但是当你在基础对象的原型上调用toString方法时,toString方法究竟做了什么?它是否也尝试打印出数组的元素?基础对象上的toString方法也使用关键字this,因为我们使用.call来更改调用函数时this关键字指向的内容。

3 个答案:

答案 0 :(得分:2)

您可以将Object.prototype.toString(或简化版)视为:

Object.prototype.toString = function() {
  var myType = (typeof this)[0].toUpperCase() + (typeof this).substr(1);
  return "[Object " + myType + "]";
}

(无关:请参阅答案底部的注释以解释什么(typeof this)[0],但现在假设myType ='String'表示字符串,'Array'表示数组等)功能

它与[].toString()不同,因为数组只是一个对象的子节点,所以数组的toString被覆盖:

Array.prototype.toString = function() {
  return this.join(',');
}

当你致电Object.prototype.toString时,你指的是第一个功能,[].toString指的是第二个功能。如果你这样做没有什么不同:

function MyClass() {};
var x = new MyClass;

x.toString(); // prints "[object Object]"

MyClass.prototype.toString = function() { return 'hello!' }
x.toString(); // prints "hello!"

// and we can call Object's toString method instead
Object.prototype.toString.call(x); // prints "[object Object]" 

调用了第一个调用Object.prototype.toString,因为MyClassObject的子类,并且没有自己的toString方法。然后,当我们提供MyClass toString方法时,调用x.toString会在toString上使用MyClass方法,最后我们可以再次调用我们的“超类”{{ 1}}方法toString

(typeof this)[0]做什么? Object.prototype.toString.call(x)返回班级的名称。 (typeof this)返回typeof """string"返回typeof 5等等(注意,数组实际上有"number"类型,但object是真的!)。但是这总是小写的。 [] instanceof Array返回一个字符串,例如Object.prototype.toString,其中对象的类型为大写。 "Object String"“给我字符串的第一个字符”(typeof this)[0]“给我超出字符串第一个字符的每个字符”。同样,这里的字符串(typeof this).substr(1)只是对象的小写表示。 (typeof this)调用确保第一个字符大写。

答案 1 :(得分:2)

Object.prototype.toString.toString()的基本实现,除非它们专门覆盖.toString(),否则所有其他对象都会继承。它的默认实现是生成如下所示的输出:

"[object Type]"

其中type类似于ObjectArray等...因此,对于普通的JS对象,它会产生:

 "[object Object]"

而且,对于一个数组,它会产生:

 "[object Array]"

同时,Array类重写.toString()以提供数组内容的串联。

所以,如果您有一个数组或者可能有一个数组对象,并且您想要的是.toString()的第一种类型,那么您可以调用:

Object.prototype.toString.call(obj)

并且,这将告诉您是否有数组对象。如果它是一个数组,你会得到:

"[object Array]"

除了较新的Array.isArray()之外,通常认为这是判断对象是否为数组的最佳方式。

这是一个工作片段,说明:

var obj = {greeting: "hello"};
var arr = [1,2,3];

log(obj.toString());
log(Object.prototype.toString.call(obj))

log(arr.toString());
log(Object.prototype.toString.call(arr))

function log(x) {
    var div = document.createElement("div")
    div.innerHTML = x;
    document.body.appendChild(div);
}

答案 2 :(得分:1)

可以改进JavaScript中的数据类型检测。它绝对可以成为其中一个领域。但公平地说,这可能是因为JavaScript在11天内创建成为处理DOM的基本运行时;它确实如此!因此,只有在特殊情况下,我才需要这样做。

此外,JavaScript围绕着非常简化的类系统(称为原型),这使得强制成为典型的实践。因此,为了向任何数据类型提供方法和属性,它们临时强制转换为对象类型。这是该方法的基本方面之一。因此,主机对象(如元素)没有构造函数接口或标准这一事实基本上解释了数据类型的情况。 (当然,我们有内置插件和本地用户,如DateMath等。

同样,JavaScript仍然会按照它的目标行事,特别是在案例中,但肯定可以改进!

我想起来就像这样:

  • typeof:primitives
  • Object.prototype.toString:对象(和基元)

这是解释JavaScript数据类型检测的好资源:http://tobyho.com/2011/01/28/checking-types-in-javascript/

但这是我发现的一个例行程序,适用于我需要的每一种情况。所选择的操作和方法的顺序已经针对速度进行了专门优化。 (仅供参考,您的使用案例可能会有所不同,因此有些订单可能会被切换,但总体来说效果会非常好。):

type = type || 
(   function detect( coerce )
    {   
        if (typeof data === 'string')
            return (coerce=document.getElementById(data)) ? (data=coerce,'element') : 'string';

        if (data.type && (data.srcElement||data.target))
            return 'event';

        if (data.nodeType != void 0)
            return 'element';

        if (data[0] != void 0 && data[0].nodeType != void 0)
            return 'elements';

        if (Object.prototype.call(data) === '[object Array]')
            return 'array';

        if (data/1 === data)
            return 'number';

        return 'object';
    }
)();

既然你提到了Array Prototype,我的直觉就是告诉你:"请不要修改数组原型。" (它可能导致环境因迭代和命名空间而变得不稳定。)

其他人似乎也提供了丰富的信息!尼斯!