Object

需要链接:

MDN —— Object

JavaScript标准参考教程(Object对象)——阮一峰

标准构造器函数Object可能是JavaScript最重要的对象之一,尽管我们从来不会直接调用它。每当使用一个对象直接量时,都会隐式调用它:

    var a = {};                // 等同于var a = new Object()
    var b = {x:1,y:2};        // 等同于var b = new Object({x:1,y:2});

构造函数定义了数据类型,所以表达式var a = new Object()表明两件事情:a是Object的一个实例,而a的原型是Object.prototype。我们用对象字面量创建的每个对象都会获得由Object.prototype定义的行为

图片描述


以下将讨论几个常用的主要的属性方法


1. Object()

    // 首先,将Object作为构造函数调用和对象字面量直接定义是等价的
    var o = {};
    var o2 = new Object();
    // 注意这里所说的等价不是指相等,是指其本身和原型继承相同
    
    // 当然也可以
    var a = {};
    var a2 = new Object(a);
    console.log(a===a2);            // true

Object本身作为工具方法

    // 返回一个Object构造器实例
    var obj = Object();
    console.log(obj instanceof Object);            // true
    
    // 返回一个字符串构造器实例
    var str = Object("string");
    console.log(str instanceof Object);            // true     等价    new String("string")
    
    // 返回一个数字构造器实例
    var num = Object(123);
    console.log(num instanceof Object);            // true        等价    new Number(123)
    
    // 返回一个布尔构造器实例
    var boo = Object(true);                        // 等价    new Boolean(true)
    var boo2 = Object(false);                    
    console.log(boo instanceof Object && boo2 instanceof Object);    // true
    
    // null存在的意义在于对象引用之中,null值最初含义为:没有引用任何对象
    // null型只能取null一个值,null值是一个字面量,但是对null进行typeof结果为对象
    console.log(typeof null);                            // object
    console.log(Object(null) instanceof Object);        // true
    // 对null调用Object方法,返回一个空对象
    
    
    // undefined型也只能取undefined一个值,对undefined进行typeof ,值为undefined
    console.log(typeof undefined);                        // undefined
    console.log(Object(undefined) instanceof Object);    // true
    // 也是返回一个空对象

Object本身当作工具方法使用时,可以将任意值转为对象。这个方法常用于保证某个值一定是对象。如果参数是原始类型的值,Object方法返回对应的包装对象的实例

Object()传入参数为基本类型值,则返回值为其类型的构造函数的实例。

上面探讨的是基础类型值,那如果是引用类型值呢?


    var arr = [1,2,3];        
    console.log(Object(arr));            // 把原对象返回了
    console.log(Object(arr)===arr);        // true
    
    var fn = function () {};            // 把原函数返回了
    console.log(Object(fn));            // function () {}
    console.log(Object(fn)===fn);        // true
    
    var obj = {x:"obj.x"};
    console.log(Object(obj));            // [object Object]
    console.log(Object(obj)===obj);        // true
    
    // 一个判断是否是对象的函数
    function judgeObj(obj) {
        return Object(obj)===obj? true : false;
    }
    
    console.log(judgeObj([]));            // true
    console.log(judgeObj(true));        // false
    console.log(judgeObj({}));            // true
    console.log(judgeObj(123));            // false

Object()传入的参数是引用类型值,则会返回原对象;


2. Object.keys(obj)

Object.keys() 方法会返回一个由一个给定对象的自身可枚举属性组成的数组,数组中属性名的排列顺序和使用 for...in 循环遍历该对象时返回的顺序一致 (两者的主要区别是 一个 for-in 循环还会枚举其原型链上的属性)。

Enumerable条件限制,且不可枚举原型链中的属性

    // 无法枚举到原型链中的属性
    var obj = Object.create({y:20});
    obj.x = 10;
    console.log(Object.keys(obj));        // "x"
    
    // 无法枚举Enumerable为false属性
    Object.defineProperty(obj,"z",{
        value:"z",
        enumerable:false
    })
    console.log(Object.keys(obj));        // "x"
        
    // 对于数组对象
    var arr = ["a","b","c"];
    console.log(Object.keys(arr));        // "0,1,2"
    
    // 对于随机排列的数组对象
    var obj_ramdom = {100:"a",2:"b",50:"c"};
    console.log(Object.keys(obj_ramdom));        // "2,50,100"

