Blog icon indicating copy to clipboard operation
Blog copied to clipboard

原型与原型链 - instanceof的底层实现原理及手动实现

Open logan70 opened this issue 6 years ago • 2 comments

instanceof的底层实现原理及手动实现

作用

instanceof 用于检测右侧构造函数的原型是否存在于左侧对象的原型链上。

Symbol.hasInstance

ES6新增的内置Symbol,用作对象方法标识符,该方法用于检测任意对象是否为拥有该方法对象的实例。instanceof操作符优先使用该Symbol对应的属性。

这样一来instanceof右侧并非必须为函数,对象也可以的。示例代码如下:

const MyArray = {
    [Symbol.hasInstance](obj) {
        return Array.isArray(obj)
    }
}

expect([] instanceof MyArray).toBe(true)

手写实现

const isObj = obj => ((typeof obj === 'object') || (typeof obj === 'function')) && obj !== null
function myInstanceOf(instance, Ctor) {
    if (!isObj(Ctor)) // 右侧必须为对象
        throw new TypeError('Right-hand side of 'instanceof' is not an object')

    const instOfHandler = Ctor[Symbol.hasInstance]
    // 右侧有[Symbol.hasInstance]方法,则返回其执行结果
    if (typeof instOfHandler === 'function') return instOfHandler(instance)
        
    // 右侧无[Symbol.hasInstance]方法且不是函数的,返回false
    if (typeof Ctor !== 'function') return false
        
    // 左侧实例不是对象类型,返回false
    if (!isObj(instance)) return false
    
    // 右侧函数必须有原型
    const rightP = Ctor.prototype
    if (!isObj(rightP))
        throw new TypeError(`Function has non-object prototype '${String(rightP)}' in instanceof check`)
        
    // 在实例原型连上查找是否有Ctor原型,有则返回true
    // 知道找到原型链顶级还没有,则返回false
    while (instance !== null) {
        instance = Object.getPrototypeOf(instance)
        if (instance === null) return false
        
        if (instance === rightP) return true
    }
}

ECMAScript定义

标准出处 -> ECMAScript#instanceof

InstanceofOperator ( V, target )

  1. If Type(target) is not Object, throw a TypeError exception.
  2. Let instOfHandler be ? GetMethod(target, @@hasInstance).
  3. If instOfHandler is not undefined, then
  4. Return ToBoolean(? Call(instOfHandler, target, « V »)).
  5. If IsCallable(target) is false, throw a TypeError exception.
  6. Return ? OrdinaryHasInstance(target, V).

OrdinaryHasInstance ( C, O )

  1. If IsCallable(C) is false, return false.
  2. If C has a [[BoundTargetFunction]] internal slot, then
    • Let BC be C.[[BoundTargetFunction]].
    • Return ? InstanceofOperator(O, BC).
  3. If Type(O) is not Object, return false.
  4. Let P be ? Get(C, "prototype").
  5. If Type(P) is not Object, throw a TypeError exception.
  6. Repeat,
    • Set O to ? O.[[GetPrototypeOf]]().
    • If O is null, return false.
    • If SameValue(P, O) is true, return true.

logan70 avatar Nov 20 '19 01:11 logan70

写得太仔细了,背不下来,面试时候感觉只能写个最简单的版本

ZhaoTim avatar Aug 08 '22 11:08 ZhaoTim

写得太仔细了,背不下来,面试时候感觉只能写个最简单的版本

不用背,前面的都是边界情况处理,或者新标准的兼容,核心还是最后一块儿代码,理解最后一块儿代码,并且面试的时候能说出来我感觉足够了。

logan70 avatar Aug 29 '22 12:08 logan70