JS数据类型之Object(一)对象知识扫盲

简介

在javascript中,对象被定义为一组属性的无序集合。即对象是一组没有特定顺序的值。
对象的构成为:属性和方法。一个对象可以拥有多个属性和多个方法。

{
  age: 18,
  name: "名字是什么",
  sayName() {
    console.log(this.name);
  }
}

对象的属性

一个JavaScript对象中有很多属性。一个对象的属性可以被解释为一个附加到对象上的变量。
属性由一个字符串类型的名字(name)和一个属性描述符(property descriptor)对象构成。

属性的类型

JavaScript中使用一些内部特性来描述属性的特征。开发者不能在JavaScript中直接访问这些特性。规范中用两个中括号把特性的名称括起来,如[[Enumerable]]

属性分两种:数据属性和访问器属性

数据属性【数据】

数据属性包含一个保存数据值的位置。数据属性有四个特性描述它们的行为。

属性描述符 解释 取值
[[Configurable]] 1、是否可以通过delete删除并重新定义
2、是否可以修改它的特性
3、是否可以把它改为访问器属性
true:默认值
false
[[Enumerable]] 是否可以被for-in循环返回 true:默认值
false
[[Writable]] 是否可以被修改 true:默认值
false
[[Value]] 属性实际值 undefined:默认值
JavaScript中的任意类型

数据属性定义

  • 直接定义:直接定义属性的时候,以上四种属性描述符都是默认值true。
  • 使用Object.defineProperty()方法进行精确定义属性及其属性描述符。
Object.defineProperty(对象名, 属性名, 属性描述符(对象))

属性描述符是必须是一个对象,对象中最多有四个属性:configurableenumerablewritablevalue。如果configurableenumerablewritable没有指定,将被指定为falsevalue指定为undefined

访问器属性【存储】

访问器属性不包含数据值。相反,它们包含一个获取(get)函数和一个设置(set)函数,不过这两个函数不是必须的。

  • 获取函数(get):在读取访问器属性时,被调用;返回一个有效值。
  • 设置函数(set):在设置访问器属性时,被调用;设置为传入的 新值。
    访问器属性有四个特性描述它们的行为。
属性描述符 解释 取值
[[Configurable]] 1、是否可以通过delete删除并重新定义
2、是否可以修改它的特性
3、是否可以把它改为数据属性
true:默认值
false
[[Enumerable]] 是否可以被for-in循环返回 true:默认值
false
[[Get]] 获取函数,在读取属性时调用 undefined:默认值
[[Set]] 设置函数,在设置属性时调用 undefined:默认值

访问器属性常常用来设置一些私有属性,从而达到属性的保护。

访问器属性定义

  • 访问器属性不能直接定义
  • 使用Object.defineProperty()定义访问器属性
Object.defineProperty(对象名, 属性名, 属性描述符(对象))

属性描述符中的获取和设置函数不一定都要定义。只定义设置函数,表示不能读取;只定义获取函数,表示只能读取。

定义多个属性

通过Object.defineProperties()方法定义多个属性及其属性描述符。

Object.defineProperties(对象, {
  数据属性: 数据属性的描述符,
  ...
  访问器属性: 访问器属性的描述符
  ...
})

注意事项
【1】数据属性的configurablewritable为false,可以通过访问器属性的set()方法进行修改。
【2】如果数据属性configurableenumerablewritable没有指定,将被指定为falsevalue指定为undefined

读取属性的描述符
  • 使用Object.getOwnPropertyDescriptor()方法可以取得指定属性的属性描述符。
    语法:Object.getOwnPropertyDescriptor(对象名, 属性名)
    参数:属性所在对象和对应的属性名。
    返回值:一个对象。对于数据属性,返回configuraableenumerablewritablevalue属性;对于访问器属性,返回configurableenumerablegetset属性。

  • 使用Object.getOwnPropertyDescriptors()方法可以取得指定属性的属性描述符。
    语法:Object.getOwnPropertyDescriptors(对象名)
    参数:属性所在对象
    返回值:一个对象。对于数据属性,返回configuraableenumerablewritablevalue属性;对于访问器属性,返回configurableenumerablegetset属性。

访问对象的方式

方式 使用 样例
点符号 属性为有效的JavaScript字符串 objectName.propertyName
方括号 属性为有效/无效的JavaScript字符串
通过for...in循环遍历对象属性
objectName[propertyName变量]
  • 注意事项:
    1、对象的名字和属性的名字是大小写敏感的。
    2、对象中未赋值的属性的值为undefined
    3、对象的属性名可以是有效的JavaScript字符串,也可以被转换为字符串的任何类型。
    4、对象的属性的值可以是普通变量,也可以是函数。

增强的对象语法

属性简写

给对象添加变量时,属性名和变量名一致,我们可以使用属性简写的进行添加变量。

let name = "名字"
// 之前
let person = {
  name: name
}
// 属性简写后
let person = {
  name
}
计算属性

计算属性:在[ ]中放入表达式,计算结果可以当做属性名。
这种用法和用方括号访问属性非常类似。