详细说明:MDN —— Object.keys()


3. Object.getOwnPropertyNames(obj)

Object.getOwnPropertyNames 返回一个数组,该数组对元素是 obj 自身拥有的枚举或不可枚举属性名称字符串。 数组中枚举属性的顺序与通过 for...in 循环(或 Object.keys)迭代该对象属性时一致。 数组中不可枚举属性的顺序未定义。

不受Enumerable条件限制,但不可枚举原型链中属性

如果你只要获取到可枚举属性,查看 Object.keys 或用 for...in循环(还会获取到原型链上的可枚举属性,不过可以使用hasOwnProperty()方法过滤掉)。

    // 无法枚举到原型链中的属性
    var obj = Object.create({y:20});
    obj.x = 10;
    console.log(
        Object.getOwnPropertyNames(obj)
    );                                    // "x"
    
    // 可以枚举Enumerable为false的属性
    Object.defineProperty(obj,"z",{
        value:"z",
        enumerable:false
    })
    console.log(
        Object.getOwnPropertyNames(obj)
    );                                    // "x,z"
        
    // 对于数组对象(length属性为不可枚举)
    var arr = ["a","b","c"];
    console.log(
        Object.getOwnPropertyNames(arr)
    );                                    // "0,1,2,length"
    
    // 对于随机排列的数组对象
    var obj_ramdom = {100:"a",2:"b",50:"c"};
    console.log(
        Object.getOwnPropertyNames(obj_ramdom)
    );                                    // "2,50,100"

详细:MDN —— Object.getOwnPropertyNames()


for-inObject.keysObject.getOwnPropertyNames特点区分

三者关于是否受Enumerable的限制测试

    
    var obj = {x:10,y:20};
    Object.defineProperty(obj,"z",{
        value:30,
        enumerable:false,
    });
    
    // for-in
    for (var a in obj) {
        console.log(a);                     // "x,y"
    }
    
    // Object.keys
    console.log(
        Object.keys(obj)                    // "x,y"
    );
    
    // Object.getOwnPropertyNames()
    console.log(
        Object.getOwnPropertyNames(obj)     // "x,y,z"
    );

三者关于是否可以枚举原型链的测试


    function Test() {
        this.x = 10;
        this.y = 20;
    }
    Test.prototype.z = 30;        // z为原型链属性
    var obj = new Test();
    
    
    // for-in
    for (var a in obj) {
        console.log(a)                         // "x,y,z"
    }
    
    // Object-keys
    console.log(
        Object.keys(obj)                       // "x,y"
    )

    
    // Object.getOwnPropertyNames()
    console.log(
        Object.getOwnPropertyNames(obj)        // "x,y"
    )

图片描述


我们如何记忆呢?就记最特殊的!

for-in:只有它可以枚举原型链里的属性,并且它也不是Object对象的方法

Object.getOwnPropertyNames():只有它可以享有Enumerable的"豁免权",不管如何设置只要是这个对象上的自有属性都可以枚举到!


对象属性控制相关方法

四个相关的方法在这里先列出,这里要要提到数据属性和访问器属性


4. Object.defineProperty()

Object.defineProperty() 方法会直接在一个对象上定义一个新属性,或者修改一个对象的现有属性, 并返回这个对象。

5. Object.getOwnPropertyDescriptor()

Object.getOwnPropertyDescriptor() 返回指定对象上一个自有属性对应的属性描述符。(自有属性指的是直接赋予该对象的属性,不需要从原型链上进行查找的属性)

    // 采用Object.defineProperty定义的属性,如果不显示定义
    // enumerable,configurable,writable值默认为false(与对象字面量相反)
    var obj = {};
    Object.defineProperty(obj,"x",{
        value:"obj.x"
    });
    
    
    // 使用Object.getOwnPropertyDescriptor()获取属性对象
    var obj_attr = Object.getOwnPropertyDescriptor(obj,"x");
    for (var i in obj_attr) {
        document.write(i+" : "+obj_attr[i]+"<br />")
    }
    // 默认下数据属性都是false

