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

typeof 、instanceof是否正确判断类型? instanceof 原理 #51

Open
TieMuZhen opened this issue Nov 29, 2021 · 0 comments
Open

typeof 、instanceof是否正确判断类型? instanceof 原理 #51

TieMuZhen opened this issue Nov 29, 2021 · 0 comments

Comments

@TieMuZhen
Copy link
Owner

TieMuZhen commented Nov 29, 2021

typeof 是否正确判断类型

首先 typeof 能够正确的判断基本数据类型,但是除了null, typeof null输出的是对象。

但是对象来说,typeof 不能正确的判断其类型, typeof 一个函数可以输出 'function',而除此之外,输出的全是 object,这种情况下,我们无法准确的知道对象的类型。

instanceof是否正确判断类型

instanceof可以准确的判断复杂数据类型,但是不能正确判断基本数据类型

instanceof原理

instanceof是通过原型链判断的,A instanceof B, 在A的原型链中层层查找,是否有原型等于B.prototype,如果一直找到A的原型链的顶端(null;即Object.prototype.__proto__),仍然不等于B.prototype,那么返回false,否则返回true。其原理代码如下:

// L instanceof R
function instance_of(L, R) {//L 表示左表达式,R 表示右表达式
    var O = R.prototype;// 取 R 的显式原型
    L = L.__proto__;    // 取 L 的隐式原型
    while (true) { 
        if (L === null) //已经找到顶层
            return false;  
        if (O === L)   //当 O 严格等于 L 时,返回 true
            return true; 
        L = L.__proto__;  //继续向上一层原型链查找
    } 
}

使instanceof既能判断基本类型又能判断复杂类型

Symbol.hasInstance被用于确定构造对象是否是其实例。instanceof的行为可以通过这个来定制。

class MyArray {
  static [Symbol.hasInstance](instance) {
    return Array.isArray(instance)
  }
}
console.log([] instanceof MyArray);  // true

所以我们可以用这个方法来封装instanceof

/**
 * isComplex判断是否是复杂数据类型,如果是返回true,否则返回false
 * @param {*} data 需要被判断类型的数据
 */

function isComplex(data) {
    if (data && (typeof data === 'object' || typeof data === 'function')) {
        return true;
    }
    return false;
}


/**
 * 定义自己的基本数据类型
 */

class PrimitiveString {
    static [Symbol.hasInstance](data) {
        return typeof data === 'string';
    }
}

class PrimitiveNumber {
    static [Symbol.hasInstance](data) {
        return typeof data === 'number';
    }
}

class PrimitiveUndefined {
    static [Symbol.hasInstance](data) {
        return typeof data === 'undefined';
    }
}

class PrimitiveBool {
    static [Symbol.hasInstance](data) {
        return typeof data === 'boolean';
    }
}

class PrimitiveNull {
    static [Symbol.hasInstance](data) {
        return data === null;
    }
}

class PrimitiveSymbol {
    static [Symbol.hasInstance](data) {
        return typeof data === 'symbol';
    }
}


/**
 * 测试 
 */

let num = 2;
console.log(num instanceof PrimitiveNumber);    //true
console.log('isComplex: ', isComplex(num));

let str = 'Yvette';
console.log(str instanceof PrimitiveString);    //true
console.log('isComplex: ', isComplex(str));

let flag = false;
console.log(flag instanceof PrimitiveBool);     //true
console.log('isComplex: ', isComplex(flag));

let und = undefined;
console.log(und instanceof PrimitiveUndefined); //true
console.log('isComplex: ', isComplex(und));

let nul = null;
console.log(nul instanceof PrimitiveNull);      //true
console.log('isComplex: ', isComplex(nul));

let sym = Symbol(10);
console.log(sym instanceof PrimitiveSymbol);    //true
console.log('isComplex: ', isComplex(sym));

console.log('isComplex: ', isComplex(isComplex)); //true

判断数据类型除了typeof、instanceof还有constructor、Object.prototype.toString共四种

使用constructor

console.log('22'.constructor === String)             // true
console.log(true.constructor === Boolean)            // true
console.log([].constructor === Array)                // true
console.log(document.constructor === HTMLDocument)   // true
console.log(window.constructor === Window)           // true
console.log(new Number(22).constructor === Number)   // true
console.log(new Function().constructor === Function) // true
console.log((new Date()).constructor === Date)       // true
console.log(new RegExp().constructor === RegExp)     // true
console.log(new Error().constructor === Error)       // true

1、nullundefined 是无效的对象,因此是不会有 constructor 存在的,这两种类型的数据需要通过其他方式来判断。
2、函数的 constructor 是不稳定的,这个主要体现在自定义对象上,当开发者重写 prototype 后,原有的 constructor 引用会丢失,constructor 会默认为 Object

使用Object.prototype.toString

console.log(Object.prototype.toString.call(bool));//[object Boolean]
console.log(Object.prototype.toString.call(num));//[object Number]
console.log(Object.prototype.toString.call(str));//[object String]
console.log(Object.prototype.toString.call(und));//[object Undefined]
console.log(Object.prototype.toString.call(nul));//[object Null]
console.log(Object.prototype.toString.call(arr));//[object Array]
console.log(Object.prototype.toString.call(obj));//[object Object]
console.log(Object.prototype.toString.call(fun));//[object Function]

function Person(){}
function Student(){}
Student.prototype = new Person()
var haoxl = new Student()
console.log(Object.prototype.toString.call(haoxl));//[object Object]

在任何值上调用 Object 原生的 toString() 方法,都会返回一个 [object NativeConstructorName] 格式的字符串。对于 Object 对象,直接调用 toString() 就能返回 [object Object] 。而对于其他对象,则需要通过 call / apply 来调用才能返回正确的类型信息。
但是它不能检测非原生构造函数的构造函数名

参考文献

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

1 participant