【问题标题】:Array Prototype toString() vs Object toString()数组原型 toString() 与对象 toString()
【发布时间】:2015-11-17 23:36:40
【问题描述】:
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 方法究竟做了什么?它是否也尝试打印出数组的元素?基础 Object 上的 toString 方法是否也使用了关键字 this,因为我们使用的是 .call,它会在调用函数时更改 this 关键字指向的内容。

【问题讨论】:

    标签: javascript arrays


    【解决方案1】:

    你可以把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 for array 只是被覆盖:

    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使用MyClass上的toString方法,最后我们可以再次使用Object.prototype.toString.call(x)调用我们的“超类”toString方法。


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

    【讨论】:

    • 嗨!在此行中: var myType = (typeof this)[0].toUpperCase() + (typeof this).substr(1);为什么在 (typeof this) 之后有 [0]?你能介绍一下变量 myType 是什么吗?就像 (typeof this)[0].toUpperCase() 会打印出什么?大批?和 (typeof this).substr(1)。谢谢!
    • 当然,(typeof this) 返回你的类名。 typeof "" 返回字符串,typeof [] 返回数组等。但是这始终是小写的。 Object.prototype.toString 返回一个字符串,例如“Object String”,其中对象的类型为大写。 (typeof this)[0] 说“给我字符串的第一个字符,并且 (typeof this).substr(1) 说“给我字符串第一个字符之外的每个字符”。同样,这里的字符串 ( typeof this) 只是对象的小写表示。toUpperCase 调用确保第一个字符大写。
    • 哦,好吧!我不知道您可以使用 [0] 访问字符串中的字符。所以在这种情况下 (typeof this) 将返回数组,带有小写的 a 并且您访问 a 并将其设为大写。
    • (typeof this) 将返回一个字符串,但您可以像枚举数组一样枚举字符串,是的,您完全正确,我们将第一个字符设为大写 ​​:)
    • @Macmee "typeof [] 返回数组" - 不,绝对不是。您的 Object.prototype.toString 实现过于简化。简化可能很好,因为方法行为不是问题的关键,但如果你是故意这样做的,你必须提到它。
    【解决方案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(),这通常被认为是判断对象是否为数组的最佳方法。


    这是一个工作的 sn-p 说明:

    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);
    }

    【讨论】:

      【解决方案3】:

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

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

      再次重申,JavaScript 仍然在做它的初衷,而且在某些情况下尤其出色,但肯定可以改进!

      我是这样想的:

      • typeof: 原语
      • 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,我的直觉是告诉你:“请不要修改数组原型。” (它可能会导致环境因迭代和命名空间而变得不稳定。)

      其他人似乎也提供了丰富的信息!不错!

      【讨论】:

      • 好吧,关于选择的答案,typeof 会为了对象而工作,但不是整体。也许他只是在证明事实。
      • 顺便说一句,我只记得一个语法简写:{}.toString.call; (我相信这是正确的。虽然创建了一个一次性对象......)
      猜你喜欢
      • 2017-02-28
      • 1970-01-01
      • 1970-01-01
      • 2010-12-02
      • 1970-01-01
      • 2018-11-22
      • 1970-01-01
      • 1970-01-01
      • 2014-10-04
      相关资源
      最近更新 更多