6. Object.defineProperties()

Object.defineProperties() 方法直接在一个对象上定义新的属性或修改现有属性,并返回该对象。

    var obj = {};
    Object.defineProperties(obj,{
        x:{
            value:"obj.x",
            writable:true,
            enumerable:true,
            configurable:true
        },
        y:{
            value:"obj.y",
            writable:true,
            enumerable:true,
            configurable:true
        },
        z:{
            value:"obj.z"
        }
    })
    
    console.log(Object.keys(obj));            // "x,y"    z属性enumerable默认为false
    // 当然,z属性的数据属性都是false

冲突:

《JavaScript编程全解》:只要将get属性与set属性指定为相应的函数,就能够定义一个只能够通过访问器gettersetter来访问值的属性。访问器与value属性是互相排斥的,也就是说,如果指定了value属性的值,访问器(包括getset)就会失效;反之,如果指定了访问器(getset中的某一个亦或是都存在),value属性就会失效。

《JS高程3》:不一定非要同时指定getter和setter。只指定getter意味着属性是不能写,尝试写入属性会被忽略。在严格模式下,尝试写入只指定了getter函数的的属性会抛出错误。类似地,没有指定setter函数的属性也不能读,否则在非严格模式下会返回undefined,在严格模式下会抛出错误。

    var obj = {_x:10};
    
    // 定义一个访问器属性
    Object.defineProperty(obj,"x",{
        get:function () {
            return this._x
        }
    })
    // 读取obj.x会隐式调用访问器属性,返回obj._x的值(下划线代表此属性只能通过访问器读写)
    console.log(obj.x);            // 10
    
    // 尝试为访问器属性赋值
    // 直接赋值
    obj.x = "aaa";
    console.log(obj.x);            // 10     赋值失败
    
    // 获取obj.x的attributes
    var objxAttr = Object.getOwnPropertyDescriptor(obj,"x");
    for (var i in objxAttr) {
        document.write(
            i+" | "+objxAttr[i]+"<br />"
        )
    }
    // get | function () { return this._x }
    // set | undefined
    // enumerable | false
    // configurable | false
    
    // 不可写的原因是value属性与访问器属性冲突,即(get、set)与value属性冲突
    
    // 可以通过查看attributes属性,判断属性是否是访问器属性还是数据属性,存在set或者get的是访问器属性

具体内容请移步至相关知识点进行更深入学习,这里只介绍方法基础用法


对象状态相关方法

Object.preventExtensions()

如果一个对象可以添加新的属性,则这个对象是可扩展的。preventExtensions 可以让这个对象变的不可扩展,也就是不能再有新的属性。需要注意的是不可扩展的对象的属性通常仍然可以被删除。尝试给一个不可扩展对象添加新属性的操作将会失败,不过可能是静默失败,也可能会抛出 TypeError 异常(严格模式)。

Object.preventExtensions 只能阻止一个对象不能再添加新的自身属性,仍然可以为该对象的原型添加属性。然而Object.preventExtensions会阻止一个对象将__proto__属性重新指向另一个对象。

    // Object.preventExtensions将原对象变的不可扩展,并且返回原对象
    var obj = {};
    var obj2 = Object.preventExtensions(obj);
    alert(obj===obj2);            // true
    obj.x = "obj.x";
    alert(obj.x);                // undefined
    
    // 采用对象字面量定义的对象默认可扩展
    var o = {};
    alert(Object.isExtensible(o));            // true
    // 当然,通过调用方法可以阻止
    Object.preventExtensions(o);
    alert(Object.isExtensible(o));            // false
    
    // 使用Object.defineProperty方法为一个不可扩展的对象添加新属性会抛出异常.
    var o2 = {a:"a"};
    Object.preventExtensions(o2);
    Object.defineProperty(o2,"b",{
        value:"test"            
    })
    // "Uncaught TypeError: Cannot define property:b, object is not extensible."
    
    
    // 一个不可扩展对象的原型是不可更改的,__proto__是个非标准魔法属性,可以更改一个对象的原型.
    var b = Object.preventExtensions({x:1,y:2});
    b.__proto__ = {a:10,b:20};            //  "Uncaught TypeError: #<Object> is not extensible" 

