• 读《JavaScript权威指南》笔记(三)--对象


    1.对象介绍

    对象是JavaScript的基本数据类型。对象是一种复合值:它将很多值(原始值或者其他对象)聚合在一起,可通过名字访问这些值。对象也可看做是属性的无序集合,每个属性都是一个名/值对。属性名是字符串,因此我们可以把对象看成是从字符串到值的映射。
    由于JavaScript是弱类型语言,因此不必遵循这条规定,在任何对象中程序都可以创建任意数量的属性。除了字符串、数字、true、false、null和undefined之外,JavaScript中的值都是对象。

    2.对象属性的操作

    1)对象对于点(.)来说,右侧必须是一个以属性名称命名的简单标识符。对于方括号来说([]),方括号内必须是一个计算结果为字符串的表达式,这个字符串就是属性的名字

    2)使用方括号和一个字符串,看起来更像数组,只是这个数组元素是通过字符串索引而不是数字索引。这种数组就是我们所说的关联数组,也称做散列、映射或字典JavaScript对象都是关联数组

    3)由于在写程序的时候不知道属性名称,因此无法通过点运算符(.)来访问对象portfolio的属性。但可以使用[]运算符,因为它使用字符串值(字符串值是动态的,可以在运行时更改)而不是标识符(标识符是静态的,必须写死在程序中)作为索引对属性进行访问。

    4)delete运算符只能删除自有属性,不能删除继承属性

    5)在这些场景下给对象o设置属性p会失败:

    • o中的属性p是只读的:不能给只读属性重新赋值(defineProperty()方法中有一个例外,可以对可配置的只读属性重新赋值)。
    • o中的属性p是继承属性,且它是只读的:不能通过同名自有属性覆盖只读的继承属性。
    • o中不存在自有属性p:o没有使用setter方法继承属性p,并且o的可扩展性(extensible attribute)是false(参照6.8.3节)。如果o中不存在p,而且没有setter方法可供调用,则p一定会添加至o中。但如果o不是可扩展的,那么在o中不能定义新属性。

    6)属性赋值要么失败,要么创建一个属性,要么在原始对象中设置属性,但有一个例外,如果o继承自属性x,而这个属性是一个具有setter方法的accessor属性,那么这时将调用setter方法而不是给o创建一个属性x。需要注意的是,setter方法是由对象o调用的,而不是定义这个属性的原型对象调用的。因此如果setter方法定义任意属性,这个操作只是针对o本身,并不会修改原型链。

    var unitcircle = { r:1 };      // 一个用来继承的对象
    var c = inherit(unitcircle); // c继承属性r
    c.x = 1; c.y = 1;              // c定义两个属性
    c.r = 2;                       // c覆盖继承来的属性
    unitcircle.r;                  // => 1,原型对象没有修改

    3.对象的继承

    假设要查询对象o的属性x,如果o中不存在x,那么将会继续在o的原型对象中查询属性x。如果原型对象中也没有x,但这个原型对象也有原型,那么继续在这个原型对象的原型上执行查询,直到找到x或者查找到一个原型是null的对象为止。可以看到,对象的原型属性构成了一个“链”,通过这个“链”可以实现属性的继承。

    现在假设给对象o的属性x赋值,如果o中已经有属性x(这个属性不是继承来的),那么这个赋值操作只改变这个已有属性x的值。如果o中不存在属性x,那么赋值操作给o添加一个新属性x。如果之前o继承自属性x,那么这个继承的属性就被新创建的同名属性覆盖了。属性赋值操作首先检查原型链,以此判定是否允许赋值操作。例如,如果o继承自一个只读属性x,那么赋值操作是不允许的。如果允许属性赋值操作,它也总是在原始对象上创建属性或对已有的属性赋值,而不会去修改原型链。在JavaScript中,只有在查询属性时才会体会到继承的存在,而设置属性则和继承无关,这是JavaScript的一个重要特性,该特性让程序员可以有选择地覆盖(override)继承的属性。

    4.循环对象

    • for/in循环对象的可枚举的属性,包括自身和继承的属性;
    • Object.keys()它返回一个数组,这个数组由对象中可枚举的自有属性的名称组成;
    • Object.getOwnPropertyNames(),它和Ojbect.keys()类似,只是它返回对象的所有自有属性的名称,而不仅仅是可枚举的属性

    5.判断某个属性是否存在于某个对象中

    判断某个属性是否存在于某个对象中。可以通过in运算符、hasOwnPreperty()和propertyIsEnumerable()方法来完成这个工作,甚至仅通过属性查询也可以做到这一点。

    1)in运算符的左侧是属性名(字符串),右侧是对象。如果对象的自有属性或继承属性中包含这个属性则返回true:

    var o = { x: 1 }
    "x" in o;             // true:"x"是o的属性
    "y" in o;             // false:"y"不是o的属性
    "toString" in o;      // true:o继承toString属性

    2)对象的hasOwnProperty()方法用来检测给定的名字是否是对象的自有属性。对于继承属性它将返回false:

    var o = { x: 1 }
    o.hasOwnProperty("x"); // true:o有一个自有属性x
    o.hasOwnProperty("y"); // false:o中不存在属性y
    o.hasOwnProperty("toString"); // false:toString是继承属性

    3)propertyIsEnumerable()是hasOwnProperty()的增强版,只有检测到是自有属性且这个属性的可枚举性(enumerable attribute)为true时它才返回true。某些内置属性是不可枚举的。通常由JavaScript代码创建的属性都是可枚举的

    4)另一种更简便的方法是使用“!==”判断一个属性是否是undefined

    var o = { x: 1 }
    o.x !== undefined; //true: o中有属性x
    o.y !== undefined; // false: o中没有属性y
    o.toString !== undefined; //true: o继承了toString属性

    6.getter和setter

    当程序查询存取器属性的值时,JavaScript调用getter方法(无参数)。这个方法的返回值就是属性存取表达式的值。当程序设置一个存取器属性的值时,JavaScript调用setter方法,将赋值表达式右侧的值当做参数传入setter。从某种意义上讲,这个方法负责“设置”属性值。可以忽略setter方法的返回值。

    我们将存取器属性的getter和setter方法看成是属性的特性。按照这个逻辑,我们也可以把数据属性的值同样看做属性的特性。因此,可以认为一个属性包含一个名字和4个特性。数据属性的4个特性分别是它的值(value)、可写性(writable)、可枚举性(enumerable)和可配置性(configurable)。存取器属性不具有值(value)特性和可写性,它们的可写性是由setter方法存在与否决定的。因此存取器属性的4个特性是读取(get)、写入(set)、可枚举性和可配置性。

    var o = {
        // 普通的数据属性
        data_prop: value,
    
        // 存取器属性都是成对定义的函数
        get accessor_prop(){ /*这里是函数体 */ },
        set accessor_prop(value){ /* 这里是函数体*/ }
    };

     7. 其他

    01 isPrototypeOf() 检测一个对象是否是另一个对象的原型(或处于原型中)

    object1.isPrototypeOf(object2);
    判断指定对象object1是否存在于另一个对象object2的原型链中

    var a = {b : 1};
    Object.prototype.isPrototypeOf(a) // true

    02 hasOwnProperty()方法用来检测给定的名字是否是对象的自有属性

    03 propertyIsEnumerable()检测到是自有属性且这个属性的可枚举性

    04 toString()讲对象转成字符串,没有参数,返回"[object Object]"

    05 valueOf() 讲对象转成某种原始值而非字符串

    06 Object.getPropertyOf(obj)是用来得到obj对象的原型对象的标准方法

    07 Object.create()创建对象

    08  Object.keys()它返回一个数组,这个数组由对象中可枚举的自有属性的名称组成;

    09  Object.values()它返回一个数组,这个数组由对象中可枚举的自有属性的值组成;

    10 Object.entries()返回一个数组,成员是参数对象可枚举的自有属性的键值对数组。

    var a = {b: 1, bb: 2}
    Object.entries(a) // [["b", 1],["bb", 2]]

    11 Object.assign()用于将所有可枚举属性的值从一个或多个源对象复制到目标对象。它将返回目标对象。

    var a = {b: 1};
    Object.assign(a, {bb: 2}, {bbb: 3}) // {b: 1, bb: 2, bbb: 3}

    12 Object.getOwnPropertyNames(),它和Ojbect.keys()类似,只是它返回对象的所有自有属性的名称,而不仅仅是可枚举的属性

    13 Object.getOwnPropertyDescriptors()返回某个对象属性的描述对象; 

    var a = {b: 1};
    Object.getOwnPropertyDescriptors(a)
    // b: {value: 1, writable: true, enumerable: true, configurable: true}

    14 Object.defineProperty(obj, prop, descriptor) 会直接在一个对象上定义一个新属性,或者修改一个对象的现有属性, 并返回这个对象。如果不指定configurable, writable, enumerable ,则这些属性默认值为false,如果不指定value, get, set,则这些属性默认值为undefined

    var obj = {};
    Object.defineProperty(obj, 'name', {
        configurable: false,
        writable: true,
        enumerable: true,
        value: '张三'
    })

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

    16 Object.is()是用来比较两个值是否严格相等的方法,与===的行为基本一致,与===的区别:01 Object.is(+0, -0) // false; 02 Object.is(NaN, NaN) // true

    17 Object.preventExtensions() 让一个对象变的不可扩展,也就是永远不能再添加新的属性。Object.isExtensible()判断一个对象是否是可扩展

    18 Object.seal() 让一个对象密封,并返回被密封后的对象。密封对象是指那些不能添加新的属性,不能删除已有属性,以及不能修改已有属性的可枚举性、可配置性、可写性,但可能可以修改已有属性的值的对象。Object.isSealed() 判断一个对象是否是密封的

    19 Object.freeze()冻结一个对象并返回被冻结的对象。冻结对象是指那些不能添加新的属性,不能修改已有属性的值,不能删除已有属性,以及不能修改已有属性的可枚举性、可配置性、可写性的对象。也就是说,这个对象永远是不可变的。Object.isFrozen()判断一个对象是否被冻结

  • 相关阅读:
    消息模型:主题和队列的区别
    Navicat12 无限试用(Windows64、Linux、Mac)
    中文技术文档的写作规范
    CentOS7安装GitLab和Jenkins构建CICD环境
    使用Ansible自动化安装MySQL数据库
    CentOS7 Linux生产环境源码编译离线安装Ansible自动化运维工具
    配置Prometheus+Grafana监控主机节点、MySQL、Node、Redis、Mongod、Nginx等
    读书分享——Beyond Feelings: A Guide to Critical Thinking
    Linux云计算架构师及大数据自学资料分享(全集)
    CentOS7安装Rancher企业容器平台
  • 原文地址:https://www.cnblogs.com/bear-blogs/p/10448115.html
Copyright © 2020-2023  润新知