大家好,我是考100分的小小码 ,祝大家学习进步,加薪顺利呀。今天说一说【JS】类型判断instanceof、typeof、isArray对比与原理解析「终于解决」,希望您对编程的造诣更进一步.
谈到JS的类型判断,首先我们先了解JS当中的数据类型内容。
JS数据基本类型和引用类型
- 基本类型:undefined、null、string、number、boolean、symbol(ES6)
- 普通基本类型:undefined、null、symbol(ES6)
- 特殊基本包装类型:String、Number、Boolean
- 引用类型:Object、Array、RegExp、Date、Function 【JS】string和String差异详解,基本类型和包装类的差异对比详解
类型判断的几种方式
typeof value
- 取值:’undefined’/’boolean’/’string’/’number’/’object’/’function’/’symbol’
- typeof不能判断object具体是哪种类型,比如:Array之类的
- typeof null 为’object’,其实是错误的,因为null不是object类型。
判断原理:根据变量的机器码低位1-3位存储其类型信息。
-
000:对象
-
010:浮点数
-
100:字符串
-
110:布尔
-
1:整数 因为null所有机器码都是0,所以typeof会把null判断为对象 typeof 原理
-
适合的使用场景:判断除了object之外的基本类型,避免判断null。
-
局限性:不适合判断Object,function,array等引用类型
value instanceof Type == true/false
- instanceof实现原理:看实例的___proto____指向的原型链上,有没有跟右侧类型的prototype指向同一个对象的
function new_instance_of(leftVaule, rightVaule) {
let rightProto = rightVaule.prototype; // 取右表达式的 prototype 值
leftVaule = leftVaule.__proto__; // 取左表达式的__proto__值
while (true) {
if (leftVaule === null) {
return false;
}
if (leftVaule === rightProto) {
return true;
}
leftVaule = leftVaule.__proto__
}
}
instanceof原理
- 局限:假设只有一个单一的全局环境。如果网页当中包含多个框架,存在两个以上不同的全局执行环境,因为存在两个以上不同版本的Array构造函数。如果从一个 框架向另一个框架传入一个数组,传入的数组与在第二个框架中原生创建的数组构造函数不同。《Javascript高级教程》
判断引用类型:Object.prototype.toString.call(value)
- 原理
Object.prototype.toString关键代码中,最终返回的对象是'[object ' + classof(this) + ']'
字符串。 可以理解为:说该方法会返回当前this
对象的对应的类型class
字符串
'use strict';
require('./_redefine')(Object.prototype, 'toString', function toString() {
return '[object ' + classof(this) + ']';
}, true);
classof(this)
伪代码逻辑:
this === undefined;return 'Undefined'
this === null;return 'Null'
O = ToObject(this value)
把当前对象转换成Object
因为js中Object key值只允许string或者Symbol类型
IsArray(O)判断是否是数组对象
IsArray判断逻辑:
Type(O)判断是否是Object,不是直接return false;
O是否为Array exotic object:
如果O的[[DefineOwnProperty]]和Array的方法一样:
大概逻辑是:
内置定义的length属性,length属性不可以人为修改
O内置定义的所有key值是可以类型转换成数字的字符串,
并且最终数字范围必须在0~2^32-1次方以内,
length的取值要大于0所有的key对应的array index
....
就认为这个是个Array对象,return 'Array';
...
注:不同版本的js规范中实现逻辑可能略有不同
ECMA#sec-object.prototype.tostring
- 应用:
Array.isArray = function(value) {
return Object.prototype.toString.call(value) === '[object Array]';
}
// 通用的类型判断方法
function type(value,typeStr){
var str = Object.prototype.toString.call(value);
var curType = str.slice(8,str.length-1);
return curType.toLowerCase() === typeStr.toLowerCase();
}
Object toString参考
Object.prototype.toString方法的演进
最近查看最新的ECMA262文档中,有了以下Note:
Historically, this function was occasionally used to access the String value of the [[Class]] internal slot that was used in previous editions of this specification as a nominal type tag for various built-in objects. 上一版本中该方法是读取的[[Class]]内置插槽的字符串数值作为内置对象的类型名称 The above definition of toString preserves compatibility for legacy code that uses toString as a test for those specific kinds of built-in objects. It does not provide a reliable type testing mechanism for other kinds of built-in or program defined objects. In addition, programs can use @@toStringTag in ways that will invalidate the reliability of such legacy type tests. 在新的版本当中可以读取对象上面的
@@toStringTag
来判断内置对象的类型名称
[[Class]]内置插槽的字符串在后续更新的内置对象中弃用了。 [[class]] property in ES2015
@@toStringTag
属性可以通过内置Symbol,Symbol.toStringTag访问
Symbol.toStringTag
我们可以来尝试一下,如果把Symbol.toStringTag
改掉会怎么样
var str = new String('123');
str[Symbol.toStringTag] = 'test';
console.log(Object.prototype.toString.call(str));
//输出 [object test]
所以此属性是可以被覆盖的
不同类型的Symbol.toStringTag
内容(代码来源lodash)
const argsTag = '[object Arguments]'
const arrayTag = '[object Array]'
const boolTag = '[object Boolean]'
const dateTag = '[object Date]'
const errorTag = '[object Error]'
const mapTag = '[object Map]'
const numberTag = '[object Number]'
const objectTag = '[object Object]'
const regexpTag = '[object RegExp]'
const setTag = '[object Set]'
const stringTag = '[object String]'
const symbolTag = '[object Symbol]'
const weakMapTag = '[object WeakMap]'
const arrayBufferTag = '[object ArrayBuffer]'
const dataViewTag = '[object DataView]'
const float32Tag = '[object Float32Array]'
const float64Tag = '[object Float64Array]'
const int8Tag = '[object Int8Array]'
const int16Tag = '[object Int16Array]'
const int32Tag = '[object Int32Array]'
const uint8Tag = '[object Uint8Array]'
const uint8ClampedTag = '[object Uint8ClampedArray]'
const uint16Tag = '[object Uint16Array]'
const uint32Tag = '[object Uint32Array]'
总结
- 判断数据是否是基础数据类型:typeof
- 判断数据是否具体是哪种引用类型:Object.prototype.toString.call(this)
- 判断数据是否是其他类型的子集:instanceof
其他参考
JavaScript专题之类型判断(下)
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
转载请注明出处: https://daima100.com/13842.html