详细:MDN —— Object.preventExtensions()


Object.seal()

通常情况下,一个对象是可扩展的(可以添加新的属性)。密封一个对象会让这个对象变的不能添加新属性,且所有已有属性会变的不可配置。属性不可配置的效果就是属性变的不可删除,以及一个数据属性不能被重新定义成为访问器属性,或者反之。但属性的值仍然可以修改。尝试删除一个密封对象的属性或者将某个密封对象的属性从数据属性转换成访问器属性,结果会静默失败或抛出TypeError 异常(严格模式)。

不会影响从原型链上继承的属性。但 _proto_ ( ) 属性的值也会不能修改。

    // 默认可以修改属性,添加属性
    var obj = {
        a:"a",
        b:"b"
    };
    
    // 密封对象Object.seal(),注意方法会返回原对象
    obj = Object.seal(obj);
    console.log(Object.isSealed(obj));            // true
    
    // 依然可以修改属性上的值
    obj.a = "Rewrite obj.a";
    obj.b = "Rewrite obj.b";
    console.log(obj.a+" | "+obj.b);                //  "Rewrite obj.a | Rewrite obj.b"
    
    // 但是除此之外的操作都无法完成
    obj.z = "obj.z";
    console.log(obj.z);                            // undefined 新属性写入失败
    console.log(delete obj.a);                    // false 删除失败
    
    // 无法定义访问器属性
    Object.defineProperty(obj,"b",{                // "Uncaught TypeError: Cannot redefine property: b"
        get:function () {
            return this.b;
        }
    });
    // 方法也无法写入新属性
    Object.defineProperty(obj,"z",{                // 抛出TypeError异常
        value:"obj.z"
    });
    console.log(obj.z);        // "Uncaught TypeError: Cannot define property:z, object is not extensible."

Object.freeze()

Object.freeze() 方法可以冻结一个对象,冻结指的是不能向这个对象添加新的属性,不能修改其已有属性的值,不能删除已有属性,以及不能修改该对象已有属性的可枚举性、可配置性、可写性。也就是说,这个对象永远是不可变的。该方法返回被冻结的对象。

    // 默认可以修改属性,添加属性,删除属性等操作
    var obj = {
        a:"a",
        b:"b",
        o:{}
    };
    
    // 调用Object.freeze
    obj = Object.freeze(obj);
    
    // 现在任何对对象的操作都会失败,严格模式下会TypeError异常
    console.log(delete obj.a);                // false
    
    obj.z = "obj.z";
    console.log(obj.z);                        // undefined
    
    // 但是非冻结对象依然可以修改,对象内数组、对象等引用类型
    obj.o.fn = function () {console.log("yes")};
    obj.o.fn();                                // "yes"    添加成功

MDN提供了一个完全冻结对象的函数:

    obj = {
      internal : {}
    };
    
    Object.freeze(obj);
    obj.internal.a = "aValue";
    
    obj.internal.a // "aValue"
    
    // 想让一个对象变的完全冻结,冻结所有对象中的对象,我们可以使用下面的函数.
    
    function deepFreeze (o) {
      var prop, propKey;
      Object.freeze(o); // 首先冻结第一层对象.
      for (propKey in o) {
        prop = o[propKey];        
        if (!o.hasOwnProperty(propKey) || !(typeof prop === "object") || Object.isFrozen(prop)) {
        // 跳过原型链上的属性和已冻结的对象.
          continue;
        }
    
        deepFreeze(prop); //递归调用.
      }
    }
    
    obj2 = {
      internal : {}
    };
    
    deepFreeze(obj2);
    obj2.internal.a = "anotherValue";
    obj2.internal.a; // undefined

Object.isExtensible()、Object.isSealed()、Object.isFrozen()

为对应的检测方法:

