一些关于javascript数据类型,你必须了解的点,你都了解了吗?
问题1:原始类型有哪几种?null是对象吗?原始数据类型和复杂数据类型存储有什么区别?
- 原始数据类型:
number,string,boolean,undefined,null,symbol typeof null是对象,但是null是基础数据类型。- 原始数据类型存储在栈中,储存的是值。
- 复杂数据类型存储在堆中,储存的是地址。
问题2:typeof和instanceof的区别,instanceof的实现原理。
typeof能够正确判断基础类型,除了null,返回object,typeof所有的对象都是object。instanceof能够正确判断复杂类型属于什么类型,但是不能正确判断基础类型。
function __instaceof(A, B) {
// 当 A 不是对象时,特殊情况先排除,因为A不是对象后,是无法访问__proto__的
if ((typeof A !== "object" && typeof A !== "function") || A === null)
return false;
// 访问 A 的原型
let a = A.__proto__;
// 访问 B 的原型
let b = B.prototype;
// 遍历 A 的原型链直到为 null 或者等于 B 的原型。
while (true) {
if (a === null) {
return false;
} else if (a === b) {
return true;
} else {
a = a.__proto__;
}
}
}
问题3:如何判断一个数据的类型。
除了上述的typeof instanceof可以去判断类型,还有String.prototype.toString.call()。
我们来看一下这个函数的ES6定义。
20.1.3.6 Object.prototype.toString() This method performs the following steps when called:
- If the this value is undefined, return "[object Undefined]" .
- If the this value is null, return "[object Null]" .
- Let O be ! ToObject(this value).
- Let isArray be ? IsArray(O).
- If isArray is true, let builtinTag be "Array" .
- Else if O has a [[ParameterMap]] internal slot, let builtinTag be "Arguments" .
- Else if O has a [[Call]] internal method, let builtinTag be "Function" .
- Else if O has an [[ErrorData]] internal slot, let builtinTag be "Error" .
- Else if O has a [[BooleanData]] internal slot, let builtinTag be "Boolean" .
- Else if O has a [[NumberData]] internal slot, let builtinTag be "Number" .
- Else if O has a [[StringData]] internal slot, let builtinTag be "String" .
- Else if O has a [[DateValue]] internal slot, let builtinTag be "Date" .
- Else if O has a [[RegExpMatcher]] internal slot, let builtinTag be "RegExp" .
- Else, let builtinTag be "Object" .
- Let tag be ? Get(O, @@toStringTag).
- If tag is not a String, set tag to builtinTag.
- Return the string-concatenation of "[object ", tag, and "]" .
从定义中可以清晰的看出来,如果我们想判断一个数据类型,使用这个方法可以识别出大部分的数据类型,除了自定义的数据类。事实上,除了以上ES6中标注的类型,还有map,set等数据类型,都可以识别,因此我们要是想要精准的识别出数据类型的话,只需要用Object.prototype.toString.call()去判断就可以了,如果是object就说明是自定义的类,再使用instanceof去判断就行了。
这里违背了单一职责原则,仅作为示例,newType做了两件事,如果不是自定义类型的话,直接可以得到类型。如果是自定义类型的话,第二个参数是父类,判断是否属于父类,返回trueorfalse。
const newType = (value, father) => {
// 获取tag
const temp = Object.prototype.toString.call(value).split(' ')[1];
const type = temp.substring(0, temp.length - 1);
if (type !== "Object") return type;
if (father && value instanceof father) return true;
return false;
};
class A {};
const a = new A();
console.log(newType(a, A));
console.log(newType(2));