资讯专栏INFORMATION COLUMN

谈谈 Object.prototype.toString 。

zollero / 2896人阅读

摘要:前几日看到一个比较熟悉的面试题,判断一个变量是不是数组以下几种方法供参考这篇文章主要是谈谈。宿主对象的内部属性的值可以是除了的任何字符串。注,本规范中除了通过见没有提供任何手段使程序访问此值。

原文链接我的blog。

前几日看到一个比较熟悉的面试题,判断一个变量是不是数组?
以下几种方法供参考:

var arr = [1, 2, 3]
Array.isArray(arr)
arr instanceof Array
arr.constructor === Array
Object.prototype.toString.call(arr) === "[object Array]"
...

这篇文章主要是谈谈 Object.prototype.toString

ECMAScript 5

在ECMAScript 5中,Object.prototype.toString()被调用时,会进行如下步骤:

如果 thisundefined ,返回 [object Undefined]

如果 thisnull , 返回 [object Null]

O 为以 this 作为参数调用 ToObject 的结果;

classO 的内部属性 [[Class]] 的值;

返回三个字符串 "[object", class, 以及"]" 拼接而成的字符串。

[[Class]]

[[Class]]是一个内部属性,值为一个类型字符串,可以用来判断值的类型。

有这么一段详细的解释:

本规范的每种内置对象都定义了 [[Class]] 内部属性的值。宿主对象的 [[Class]] 内部属性的值可以是除了 "Arguments", "Array", "Boolean", "Date", "Error", "Function", "JSON", "Math", "Number", "Object", "RegExp", "String" 的任何字符串。[[Class]] 内部属性的值用于内部区分对象的种类。注,本规范中除了通过 Object.prototype.toString ( 见 15.2.4.2) 没有提供任何手段使程序访问此值。

在JavaScript代码里,唯一可以访问该属性的方法就是通过 Object.prototype.toString ,通常方法如下:

Object.prototype.toString.call(value)

举例:

> Object.prototype.toString.call(null)
"[object Null]"

> Object.prototype.toString.call(undefined)
"[object Undefined]"

> Object.prototype.toString.call(Math)
"[object Math]"

> Object.prototype.toString.call({})
"[object Object]"

> Object.prototype.toString.call([])
"[object Array]"

因此,可以用下列函数,来获取任意变量的[[Class]]属性:

function getClass (a) {
  const str = Object.prototype.toString.call(a)
  return /^[object (.*)]$/.exec(str)[1]
}

运行即可得

> getClass(null)
"Null"

> getClass(undefined)
"Undefined"

> getClass(Math)
"Math"

> getClass({})
"Object"

> getClass([])
"Array"
ECMAScript 6

在ES6,调用 Object.prototype.toString 时,会进行如下步骤:

如果 thisundefined ,返回 "[object Undefined]" ;

如果 thisnull , 返回 "[object Null]"

O 为以 this 作为参数调用 ToObject 的结果;

isArrayIsArray(O)

ReturnIfAbrupt(isArray) (如果 isArray 不是一个正常值,比如抛出一个错误,中断执行);

如果 isArraytrue , 令 builtinTag"Array" ;

else ,如果 O is an exotic String object , 令 builtinTag"String"

else ,如果 O 含有 [[ParameterMap]] internal slot, , 令 builtinTag"Arguments"

else ,如果 O 含有 [[Call]] internal method , 令 builtinTagFunction

else ,如果 O 含有 [[ErrorData]] internal slot , 令 builtinTagError

else ,如果 O 含有 [[BooleanData]] internal slot , 令 builtinTagBoolean

else ,如果 O 含有 [[NumberData]] internal slot , 令 builtinTagNumber

else ,如果 O 含有 [[DateValue]] internal slot , 令 builtinTagDate

else ,如果 O 含有 [[RegExpMatcher]] internal slot , 令 builtinTagRegExp

else , 令 builtinTagObject

tagGet(O, @@toStringTag) 的返回值( Get(O, @@toStringTag) 方法,既是在 O 是一个对象,并且具有 @@toStringTag 属性时,返回 O[Symbol.toStringTag] );

ReturnIfAbrupt(tag) ,如果 tag 是正常值,继续执行下一步;

如果 Type(tag) 不是一个字符串,let tag be builtinTag

返回由三个字符串 "[object", tag, and "]" 拼接而成的一个字符串。