严格程度升序:preventExtensions —— seal —— freeze

图片描述

链接:


  • Object.isExtensible():

默认情况下,对象是可扩展的:即可以为他们添加新的属性。以及它们的 proto 属性可以被更改。Object.preventExtensions,Object.seal 或 Object.freeze 方法都可以标记一个对象为不可扩展(non-extensible)。


  • Object.isSealed()

    // 新建对象默认不可密封
    var obj = {};
    console.log(Object.isSealed(obj));            // false
    
    // 如果是空对象变为不可扩展preventExtensions,则对象也会变成密封对象
    obj = Object.preventExtensions(obj);
    console.log(
        Object.isExtensible(obj)+" | " +Object.isSealed(obj)
    )                                            // false | true        不可扩展  | 密封
    
    // 但不是空对象,则不会发生上面情况,记住:密封对象与Configurable属性相关联
    var obj2 = {x:"obj2.x"};
    Object.preventExtensions(obj2);
    console.log(
        Object.isExtensible(obj2)+" | " +Object.isSealed(obj2)
    )                                            // false | false    不可扩展  | 不密封
    
    // 反过来设置configurable设置为false,则自动变为密封对象
    var o = {a:"o.a"};
    Object.preventExtensions(o);
    Object.defineProperty(o,"a",{
        configurable:false
    });
    console.log(
        Object.isSealed(o)
    );                                            // true
    
    // 直接生成一个密封对象
    var obj_seal = {};
    Object.seal(obj_seal);
    
    // 当然密封对象也可以是冻结对象
    Object.isFrozen(obj_seal);                    // true
    var o2 = Object.seal({a:"o2.a"});
    console.log(Object.isFrozen(o2));            // false    依旧可更改o2.a属性

  • Object.isFrozen()

一个对象是冻结的(frozen)是指它不可扩展,所有属性都是不可配置的(non-configurable),且所有数据属性(data properties)都是不可写的(non-writable)

    // 一个对象默认是可扩展的,所以它也是非冻结的.
    assert(Object.isFrozen({}) === false);
    
    // 一个不可扩展的空对象同时也是一个冻结对象.
    var vacuouslyFrozen = Object.preventExtensions({});
    assert(Object.isFrozen(vacuouslyFrozen) === true);
    
    // 一个非空对象默认也是非冻结的.
    var oneProp = { p: 42 };
    assert(Object.isFrozen(oneProp) === false);
    
    // 让这个对象变的不可扩展,并不意味着这个对象变成了冻结对象,
    // 因为p属性仍然是可以配置的(而且可写的).
    Object.preventExtensions(oneProp);
    assert(Object.isFrozen(oneProp) === false);
    
    // ...如果删除了这个属性,则它会成为一个冻结对象.
    delete oneProp.p;
    assert(Object.isFrozen(oneProp) === true);
    
    // 一个不可扩展的对象,拥有一个不可写但可配置的属性,则它仍然是非冻结的.
    var nonWritable = { e: "plep" };
    Object.preventExtensions(nonWritable);
    Object.defineProperty(nonWritable, "e", { writable: false }); // 变得不可写
    assert(Object.isFrozen(nonWritable) === false);
    
    // 把这个属性改为不可配置,会让这个对象成为冻结对象.
    Object.defineProperty(nonWritable, "e", { configurable: false }); // 变得不可配置
    assert(Object.isFrozen(nonWritable) === true);
    
    // 一个不可扩展的对象,拥有一个不可配置但可写的属性,则它仍然是非冻结的.
    var nonConfigurable = { release: "the kraken!" };
    Object.preventExtensions(nonConfigurable);
    Object.defineProperty(nonConfigurable, "release", { configurable: false });
    assert(Object.isFrozen(nonConfigurable) === false);
    
    // 把这个属性改为不可写,会让这个对象成为冻结对象.
    Object.defineProperty(nonConfigurable, "release", { writable: false });
    assert(Object.isFrozen(nonConfigurable) === true);
    
    // 一个不可扩展的对象,值拥有一个访问器属性,则它仍然是非冻结的.
    var accessor = { get food() { return "yum"; } };
    Object.preventExtensions(accessor);
    assert(Object.isFrozen(accessor) === false);
    
    // ...但把这个属性改为不可配置,会让这个对象成为冻结对象.
    Object.defineProperty(accessor, "food", { configurable: false });
    assert(Object.isFrozen(accessor) === true);
    
    // 使用Object.freeze是冻结一个对象最方便的方法.
    var frozen = { 1: 81 };
    assert(Object.isFrozen(frozen) === false);
    Object.freeze(frozen);
    assert(Object.isFrozen(frozen) === true);
    
    // 一个冻结对象也是一个密封对象.
    assert(Object.isSealed(frozen) === true);
    
    // 当然,更是一个不可扩展的对象.
    assert(Object.isExtensible(frozen) === false);        

