前端八股文-类型判断

1,003 阅读2分钟

系列文章

前端八股文-原型链

前端八股文-继承

前端八股文-手写new、bind、call、apply的三两事

typeof(无法正确判断类型)

  • 对于原始类型来说,除了 null 都可以显示正确的类型
  • 对于对象来说,除了函数都会显示 object
  • 对于null,显示 object

instanceof(原始类型无效)

用法:object(要检测的对象) instanceof constructor(某个构造函数)

描述:用来检测 constructor.prototype 是否存在于参数 object 的原型链上

重点:另外,更重要的一点是 instanceof 可以在继承关系中用来判断一个实例是否属于它的父类型。其本质是在原型链上层层检索

正常使用用例:

const Person = function() {}
const p1 = new Person()
p1 instanceof Person // true

var str = 'hello world'
str instanceof String // false

var str1 = new String('hello world')
str1 instanceof String // true

对于原始类型来说,你想直接通过 instanceof 来判断类型是不行的,当然我们还是有办法让 instanceof 判断原始类型的

class PrimitiveString {
  static [Symbol.hasInstance](x) {
    return typeof x === 'string'
  }
}
console.log('hello world' instanceof PrimitiveString) // true

重点代码用例:

  function Aoo() {} // 构造函数 Aoo
  function Foo() {} // 构造函数 Foo
  Foo.prototype = new Aoo(); //将Aoo的实例赋值给Foo的原型
  var foo = new Foo(); // 构造函数Foo的实例
  // foo.__proto__ === Foo.prototype
  // foo.__proto__.__proto__ === Aoo.prototype
  console.log(foo.__proto__ === Foo.prototype); // __proto__指向构造函数的原型
  console.log(foo.__proto__.__proto__ === Aoo.prototype);
  console.log(foo instanceof Foo) //true Foo的原型是挂载在实例
  console.log(foo instanceof Aoo)//true //  Foo.prototype往上接着找___proto__,找到Aoo.prototype,因而为true

Object.prototype.toString.call()

toString方法可以将对象转化为形如"[object XXX]" 的字符串。

大多数对象,toString() 方法都是重写了的,这时,需要用 call() 或 Reflect.apply() 等方法来调用。

对于 Object.prototype.toString.call(arg),若参数为 null 或 undefined,直接返回结果。

若参数不为 null 或 undefined,则将参数转为对象,再作判断。

注意:原始数据类型,在调用方法时,会先将原始数据类型转换为包装对象再进行方法调用

var a = '1'
a.length  =>  new String('1').length

核心原理

转为对象后,取得该对象的 [Symbol.toStringTag] 属性值(可能会遍历原型链)作为 tag,如无该属性,或该属性值不为字符串类型,则依下表取得 tag, 然后返回 "[object " + tag + "]" 形式的字符串。属性值期望是一个字符串,否则会被忽略。

类型检测列表

// Boolean 类型,tag 为 "Boolean"
Object.prototype.toString.call(true);            // => "[object Boolean]"

// Number 类型,tag 为 "Number"
Object.prototype.toString.call(1);               // => "[object Boolean]"

// String 类型,tag 为 "String"
Object.prototype.toString.call("");              // => "[object String]"

// Array 类型,tag 为 "String"
Object.prototype.toString.call([]);              // => "[object Array]"

// Arguments 类型,tag 为 "Arguments"
Object.prototype.toString.call((function() {
  return arguments;
})());                                           // => "[object Arguments]"

// Function 类型, tag 为 "Function"
Object.prototype.toString.call(function(){});    // => "[object Function]"

// Error 类型(包含子类型),tag 为 "Error"
Object.prototype.toString.call(new Error());     // => "[object Error]"

// RegExp 类型,tag 为 "RegExp"
Object.prototype.toString.call(/\d+/);           // => "[object RegExp]"

// Date 类型,tag 为 "Date"
Object.prototype.toString.call(new Date());      // => "[object Date]"

// 其他类型,tag 为 "Object"
Object.prototype.toString.call(new class {});    // => "[object Object]"

重写Symbol.toStringTag的示例

var o1 = { [Symbol.toStringTag]: "A" };
var o2 = { [Symbol.toStringTag]: null };

Object.prototype.toString.call(o1);      // => "[object A]"
Object.prototype.toString.call(o2);      // => "[object Object]"