在ES6里,之前的 [[Class]] 不再使用,取而代之的是一系列的 internal slot ,有一个比较完整的解释:

Internal slots correspond to internal state that is associated with objects and used by various ECMAScript specification algorithms. Internal slots are not object properties and they are not inherited. Depending upon the specific internal slot specification, such state may consist of values of any ECMAScript language type or of specific ECMAScript specification type values

大概的意思是:Internal slots 对应于与对象相关联并由各种ECMAScript规范算法使用的内部状态,它们没有对象属性,也不能被继承,根据具体的 Internal slot 规范,这种状态可以由任何ECMAScript语言类型或特定ECMAScript规范类型值的值组成。

此外,通过对 Object.prototype.toString 在ES6的实现步骤分析,我们其实可以很容易改变 Object.prototype.toString.call 的结果,像下面一样:

let obj = {}

Object.defineProperty(obj, Symbol.toStringTag, {
    get: function() {
        return "newClass"
    }
})

console.log(Object.prototype.toString.call(obj)) // "[object newClass]"
ECMAScript 7

ES7目前还是工作草案,到目前为止,就 Object.prototype.toString 的实现步骤来说, 只是移除了ES6其中的 ReturnIfAbrupt

参考

http://www.ecma-international...

http://www.adobe.com/devnet/a...

https://developer.mozilla.org...

http://www.ecma-international...

http://es6.ruanyifeng.com/#do...

https://tc39.github.io/ecma26...

完。

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/82969.html

相关文章

  • 谈谈javascript的Function中那些隐藏的属性/方法:caller/callee/app

    摘要:在全局环境中调用函数是不会生成此属性,因为不符合此属性的存在意义价值见上条。函数递归时用起来比用函数名调用函数更带感方法这俩方法性质一样,只是用法稍有不同,因此放在一起来介绍。 javascript的Function中有不少不那么常用,又或者用了也是知其然而不知其所以然的属性/方法,本文就来谈谈这一系列属性/方法:caller/callee/apply/call/bind。 call...

    shery 评论0 收藏0
  • 深入理解 Javascript 之 对象

    摘要:返回如下仔细分析下面的图,将会加深你的理解和我们有一个类对象有一个属性,其指向构造器的原型是一个类构造器是之后产生的。 撸js基础之对象 图例 showImg(https://segmentfault.com/img/remote/1460000015949904?w=768&h=448); 先谈谈 ECMAScript 中的数据类型 ES6 之前 ECMAScript 中有 5 种...

    neroneroffy 评论0 收藏0
  • lodash源码分析之获取数据类型

    摘要:规范对类型的判断进行了细化,前步可以看成跟的作用一样,获取到数据的类型,但是第步调用了的方法,如果再看规范的描述,可以知道这个其实是对象中的属性,如果这个属性返回的是一个字符串,则采用这个返回值作为数据的类型,否则才采用。 所有的悲伤,总会留下一丝欢乐的线索,所有的遗憾,总会留下一处完美的角落,我在冰峰的深海,寻找希望的缺口,却在惊醒时,瞥见绝美的阳光!——几米 本文为读 lodas...

    huangjinnan 评论0 收藏0
  • 读 arale 源码之 class 篇

    摘要:拥有了和方法的三个变种属性这三个属性会做特殊处理继承的方法,只支持单继承建立原型链来实现继承强制改变构造函数提供语法糖,来调用父类属性混入属性,可以混入多个类的属性将参数变成数组无论参数是类,还是对象,都混入。 更新:读 arale 源码之 attribute 篇 arale 是阿里、开源社区明星人物--玉伯,开发的一套组件,代码相当优美,大赞玉伯的开源精神,我是您的粉丝。 这里分享下...

    firim 评论0 收藏0
  • 掌握 Javascript 类型转换:从规则开始

    摘要:首先,为了掌握好类型转换,我们要理解一个重要的抽象操作为什么说这是个抽象操作呢因为这是内部才会使用的操作,我们不会显示调用到。基本规则中的类型转换总是返回基本类型值,如字符串数字和布尔值,不会返回对象和函数。 Javascript 里的类型转换是一个你永远绕不开的话题,不管你是在面试中还是工作写代码,总会碰到这类问题和各种的坑,所以不学好这个那是不行滴。关于类型转换我也看过不少的书和各...

    mikyou 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<