Object.getPrototypeOf()

给定对象的原型。如果没有继承属性,则返回 null 。

    var obj = {};
    console.log(Object.getPrototypeOf(obj) === Object.prototype);        // true

    var fn = function () {};
    console.log(Object.getPrototypeOf(fn) === Function.prototype);        // true
    
    var arr = [];
    console.log(Object.getPrototypeOf(arr) === Array.prototype);        // true
    
    var q = {x:"x"};
    var p = Object.create(q);
    console.log(Object.getPrototypeOf(p) === q);                        // true
    
    // 如果参数不是引用类型,将抛出异常
    var num = 123;
    Object.getPrototypeOf(num);
    // "Uncaught TypeError: Object.getPrototypeOf called on non-object"

Object实例方法

Object.prototype.valueOf()

JavaScript 调用 valueOf() 方法用来把对象转换成原始类型的值(数值、字符串和布尔值)。 你很少需要自己调用此函数;当遇到一种需要转换成一个原始值情况时候, JavaScript 会自动调用此函数。

默认情况下, valueOf() 会被每个对象Object继承。每一个内置对象都会覆盖这个方法为了返回一个合理的值,如果对象没有原始值,valueOf() 就会返回对象自身。

你可以在自己的代码中使用 valueOf 方法用来把内置对象的值转换成原始值。 当你创建了自定义对象时,你可以覆盖 Object.prototype.valueOf() 并调用来取代 Object 方法。

JavaScript的许多内置对象都重写了该函数,以实现更适合自身的功能需要。因此,不同类型对象的valueOf()方法的返回值和返回值类型均可能不同。
图片描述

    // Array:返回数组本身
    var arr = [1,2,3,"Array"];
    console.log(arr+" | "+(arr.valueOf() === arr));            //    "1,2,3,Array | true"    
    
    // String:返回当前字符串
    var str = "string";
    console.log(str.valueOf() === str);                        // true
    
    // Number:返回当前值
    var num = 123;
    console.log(num.valueOf() === num);                        // true
    
    // Boolean:返回当前布尔值
    var boo = true;                                            // 布尔值
    console.log(boo.valueOf() === boo);                        // true
    // 这里是布尔对象
    var boo2 = new Boolean(false);                            // 布尔对象
    console.log(boo2.valueOf());                            // false
    console.log(typeof boo2.valueOf());                        // boolean
    // 注意:这里对布尔对象操作,返回的是原值的boolean类型,而不在是引用类型
    
    // Date:从1970年1月1日到现在的毫秒数
    var date = new Date();
    console.log(date.valueOf());                            // "1497789410938"
    
    // function: 返回当前函数
    var fn = function () {console.log("fn")};
    (fn.valueOf())();                                        // fn
    
    // Object: 返回对象本身
    var obj = {x:"obj.a"};
    console.log(obj.valueOf() === obj);                        // true                            

当然也可以覆盖方法:

    var obj = {a:1};
    obj.valueOf = function () {return this.a}
    
    console.log(obj+1);            // 2
    // 这里隐式调用了valueOf方法

Object.prototype.toString()

