Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

JS-操作符-instanceof #190

Open
yaofly2012 opened this issue Oct 22, 2020 · 0 comments
Open

JS-操作符-instanceof #190

yaofly2012 opened this issue Oct 22, 2020 · 0 comments
Labels

Comments

@yaofly2012
Copy link
Owner

yaofly2012 commented Oct 22, 2020

一、语法

1.1 基本用法

object instanceof constructorFunc

判断构造函数constructorFuncprototype属性是否在对象object的原型链上。

Object.create({}) instanceof Object // true
Object.create(null) instanceof Object // false

Function instanceof Object // true
Function instanceof Function // true
Object instanceof Object // true

1. 作为类型判断的一种方式,instanceof 操作符不会对object进行隐式类型转换

"" instanceof String; // false,基本类型不会转成对象
new String('') instanceof String; // true
  • 对于没有原型的对象,或则基本类型直接返回false
1 instanceof Object // false
Object.create(null) instanceof Object // false

2. constructorFunc必须是函数,且可以作为构造函数(即要具有prototype属性)

// TypeError: Right-hand side of 'instanceof' is not callable
1 instanceof ({})

// TypeError: Function has non-object prototype 'undefined' in instanceof check
({}) instanceof (() => {})

3. 对于跨全局执行上下文intanceof就不能正常工作了

不同的全局执行上下文的对象和函数都是不相等的。

<!DOCTYPE html>
<html>
    <head></head>
    <body>
        <iframe src=""></iframe>
        <script type="text/javascript">
            var iframe = window.frames[0];
            var iframeArr = new iframe.Array();

            console.log([] instanceof iframe.Array) // false
            console.log(iframeArr instanceof Array)  // false
            console.log(iframeArr instanceof iframe.Array)  // true       
        </script>
    </body>
</html>

1.2 PK Object.prototype.isPrototypeOf()

Object.prototype.isPrototypeOf()用于判断对象是否在另一个对象的原型链上。
[] instanceof Array相等于Array.prototype.isPrototypeOf([])
看似可以利用Object.prototype.isPrototypeOf()代替instanceof,但是其实不是的见下面“自定义instanceof行为”。

综上:只是instanceof内部逻辑利(OrdinaryHasInstance)和Object.prototype.isPrototypeOf()存在相似的地方。

二、instanceof check

var foo = () => {}
var a = {}

// TypeError: Function has non-object prototype 'undefined' in instanceof check
a instanceof foo

// 显示增加个`prototype `成员函数(必须是函数)就不报错了
foo.prototype = function() {}
a instanceof foo // false

要弄清原因还是看下规范InstanceofOperator

  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
  • Return ! ToBoolean(? Call(instOfHandler, target, « V »)).
  1. If IsCallable(target) is false, throw a TypeError exception.
  2. Return ? OrdinaryHasInstance(target, V).

即:

  1. 如果constructorFunc不是对象,直接抛TypeError异常;
  2. 如果constructorFunc定义了Symbol.hasInstance方法(不为undefined就算),则调用该方法,并以该方法的返回值作为instanceof的值;
var foo = () => {}
var a = {}

// 显示增加个`prototype `成员函数(必须是函数)就不报错了
foo.prototype = function() {}

// 自定义Symbol.hasInstance方法
Object.defineProperty(foo, Symbol.hasInstance, {
  value: {} // 不是个方法
});

// TypeError: object is not a function
a instanceof foo
  1. 否则走OrdinaryHasInstance(target, V)流程。

三、自定义instanceof行为

instanceof操作符默认通过原型链判断(OrdinaryHasInstance),但可以利用Symbol.hasInstance自定义instanceof行为。

var foo = () => {}
var a = {}

// 显示增加个`prototype `成员函数(必须是函数)就不报错了
foo.prototype = function() {}

// 自定义Symbol.hasInstance方法
Object.defineProperty(foo, Symbol.hasInstance, {
  value: function(instance) { 
    return true
   }
});

a instanceof foo // true

所有函数(包含不可以作为构造函数的函数,如Function.prototype)都定义了Symbol.hasInstance方法。

function foo() {
}

typeof  foo[Symbol.hasInstance]() // "function"
typeof Function.prototype[Symbol.hasInstance] // "function"

四、利用Object.getPrototypeOf实现instanceof

function isInstanceOf(obj, constructor) {
    if(typeof constructor !== 'object') {
        throw new TypeError('constructor is not a object')
    }

    // Symbol.hasInstance方式
    if(constructor[Symbol.hasInstance] !== undefined) {
        return !!constructor[Symbol.hasInstance](obj);
    }

    // 原型链方式:
    if(typeof obj !== 'object') {
        return false
    }

    if(typeof constructor !== 'function') {
        throw new TypeError('constructor is not a function')
    }

    if(typeof constructor.prototype !== 'object') {
        throw new TypeError('Function has non-object prototype');
    }

    while(obj !== null) {
        if(obj === constructor.prototype) {
            return true;
        }

        obj = Object.getPrototypeOf(obj);
    }

    return false;
}

参考

  1. MDN instanceof
  2. JavaScript instanceof 运算符深入剖析
@yaofly2012 yaofly2012 added the JS label Oct 22, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

1 participant