zoukankan      html  css  js  c++  java
  • JavaScript中typeof,instanceof,hasOwnProperty,in的用法和区别

    一. typeof操作符

    typeof操作符用于返回正在使用值的类型。

    // 使用原始值
    let mNull = null;
    let mUndefined = undefined;
    let mString = 'mazey';
    let mNumber = 123;
    let mBoolean = true;
    let mFunction = function () {
        return true;
    };
    
    // 用构造函数的方式new一个实例
    let oString = new String('cherrie');
    let oRegExp = new RegExp('^[0-9]+$');
    let oFunction = new Function('x', 'y', 'return x + y');
    
    let oObj = {};
    let oNew = new Object();
    
    // typeof值
    console.log(typeof mNull); // object
    console.log(typeof mUndefined); // undefined
    console.log(typeof mString); // string
    console.log(typeof mNumber); // number
    console.log(typeof mBoolean); // boolean
    console.log(typeof mFunction); // function
    console.log(typeof oString); // object
    console.log(typeof oRegExp); // object
    console.log(typeof oFunction); // function
    console.log(typeof oObj); // object
    console.log(typeof oNew); // object
    

    在《JavaScript启示录》中new RegExp()介绍会返回function,但是事实上我在chrome控制台中看到的是object

    于是我console.log(new RegExp('^[0-9]+$')),打印出来的是字符串/^[0-9]+$/

    console.log(new RegExp('^[0-9]+$')); // /^[0-9]+$/
    console.log(RegExp); // ƒ RegExp() { [native code] } 原始值
    console.log(String); // ƒ String() { [native code] } 原始值
    console.log(/^[0-9]+$/); // /^[0-9]+$/
    console.log(new RegExp('^[0-9]+$') === /^[0-9]+$/); // false
    console.log(RegExp('^[0-9]+$') === /^[0-9]+$/); // false
    

    综上可以看出现版本RegExpString Number一样属于JavaScript的原始值。

    Math作为JavaScript中的静态对象回返回什么呢?

    console.log(typeof Math); // object
    console.log(typeof Math.PI); // number
    console.log(typeof Math.ceil); // function
    

    所以Math__proto__还是Objecttypeof还能返回对象的属性和方法的类型。

    typeof使用场景

    1.判断某个变量是否已定义

    console.log(typeof aaa); // 'undefined'
    
    // 判断
    if (typeof bbb === 'undefined') {
        console.log('变量未定义');
    }
    

    2.区分原始值和复杂值(对象值)

    因为复杂值往往返回object,当然有个例外就是原始值里面的null也返回object,然后function作为Object的实例也是复杂值。

    // 判断是否时复杂值(对象值)
    function isObject (m) {
        return (typeof m === 'function' || (typeof m === 'object' && m !== null));
    }
    
    console.log(isObject(new RegExp('123'))); // true
    console.log(isObject('123')); // false
    console.log(isObject(String('123'))); // false
    console.log(isObject(null)); // false
    
    // 判断是否是原始值
    function isNative (m) {
        return (m === null || (typeof m !== 'object' && typeof m !== 'function'));
    }
    
    console.log(isNative(new RegExp('123'))); // false
    console.log(isNative('123')); // true
    console.log(isNative(String('123'))); // true
    console.log(isNative(null)); // true
    

    3.检测某个变量是否是函数

    当使用闭包时判断是函数后再进行下一步。

    function qqq () {
        let a = 0;
        let b = function () {
            a++;
            console.log(a);
        };
        return b;
    }
    
    let ccc = qqq();
    console.log(typeof ccc); // function
    if (typeof ccc === 'function') {
        ccc(); // 1
        ccc(); // 2
        ccc(); // 3
        ccc(); // 4
    }
    

    二. instanceof操作符

    通过使用instanceof操作符,可以确定一个对象是否是特定构造函数实例,返回truefalse

    instanceof只适用于构造函数创建返回的复杂对象实例

    任何时间判断一个对象(复杂值)是否是Object的实例时,它都将返回true,因为所有对象都继承自Object()构造函数。

    let oFather = function () {
        this.firstName = 'mazey';
    };
    oFather.prototype.lastName = 'qian';
    
    // 实例
    let oSon = new oFather();
    console.log(oSon instanceof oFather); // true
    
    // 继承
    let nFather = function () {};
    nFather.prototype = new oFather();
    nFather.construction = nFather;
    console.log(nFather.firstName); // undefined
    console.log(nFather.prototype.lastName); // qian
    console.log(nFather instanceof oFather); // false
    console.log(new nFather() instanceof nFather); // true
    
    // 相对于Object来说
    console.log('123' instanceof Object); // false
    console.log(new String('123') instanceof Object); // true 构造出来的实例
    console.log(null instanceof Object); // false
    

    instanceof使用场景

    判断在一个继承关系中实例是否属于它的父类。

    // 继承
    let oFather = function () {};
    let nFather = function () {};
    nFather.prototype = new oFather();
    nFather.construction = nFather;
    
    let nSon = new nFather();
    console.log(nSon instanceof nFather); // true
    console.log(nSon instanceof oFather); // true
    

    三. in操作符和hasOwnProperty方法

    in操作符可以检查一个对象的属性,包括来自原型链的属性,hasOwnProperty()方法可以检查来自非原型链属性的对象。

    例如现在有一个对象let obj = {name: 'mazey'};name是它自身定义的属性,toString是它从原型链上继承下来的属性。

    let obj = {name: 'mazey'};
    console.log('name' in obj); // true
    console.log('toString' in obj); // true
    console.log('name' in Object); // true
    console.log(obj.hasOwnProperty('name')); // true
    console.log(obj.hasOwnProperty('toString')); // false
    console.log(Object.hasOwnProperty('name')); // true
    

    所以in操作符查找的范围更广一点,可以用hasOwnProperty()判断是否是对象自身的属性,而不是通过类似obj.prototype.foo = 'foo';这样定义的。

    hasOwnProperty方法使用场景

    在实际项目中经常使用for...in...来遍历对象中可枚举的属性,但是for...in...常常把原型obj.prototype.xxx中的属性也列举出来,所以在循环的时候可以加上hasOwnProperty()方法判断下。

    function obj0 () {
        this.name = 'mazey',
        this.age = '24'
    };
    obj0.prototype.gender = 'male';
    let obj1 = new obj0();
    
    // 打印所有可枚举属性
    for (let key in obj1) {
        console.log(key); // name age gender 从原型链上继承下来的属性也会被打印出来
    }
    
    // 过滤掉原型链上的属性
    for (let key in obj1) {
        if (obj1.hasOwnProperty(key)) {
            console.log(key); // name age
        }
    }
    

    四. 总结

    1.typeof可以判断使用值的类型,注意null返回object。 2.instanceof验证构造函数构造出来的实例,可以用来判断一个对象是否属于一个父类。 3.hasOwnProperty方法常常与in操作符搭配使用,用来遍历一个对象自身的属性。

    五. 相关扩展

    1.删除对象的属性

    若想把一个对象的自身属性完全删除,要使用delete操作符。

    let obj0 = {
        name: 'mazey',
        age: 24
    };
    
    // 删除age属性
    delete obj0.age;
    console.log(obj0.hasOwnProperty('age')); // false
    console.log('age' in obj0); // false
    
    // 试着删除原型链上的属性 toString
    delete obj0.toString
    console.log('toString' in obj0); // true
    

    需要注意的是delete不会删除原型链上的属性。

    2.可枚举

    每个对象的属性都分为可枚举和不可枚举属性,可以使用propertyIsEnumerable()方法来检查哪些属性是可枚举的。

    每个对象都有一个propertyIsEnumerable方法。此方法可以确定对象中指定的属性是否可以被for...in(for...in语句以任意顺序遍历一个对象的可枚举属性。对于每个不同的属性,语句都会被执行)循环枚举,但是通过原型链继承的属性除外。如果对象没有指定的属性,则此方法返回false

    有的资料说只要能被for..in遍历的属性就是可枚举的,实际上要排除从原型链上继承下来的属性,只有自身的属性是可枚举的。

    // 第一个构造函数
    function ConFun0 () {
        this.firstName = 'mazey';
    }
    ConFun0.prototype.firstCom = 'bang';
    
    // 第二个构造函数
    function ConFun1 () {
        this.secondName = 'qian';
    }
    // 继承第一个
    ConFun1.prototype = new ConFun0();
    ConFun1.prototype.constructor = ConFun1;
    
    // 实例
    let obj = new ConFun1();
    obj.girlName = 'cherrie';
    
    // 是否可枚举
    console.log(obj.propertyIsEnumerable('constructor')); // false
    console.log(obj.propertyIsEnumerable('firstName')); // false
    console.log(obj.propertyIsEnumerable('firstCom')); // false
    // 通过原型链继承的属性不是可枚举
    console.log(obj.propertyIsEnumerable('secondName')); // true
    console.log(obj.propertyIsEnumerable('girlName')); // true
    
    for (let key in obj) {
        console.log(key); // secondName girlName (原型链上的属性也会被打印出来->) firstName constructor firstCom
    }
    
    console.log(`---分割线---`);
    
    for (let key in obj) {
        // 过滤掉原型链上的属性
        if (obj.hasOwnProperty(key)) {
            console.log(key); // secondName girlName
        }
    }
    

    所以可枚举的属性一定能被for..in循环遍历出来,但是for...in循环遍历出来的属性不一定是可枚举的,需排除从原型链上继承下来的属性,这里可以通过hasOwnProperty()方法过滤掉不可枚举属性。

    JavaScript中typeof,instanceof,hasOwnProperty,in的用法和区别

  • 相关阅读:
    printf,wprintf与setlocale,char与wchar_t区别
    C++常量表达式、const、constexpr(C++11新增)的区别
    珍珠项链 Beads
    A Horrible Poem
    三个朋友
    Seek the Name, Seek the Fame
    Power Strings
    图书管理
    子串查找
    山峰和山谷 Ridges and Valleys
  • 原文地址:https://www.cnblogs.com/mazey/p/7965733.html
Copyright © 2011-2022 走看看