每个对象都有一个 toString() 方法,当对象被表示为文本值时或者当以期望字符串的方式引用对象时,该方法被自动调用。默认情况下,toString() 方法被每个继承自Object的对象继承。如果此方法在自定义对象中未被覆盖,toString() 返回 "[object type]",其中type是对象类型。

    // toString返回对象的字符串形式,默认情况下返回类型字符串
    var o1 = new Object();
    var o2 = {a:1};
    console.log(o1.toString());
    console.log(o2.toString());
    // "[object Object]"
    
    // 当然可以自定义它
    var obj = {};
    obj.toString = function () {return 1}
    console.log(2+obj);                    // 3

关于toString()更详细的可以看这里:

阮一峰 toString()的应用:判断数据类型


Object.prototype.toLocaleString()

Object's toLocaleString 返回调用 toString() 方法的结果。

    var num = 123;
    console.log(num.toString() === num.toLocaleString());            // true
    
    var obj = {};
    console.log(obj.toString() === obj.toLocaleString());            // true

Object.prototype.hasOwnProperty()

所有继承了 Object 的对象都会继承到 hasOwnProperty 方法。这个方法可以用来检测一个对象是否含有特定的自身属性;和 in 运算符不同,该方法会忽略掉那些从原型链上继承到的属性。

    // 判断属性书否存在
    var obj = {x:"obj.x"};        
    console.log(obj.hasOwnProperty("x"));            // true                
    delete obj.x;
    console.log(obj.hasOwnProperty("x"));            // false                
    
    // 判断自身属性还是继承属性
    var p = {z:10};
    var o = Object.create(p);
    o.a = 20;        
    console.log(o.hasOwnProperty("a")+" | "+o.hasOwnProperty("z"));                
    // true | false
    
    console.log(o.hasOwnProperty("toString"));            // false
    console.log(o.hasOwnProperty("hasOwnProperty"));    // false
    
    // 遍历一个对象的自身属性
    var o1 = {z:"o1.z"};
    var o2 = Object.create(o1);
    o2.x = "o2.x";
    o2.y = "o2.y";
    
    for (var i in o2) {
        if (o2.hasOwnProperty(i)) {
            console.log("自身属性:"+i+" | "+"value:"+(o2[i]));
        } else {
            console.log(i+"不是自身属性")
        }
    }
    // "自身属性:x | value:o2.x"
    // "自身属性:y | value:o2.y"
    // "z不是自身属性"

hasOwnProperty也可以重写,所以需要注意这一点:

    var foo = {
        hasOwnProperty: function() {
            return false;
        },
        bar: 'Here be dragons'
    };
    
    foo.hasOwnProperty('bar'); // 始终返回 false
    
    // 如果担心这种情况,可以直接使用原型链上真正的 hasOwnProperty 方法
    ({}).hasOwnProperty.call(foo, 'bar'); // true
    
    // 也可以使用 Object 原型上的 hasOwnProperty 属性
    Object.prototype.hasOwnProperty.call(foo, 'bar'); // true
    

Object.prototype.isPrototypeOf()

isPrototypeOf 方法允许你检查一个对象是否存在于另一个对象的原型链上。

      function fn1() {
        this.a = "a";
    }
    function fn2() {
        this.b = "b";
    }
    
    fn2.prototype = new fn1();
    
    function fn3() {
        this.c = "c";
    }
    
    fn3.prototype = new fn2();
    
    function fn4() {
        this.d = "d";
    }
    
    fn4.prototype = new fn3();
    
    var test = new fn4();

    console.log(
        test.hasOwnProperty("a")+ " | "+test.hasOwnProperty("b")+" | "+test.hasOwnProperty("c")+" | "+test.hasOwnProperty("d")
    )
    // "false | false | false | true"

Object.prototype.propertyIsEnumerable()

每个对象都有 propertyIsEnumerable 方法。该方法可以判断出指定对象里的属性是否可枚举,也就是说该属性是否可以通过 for...in 循环等遍历到,不过有些属性虽然可以通过 for...in 循环遍历到,但因为它们不是自身属性,而是从原型链上继承的属性,所以该方法也会返回false。如果对象没有指定的属性,该方法返回 false。

MDN:Object.prototype.propertyIsEnumerable()



Queen
139 声望20 粉丝