zoukankan      html  css  js  c++  java
  • 小tips:JS之for in、Object.keys()和Object.getOwnPropertyNames()的区别

    for..in循环

    使用for..in循环时,返回的是所有能够通过对象访问的、可枚举的属性,既包括存在于实例中的属性,也包括存在于原型中的实例。这里需要注意的是使用for-in返回的属性因各个浏览器厂商遵循的标准不一致导致对象属性遍历的顺序有可能不是当初构建时的顺序。

    虽然for..in主要用于遍历对象的属性,但同样也可以用来遍历数组元素。

    var arr = ['a', 'b', 'c', 'd'];
    
    // 使用for..in
    for (var i in arr) {
      console.log('索引:' + i + ',值:' + arr[i]);
    }
    
    // 使用for循环
    for (var j = 0; j < arr.length; j++) {
      console.log('索引:' + j + ',值:' + arr[j]);
    }
    
    /* 两种方式都输出:
     * ----------------
     * 索引:0,值:a
     * 索引:1,值:b
     * 索引:2,值:c
     * 索引:3,值:d
     * ----------------
     */

    如何查看一个属性的特性可以使用propertyIsEnumberable()Object.getOwnPropertyDescriptor()这两个方法。

    var colors = ['red', 'green', 'blue'];
    // 扩展Array.prototype
    Array.prototype.demo = function () {};
    
    for (var i in colors) {
      console.log(i); // 输出: 0 1 2 demo
    }
    
    // 查看原生的方法[[enumberable]]特征,这里以splice为例
    Array.prototype.propertyIsEnumerable('splice'); // false
    Object.getOwnPropertyDescriptor(Array.prototype, 'splice'); // {writable: true, enumerable: false, configurable: true}
    
    // 查看 demo 属性的特性
    Array.prototype.propertyIsEnumerable('demo'); // true
    Object.getOwnPropertyDescriptor(Array.prototype, 'demo'); // {writable: true, enumerable: true, configurable: true}

    从上面的示例代码中可以看出,我们添加的demo方法,默认是可以被for..in枚举出来的。如果想让其不被枚举,那么可以使用ES5的Object.defineProperty()来定义属性,此外如果浏览器版本不支持ES5的话,我们可以使用hasOwnProperty()方法在for..in代码块内将可枚举的属性过滤掉。

    var colors = ['red', 'green', 'blue'];
    Object.defineProperty(Array.prototype, 'demo', {
      enumerable: false,
      value: function() {}
    });
    
    Array.prototype.propertyIsEnumerable('demo'); // false
    Object.getOwnPropertyDescriptor(Array.prototype, 'demo'); // {writable: false, enumerable: false, configurable: false}
    
    for (var i in colors) {
      console.log(i); // 输出:0 1 2
    }
    
    // 或者使用 hasOwnProperty
    var colors = ['red', 'green', 'blue'];
    Array.prototype.demo = function() {};
    
    // 安全使用hasOwnProperty方法
    var hasOwn = Object.prototype.hasOwnProperty;
    for (var i in colors) {
      if (hasOwn.call(colors, i)) {
        console.log(i); // 输出:0 1 2
      }
    }

    Object.keys()

    Object.keys()用于获取对象自身所有的可枚举的属性值,但不包括原型中的属性,然后返回一个由属性名组成的数组。注意它同for..in一样不能保证属性按对象原来的顺序输出。

    // 遍历数组
    var colors = ['red', 'green', 'blue'];
    colors.length = 10;
    colors.push('yellow');
    Array.prototype.demo = function () {};
    
    Object.keys(colors); // 0 1 2 10
    
    // 遍历对象
    function Person(name, age) {
      this.name = name;
      this.age = age;
    }
    
    Person.prototype.demo = function() {};
    
    var jenemy = new Person('jenemy', 25);
    
    Object.keys(jenemy); // name age

    注意在 ES5 环境,如果传入的参数不是一个对象,而是一个字符串,那么它会报 TypeError。在 ES6 环境,如果传入的是一个非对象参数,内部会对参数作一次强制对象转换,如果转换不成功会抛出 TypeError。

    // 在 ES5 环境
    Object.keys('foo'); // TypeError: "foo" is not an object
    
    // 在 ES6 环境
    Object.keys('foo'); // ["0", "1", "2"]
    
    // 传入 null 对象
    Object.keys(null); // Uncaught TypeError: Cannot convert undefined or null to object
    
    // 传入 undefined
    Object.keys(undefined); // Uncaught TypeError: Cannot convert undefined or null to object

    由于Object.keys()为ES5上的方法,因此对于ES5以下的环境需要进行polyfill

    // From https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/keys
    if (!Object.keys) {
      Object.keys = (function() {
        'use strict';
        var hasOwn = Object.prototype.hasOwnProperty,
            hasDontEnumBug = !({ toString: null }).propertyIsEnumerable('toString'),
            dontEnums = [
              'toString',
              'toLocaleString',
              'valueOf',
              'hasOwnProperty',
              'isPrototypeOf',
              'propertyIsEnumerable',
              'constructor'
            ],
            dontEnumsLength = dontEnums.length;
    
          return function(obj) {
            if (typeof obj !== 'object' && (typeof obj !== 'function' || obj === null)) {
              throw new TypeError('Object.keys called on non-object');
            }
    
            var result = [], prop, i;
    
            for (prop in obj) {
              if (hasOwn.call(obj, prop)) {
                result.push(prop);
              }
            }
    
            if (hasDontEnumBug) {
              for (i = 0; i < dontEnumsLength; i++) {
                if (hasOwn.call(obj, dontEnums[i])) {
                  result.push(dontEnums[i]);
                }
              }
            }
            return result;
          }
      }) ();
    }

    Object.getOwnPropertyNames()

    Object.getOwnPropertyNames()方法返回对象的所有自身属性的属性名(包括不可枚举的属性)组成的数组,但不会获取原型链上的属性。

    function A(a,aa) {
      this.a = a;
      this.aa = aa;
      this.getA = function() {
        return this.a;
      }
    }
    // 原型方法
    A.prototype.aaa = function () {};
    
    var B = new A('b', 'bb');
    B.myMethodA = function() {};
    // 不可枚举方法
    Object.defineProperty(B, 'myMethodB', {
      enumerable: false,
      value: function() {}
    });
    
    Object.getOwnPropertyNames(B); // ["a", "aa", "getA", "myMethodA", "myMethodB"]

    参考地址:https://www.cnblogs.com/wujie520303/p/4931384.html

  • 相关阅读:
    表单序列化
    创建.ignore文件
    头条数学救火队长马丁的一道中山大学研究生入学考试数学分析题
    实数理论
    方法
    目标
    闭区间有限覆盖定理
    零值定理的确界原理证明方法,来自百度
    各种范例
    零值定理
  • 原文地址:https://www.cnblogs.com/moqiutao/p/8657040.html
Copyright © 2011-2022 走看看