zoukankan      html  css  js  c++  java
  • 红宝书4-第八章对象、类与面向对象编程(4)


    原型层级

    在通过对象访问属性时,会按照这个属性的名称开始搜索。现在这个对象上找,没有再去找原型,返回他的值。
    在这里插入图片描述
    虽然可以通过实例读取原型对象上的值,但不可能通过实例重写这些值。如果在实例上添加了一个 与原型对象中同名的属性,那就会在实例上创建这个属性,这个属性会遮住原型对象上的属性。

    只要给对象实例添加一个属性,这个属性就会遮蔽(shadow)原型对象上的同名属性,也就是虽然 不会修改它,但会屏蔽对它的访问。即使在实例上把这个属性设置为 null,也不会恢复它和原型的联 系。不过,使用 delete 操作符可以完全删除实例上的这个属性,从而让标识符解析过程能够继续搜索 原型对象。

    function Person() {} 
     
    Person.prototype.name = "Nicholas"; 
    Person.prototype.age = 29; 
    Person.prototype.job = "Software Engineer"; 
    Person.prototype.sayName = function() {   console.log(this.name);  }; 
     
    let person1 = new Person(); let person2 = new Person(); 
     
    person1.name = "Greg"; console.log(person1.name);  // "Greg",来自实例 console.log(person2.name);  // "Nicholas",来自原型 
     
    delete person1.name; console.log(person1.name);  // "Nicholas",来自原型 
    

    hasOwnProperty()方法用于确定某个属性是在实例上还是在原型对象上

    这个方法是继承自 Object 的,会在属性存在于调用它的对象实例上时返回 true

    function Person() {} 
    Person.prototype.name = "Nicholas"; 
    Person.prototype.age = 29; Person.prototype.job = "Software Engineer"; Person.prototype.sayName = function() {   console.log(this.name);  }; 
     
    let person1 = new Person(); let person2 = new Person(); console.log(person1.hasOwnProperty("name")); // false 
     
    person1.name = "Greg"; console.log(person1.name); // "Greg",来自实例 console.log(person1.hasOwnProperty("name")); // true 
     
    console.log(person2.name); // "Nicholas",来自原型 console.log(person2.hasOwnProperty("name")); // false 
     
    delete person1.name; console.log(person1.name); // "Nicholas",来自原型 console.log(person1.hasOwnProperty("name")); // false
    

    在这个例子中,通过调用 hasOwnProperty()能够清楚地看到访问的是实例属性还是原型属性。 调用 person1.hasOwnProperty("name")只在重写 person1 上 name 属性的情况下才返回 true,表 明此时 name 是一个实例属性,不是原型属性。
    在这里插入图片描述

    原型和 in 操作符

    in 操作符

    无论该属性是在实例上还是在原型上,返回 true。

    如果要确定某个属性是否存在于原型上,则可以像下 面这样同时使用 hasOwnProperty()和 in 操作符:

    function hasPrototypeProperty(object, name)
    {    
    return !object.hasOwnProperty(name) && (name in object); 
    }
    

    只要通过对象可以访问,in 操作符就返回 true,而 hasOwnProperty()只有属性存在于实例上 时才返回 true。因此,只要 in 操作符返回 true 且 hasOwnProperty()返回 false,就说明该属性 是一个原型属性。

    即便此时 原型对象还有 name 属性,但因为实例上的属性遮蔽了它,所以不会用到。

    for-in

    在 for-in 循环中使用 in 操作符时,可以通过对象访问且可以被枚举的属性都会返回,包括实例 属性和原型属性。遮蔽原型中不可枚举([[Enumerable]]特性被设置为 false)属性的实例属性也会 在 for-in 循环中返回,因为默认情况下开发者定义的属性都是可枚举的。

    Object.keys()

    这个方法接收一个对象作 为参数,返回包含该对象所有可枚举实例属性名称的字符串数组。
    这里,keys 变量保存的数组中包含"name"、"age"、"job"和"sayName"。这是正常情况下通过 for-in 返回的顺序。而在 Person 的实例上调用时,Object.keys()返回的数组中只包含"name"和 "age"两个属性。

    Object.getOwnPropertyNames()

    列出所有实例属性,无论是否可以枚举。

    let keys = Object.getOwnPropertyNames(Person.prototype); 
    console.log(keys);   // "[constructor,name,age,job,sayName]" 
    

    注意,返回的结果中包含了一个不可枚举的属性 constructor。Object.keys()和 Object. getOwnPropertyNames()在适当的时候都可用来代替 for-in 循环。

    Object.getOwnProperty- Symbols()

    在 ECMAScript 6新增符号类型之后,相应地出现了增加一个 Object.getOwnPropertyNames() 的兄弟方法的需求,因为以符号为键的属性没有名称的概念。因此,Object.getOwnProperty- Symbols()方法就出现了,这个方法与 Object.getOwnPropertyNames()类似,只是针对符号而已:

    let k1 = Symbol('k1'),     
    k2 = Symbol('k2');
    let o = {   [k1]: 'k1',   [k2]: 'k2' }; 
     
    console.log(Object.getOwnPropertySymbols(o)); // [Symbol(k1), Symbol(k2)]
    

    属性枚举顺序

    for-in 循环、Object.keys()Object.getOwnPropertyNames()Object.getOwnProperty- Symbols()以及 Object.assign()在属性枚举顺序方面有很大区别。for-in 循环和 Object.keys() 的枚举顺序是不确定的,取决于 JavaScript引擎,可能因浏览器而异。
    Object.getOwnPropertyNames()、Object.getOwnPropertySymbols()和 Object.assign() 的枚举顺序是确定性的。先以升序枚举数值键,然后以插入顺序枚举字符串和符号键。在对象字面量中 定义的键以它们逗号分隔的顺序插入。

    义的键以它们逗号分隔的顺序插入。 let k1 = Symbol('k1'),     k2 = Symbol('k2'); 
     
    let o = {   1: 1,   first: 'first',   [k1]: 'sym2',   second: 'second',   0: 0 }; 
     
    o[k2] = 'sym2'; o[3] = 3; o.third = 'third'; o[2] = 2; 
     
    console.log(Object.getOwnPropertyNames(o)); // ["0", "1", "2", "3", "first", "second", "third"] 
     
    console.log(Object.getOwnPropertySymbols(o)); // [Symbol(k1), Symbol(k2)]
    

        感谢您花时间阅读此篇文章,如果您觉得看了这篇文章之后心情还比较高兴,可以打赏一下,请博主喝上一杯咖啡,让博主继续码字……
        本文版权归作者和博客园共有,来源网址:https://blog.csdn.net/weixin_46498102 欢迎各位转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接
  • 相关阅读:
    大的FIbonacci数列_Java求法
    HDU1134_Game of Connections 卡特兰数
    oracle中查询锁表
    SpringBoot之使用Druid连接池以及SQL监控和spring监控
    用vue封装插件并发布到npm
    vue 预览 Excel 表格
    vue + elementUI 表格 底部 合计总数
    springboot项目中实现访问druid内置监控页面
    解决Elementui eltable合计 showsummary不显示,样式混乱问题
    Druid连接池:慢查询监控
  • 原文地址:https://www.cnblogs.com/jackson1/p/13804080.html
Copyright © 2011-2022 走看看