简写方法名
// 未简写
let person = {
  sayName: function() {
    
  }
}

// 简写后
let person = {
  sayName() {
    
  }
}

注意事项

  • 简写方法名对获取函数(get)和设置函数(set)也是适用的。
  • 简写方法名可以与计算属性相互兼容

对象解构

对象解构就是使用与对象匹配的结构来实现对象属性的赋值。

展开语法(...):三个点,将对象中的属性全部提取出来。【与数组中的展开语法类似,但有区别】
解构语法(...):将对象中的某些属性从中拿出来。【注意:左边的源数据,右边是声明的变量】解构语法可以解构内置对象中的某些属性。

<!DOCTYPE html>
<html>
    <head>
        <meta charset="utf-8">
    </head>
    <body>
        <script type="text/javascript">
            "use strict"
            let item = {
                name: "hahaha",
                sex: "nan"
            }

            // 展开语法
            console.log({
                ...item
            }) // {name: "hahaha", sex: "nan"}

            // 解构语法
            let {
                name: n,
                sex: s,
                other = "nothing" // 设置默认值
            } = item // let {name, sex} = item // 如果名字一致,可以用省略模式            
            console.log(n) // hahaha
            console.log(s) // nan
            console.log(other) // nothing
            
            // 变量提前定义,结垢时使用()括起来。
            let item_name, item_sex
            ({
                name: item_name,
                sex: item_sex,
            } = item) // let {name, sex} = item // 如果名字一致,可以用省略模式           
            console.log(item_name) // hahaha
            console.log(item_sex) // nan

            // 深层次的解构
            let item2 = {
                name1: "hahaha",
                other1: {
                    no: "none"
                }
            }
            let {
                name1,
                other1: {
                    no
                }
            } = item2;
            console.log(name1) // hahaha
            // console.log(other1) // Uncaught ReferenceError: other1 is not defined
            console.log(no) // none


            // 与解构语法进行区分
            let a = "123"
            let b = "456"
            let opt = {
                a1: a,
                b1: b
            } //  let opt = {a, b} // 如果名字一致,可以用省略模式
            console.dir(opt)
        </script>
    </body>
</html>

对象合并

合并的方法:

  • 使用展开语法(...)将对象的枚举属性赋值到一个新的对象上。
  • 使用Object.assgin()方法进行对象的赋值。【Object.assign()进行对象复制的时候是浅复制】
Object.assign() 展开语法
使用场景 复制对象
对象拷贝
复制对象
对象拷贝
枚举 可枚举 可枚举
原型链 不触发,即使原型链上是可枚举的属性 不触发,即使原型链上是可枚举的属性
区别 会触发setter 不会触发setter

对象的方法

一个方法是关联到某个对象的函数,或者简单说,一个方法是一个值为某个函数的对象属性。定义方法就像定义普通的函数,然后赋值给对象的某个属性。
方法的定义有两种方式:

// 常规方式
var obj = {
  foo: function() {
    /* code */
  },
  bar: function() {
    /* code */
  }
};
// 方法名简写方式
var obj = {
  foo() {
    /* code */
  },
  bar() {
    /* code */
  }
};

Object中的静态方法

Object.assgin()
  • 作用:进行对象的复制【浅拷贝】
  • 语法:Object.assign(目标对象, 多个源对象)
  • 返回值:返回合并后的对象,与目标对象相等。
  • 底层:使用源对象的[[Get]]取的属性的值,使用目标对象的[[Get]]设置属性的值。
    注意事项
    1、复制以字符串和符号为键的属性。
    2、Object.assgin()该方法是浅拷贝。
    3、如果多个源对象有相同的属性,则使用最后一个复制的值。
Object.is()
  • 作用:进行对象的判断
  • 语法:Object.is(对象1,对象2)
  • 返回值:如果相等,返回true;否则返回false。
    注意事项
    1、该方法与===的作用类型
    2、参数可以是基本数据类型
Object.defineProperty()
  • 作用:给某个对象添加单个属性,同时设置属性的描述符
  • 语法:Object.defineProperty(对象, 属性名, 属性描述符)
    注意事项
    1、属性描述符必须是一个对象
Object.defineProperties()
  • 作用:给某个对象同时添加多个属性,同时设置属性的描述符
  • 语法:Object.defineProperties(对象, 属性名及属性描述符)
    注意事项
    1、第二个参数的形式如下,属性描述符必须是一个对象。
{
  属性一: 属性描述符,
  ...
}
Object.getOwnPropertyDescriptor()
  • 作用:获取某个对象中某个属性的属性描述符
  • 语法:Object.getOwnPropertyDescriptor(对象, 属性名)
  • 返回值:返回一个对象。如果是数据属性,返回configurableenumerablewritablevalue;如果是访问器属性,返回configurableenumerablegetset
Object.getOwnPropertyDescriptors()
  • 作用:获取某个对象中某个属性的属性描述符
  • 语法:Object.getOwnPropertyDescriptor(对象)
  • 返回值:返回一个对象。如果是数据属性,返回configurableenumerablewritablevalue;如果是访问器属性,返回configurableenumerablegetset

