js类型的一二三点

174 阅读3分钟

一些关于javascript数据类型,你必须了解的点,你都了解了吗?

问题1:原始类型有哪几种?null是对象吗?原始数据类型和复杂数据类型存储有什么区别?

  1. 原始数据类型:number, string, boolean,undefined, null, symbol
  2. typeof null是对象,但是null是基础数据类型。
  3. 原始数据类型存储在栈中,储存的是值。
  4. 复杂数据类型存储在堆中,储存的是地址。

问题2:typeofinstanceof的区别,instanceof的实现原理。

  1. typeof能够正确判断基础类型,除了null,返回objecttypeof所有的对象都是object
  2. 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:

  1. If the this value is undefined, return "[object Undefined]" .
  2. If the this value is null, return "[object Null]" .
  3. Let O be ! ToObject(this value).
  4. Let isArray be ? IsArray(O).
  5. If isArray is true, let builtinTag be "Array" .
  6. Else if O has a [[ParameterMap]] internal slot, let builtinTag be "Arguments" .
  7. Else if O has a [[Call]] internal method, let builtinTag be "Function" .
  8. Else if O has an [[ErrorData]] internal slot, let builtinTag be "Error" .
  9. Else if O has a [[BooleanData]] internal slot, let builtinTag be "Boolean" .
  10. Else if O has a [[NumberData]] internal slot, let builtinTag be "Number" .
  11. Else if O has a [[StringData]] internal slot, let builtinTag be "String" .
  12. Else if O has a [[DateValue]] internal slot, let builtinTag be "Date" .
  13. Else if O has a [[RegExpMatcher]] internal slot, let builtinTag be "RegExp" .
  14. Else, let builtinTag be "Object" .
  15. Let tag be ? Get(O, @@toStringTag).
  16. If tag is not a String, set tag to builtinTag.
  17. Return the string-concatenation of "[object ", tag, and "]" .

从定义中可以清晰的看出来,如果我们想判断一个数据类型,使用这个方法可以识别出大部分的数据类型,除了自定义的数据类。事实上,除了以上ES6中标注的类型,还有mapset等数据类型,都可以识别,因此我们要是想要精准的识别出数据类型的话,只需要用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));