# instanceof 原理

  • instanceof 运算符用于检测构造函数的 prototype 属性是否出现在某个实例对象的原型链上。
  • 语法 object instanceof constructor
  • 参数 object(某个实例对象)constructor(某个构造函数)
  • 本质上 instanceof 运算符用来检测 constructor.prototype 是否存在于参数 object 的原型链上。
function _instanceof(target, origin) {
  // 这里需要加层判断
  if (typeof target !== 'object') return false
  // 循环 当 target 为 null 时 (代表已经达到顶层原型已经指向 null),那么停止循环
  while (target) {
    if (Reflect.getPrototypeOf(target) === origin.prototype) return true
      
    // 否则再取出 target 的隐式原型对象
    target = Reflect.getPrototypeOf(target)
  }
  return false
}

# instanceof 测试

function Foo() { }
const f = new Foo
            
f instanceof Foo    // true
f instanceof Object   // true
f instanceof Function // false
            
'abc' instanceof String        // false
123 instanceof Number          // false
[] instanceof Array            // true
{} instanceof Object           // true
(() => {}) instanceof Object   // true
(() => {}) instanceof Function // true
(() => {}) instanceof Array    // false

# _instanceof 测试

function Foo() { }
const f = new Foo
_instanceof(f, Foo)      // true
_instanceof(f, Object)   // true
_instanceof(f, Function) // false
_instanceof('abc', String)      // false
_instanceof(123, Number)        // false
_instanceof([], Array)          // true
_instanceof({}, Object)         // true
_instanceof(() => {}, Object)   // true
_instanceof(() => {}, Function) // true
_instanceof(() => { }, Array)   // false

# new 原理

  • new 实际做了什么?

    • 创建一个新的空对象

    • 把新对象的原型绑定到构造函数的原型上

    • 构造函数被执行,执行过程中的 this 被绑定在新的对象上

    • 返回这个新对象 (构造函数中一般不会显示返回, 但有时也可以 return this)

# Object.setPrototypeOf 实现

function _new(fn, ...args) {
  // 1. 创建新的空对象
  const obj = {}
  
  // 2. 把新对象的原型绑定到构造函数的原型上
  Object.setPrototypeOf(obj, fn.prototype)
  // 3. 构造函数被执行,绑定 `this` 与传入参数在新的对象上,并获取 obj 函数执行的结果
  const result = fn.apply(obj, args)
  // 4. 如果执行结果有返回值并且是一个对象,返回执行的结果,否则,返回新创建的对象 
  return Object.prototype.toString.call(result) === '[object Object]' ? result : obj
}
  • 测试
function Foo() {}
const foo = new Foo()
_new(Foo) instanceof Foo // true
foo instanceof Foo // true

# Object. create 实现

function _new(fn, ...args){
  // 1. 基于 obj 的原型创建一个新的对象
  const obj = Object.create(fn.prototype);
  // 2. 添加属性到新创建的 newObj 上,并获取 obj 函数执行的结果
  const result = fn.apply(obj, args);
  // 3. 如果执行结果有返回值并且是一个对象,返回执行的结果,否则,返回新创建的对象
  return Object.prototype.toString.call(result) === '[object Object]' ? result : obj
}
  • 测试
function Foo() {}
const foo = new Foo()
_new(Foo) instanceof Foo // true
foo instanceof Foo // true

# typeof 原理

  • typeof 一般被用于判断一个变量的类型,我们可以利用 typeof 来判断 number , string , object , boolean , function , undefined , symbol 这七种类型

  • 这种判断能帮助我们搞定一些问题,比如在判断不是 object 类型的数据的时候, typeof 能比较清楚的告诉我们具体是哪一类的类型。

  • 但是,很遗憾的一点是, typeof 在判断一个 object 的数据的时候只能告诉我们这个数据是 object, 而不能细致的具体到是哪一种 object

  • , 比如我们都知道 typeof(null) === 'object' ,关于原因,在小黄书《你不知道的 JavaScript》中有这么一段解释:

    原理是这样的, 不同的对象在底层都表示为二进制, 在 JavaScript 中二进制前三位都为 0 的话会被判断为 object 类型, null 的二进制表示是全 0, 自然前三位也是 0, 所以执行 typeof 时会返回 “object”。

  • javascript 中的 null :既是对象,又不是对象,史称「薛定谔的对象」。

typeof null === 'object' // true
null instanceof Object  // false
  • 如果我们这样比较
null instanceof null
  • 会抛出异常: TypeError: invalid 'instanceof' operand null
  • 在 javascript 的最初版本中,使用的 32 位系统,为了性能考虑使用低位存储了变量的类型信息:
    • 000:对象
    • 1:整数
    • 010:浮点数
    • 100:字符串
    • 110:布尔
  • 有 2 个值比较特殊:
    • undefined:用 - (−2^30)表示。
    • null:对应机器码的 NULL 指针,一般是全零。
  • 在第一版的 javascript 实现中,判断类型的代码是这么写的:
if (JSVAL_IS_VOID(v)) {  // (1)
    type = JSTYPE_VOID;
} else if (JSVAL_IS_OBJECT(v)) {  // (2)
    obj = JSVAL_TO_OBJECT(v);
    if (obj &&
        (ops = obj->map->ops,
            ops == &js_ObjectOps
            ? (clasp = OBJ_GET_CLASS(cx, obj),
            clasp->call || clasp == &js_FunctionClass) // (3,4)
            : ops->call != 0)) {  // (3)
        type = JSTYPE_FUNCTION;
    } else {
        type = JSTYPE_OBJECT;
    }
} else if (JSVAL_IS_NUMBER(v)) {
    type = JSTYPE_NUMBER;
} else if (JSVAL_IS_STRING(v)) {
    type = JSTYPE_STRING;
} else if (JSVAL_IS_BOOLEAN(v)) {
    type = JSTYPE_BOOLEAN;
}
  • 判断是否为 undefined
  • 如果不是 undefined,判断是否为对象
  • 如果不是对象,判断是否为数字
  • ......
  • 这样一来, null 就出了一个 bug。根据 type tags 信息,低位是 000 ,因此 null 被判断成了一个对象。这就是为什么 typeof null 的返回值是 object
  • 摘自:https://cloud.tencent.com/developer/article/1362660