对象引用

对象和函数、数组一样是引用类型,即复制只会复制引用地址。
对象作为函数的形参,实际上传递的是对象的地址

this

this关键字表示当前对象

对象的遍历

枚举一个对象的属性

以下方法受到enumerable原型链的影响。

方法 for...in循环 Object.keys(o) Object.getOwnPropertyNames(o) Object.getOwnPropertySymbols(o)
含义 返回对象及原型链上可枚举的属性 返回自身的所有可枚举属性 返回自身所有属性 返回自身所有的Symbols属性
是否可枚举 不关心 Symbol
是否访问原型链 访问 不访问 不访问 不访问
是否访问Symbol 不访问 不访问 不访问 访问

for...in

作用:以任意顺序遍历一个对象的除Symbol以外的可枚举属性【包含原型链上可枚举的属性】

Object.keys()

作用:返回一个由一个给定对象的自身可枚举属性组成的数组,数组中属性名的排列顺序和正常循环遍历该对象时返回的顺序一致 。

Object.values()

作用:返回一个给定对象自身的所有可枚举属性值的数组。

Object.entries()

作用:返回一个给定对象自身可枚举属性的键值对数组

Object.getOwnPropertyNames()

作用:返回一个由指定对象的所有自身属性的属性名(包括不可枚举属性但不包括Symbol值作为名称的属性)组成的数组。

Object.getOwnPropertySymbols()

作用:返回一个给定对象自身的所有 Symbol 属性的数组。

对象的继承

所有的JavScript对象至少继承于一个对象,被继承的对象被称为原型。
每个对象可以通过构造函数的prototype属性找到原型 或 每个实例对象有一个私有属性__proto__指向原型

获取对象原型

方法一:Object.getPrototypeOf()方法返回指定对象的原型。
方法二:实例化对象.__proto__

Object.getPrototypeOf(object)

  • 参数
    obj:要返回其原型的对象
  • 返回值
    给定对象的原型,如果没有继承属性,则返回null

设置或修改对象原型

方法一:Object.create()创建对象的时候指定原型.
方法二:Object.prototype.__proto__
方法三:Objcet.setPrototypeOf()
方法四:Reflect.setPrototypeOf()

Object.create(proto, propertiesObject):

  • 参数:
    proto:新创建对象的原型对象
    propertiesObject:可选
  • 返回值
    一个新对象,带着指定的原型对象的属性。
<!DOCTYPE html>
<html>
   <head>
       <meta charset="utf-8">
   </head>
   <body>

       <script type="text/javascript">
           "use strict"
           // Shape - 父类(superclass)
           function Shape() {
             this.x = 0;
             this.y = 0;
           }
           
           // 父类的方法
           Shape.prototype.move = function(x, y) {
             this.x += x;
             this.y += y;
             console.info('Shape moved.');
           };
           
           // Rectangle - 子类(subclass)
           function Rectangle() {
             Shape.call(this); // call super constructor.
           }
           
           // 子类续承父类,以下两句话一般同时存在
           Rectangle.prototype = Object.create(Shape.prototype);
           Rectangle.prototype.constructor = Rectangle;
           
           var rect = new Rectangle();
           
           console.dir(rect) // rect --> Rectangle---->Shape---->Object
       </script>
   </body>
</html>

Objcet.setPrototypeOf(obj, prototype)

  • 参数:
    obj:设置其原型对象
    prototype:对象的新原型(对象或null)
  • 过程:
    如果对象的原型被修改成不可扩展(通过Object.isExtensible())的,则抛出TypeError异常。
    如果prototype新原型参数不是对象或努力了,则什么也不做。
    否则,该方法修改对象的原型。

Reflect.setPrototypeOf(target, prototype)

  • 参数:
    target:设置其原型对象
    prototype:对象的新原型(对象或null)
  • 返回值:
    返回一个boolean类型表明是否原型已经设置成功。
  • 过程:
    如果参数target不是Object,或者prototype既不是对象,也不是null,则抛出TypeError异常。

Object原型与属性相关的方法

方法 作用 参数 返回值
obj.hasOwnProperty() 判断属性是否在某个对象自身上 {不含原型链} prop:要检测的属性 true:有
false:无
prop in obj 判断属性是否在某个对象上 {含原型链} prop:要检测的属性 true:有
false:无
prototypeObj.isPrototypeOf(obj) 测试一个对象是否在另一个对象的原型链上 object:在该对象的原型链上搜寻 true:在
false:不
instanceof操作符 检测构造函数的prototype属性是否会出现在某个实例对象的原型链上 操作符,不是函数 true:在
false:不在
obj.propertyIsEnumerable(prop) 判断属性名是否可枚举 prop需要测试的属性 true:枚举
false:非枚举
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,547评论 6 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,399评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,428评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,599评论 1 274
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,612评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,577评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,941评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,603评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,852评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,605评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,693评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,375评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,955评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,936评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,172评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,970评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,414评论 2 342

推荐阅读更多精彩内容