博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
JS 之一起来谈个对象吧~
阅读量:7104 次
发布时间:2019-06-28

本文共 8694 字,大约阅读时间需要 28 分钟。

写的不好的地方麻烦各位大佬指点一下,轻喷,(捂脸逃)

对象:目录

  1. 对象声明
  2. JS 内置对象
  3. 对象属性
  • 获取、添加属性
  • 属性描述符
  • 遍历对象属性的方法
  1. 对象的扩展、密封、冻结
  2. 对象的解构赋值
  3. 常见对象相关操作
  • 判断对象是否是对象
  • 判断是否是空对象
  • 合并对象
  • 深浅拷贝对象
  • 操作原型对象
  • 对象其他方法

1. 对象声明

  1. 文字形式:{}
  • 属性缩写(属性名、方法)
  • 属性名用变量 / 表达式
var a = 1var b = 'sayHi'var c = 'name'var o = {    a,  // 属性缩写    test () { // 方法缩写        console.log('test')     },    [c + ' is']: 'Lin',    [b] () { // 方法缩写 + 变量        console.log('hi')    }    }console.log(o)o.test()复制代码
  1. 构造形式:new Object() (或者 new 其他构造函数/class)

文字形式和构造形式唯一的区别是,在文字声明中你可以添加多个 键 / 值对,而且可以用缩写,但是在构造形式中你必须逐个添加属性

  1. Object.create()

2. 内置对象

  • String、Number、Boolean、Object、Function、Array、Date、RegExp、Error
  • js 会自动把字符串字面量转化为一个 String 对象(如果需要的话,如通过字符串调用方法:'123'.indexOf(1)

3. 对象属性

  • 属性名永远是 string 或者 symbol,如果用了其他类型作为属性名,就会转为 string(PS:所以才有了 Map)
var myObject = {};  myObject[true] = "foo";  myObject[3] = "bar";  myObject[myObject] = "baz";  myObject["true"]; // "foo"  myObject["3"]; // "bar"  myObject["[object Object]"]; // "baz"复制代码
  • 存储在对象内部的是属性的名称,像指针一样,指向这些值真正的存储位置

3.1 访问对象属性

  1. . 操作符
  2. []
  • 变量
  • 表达式
var pre = 'haha'var obj = {  [pre + 'aaa']: 'aaa',  [pre + 'bbb']: 'bbb',  [pre] () {      console.log('haha')  }}console.log(obj['hahabbb']) // bbbobj[pre]()复制代码

3.2 添加对象属性

  1. .
  2. []
  3. Object.defineProperty()

3.3 属性描述符

用来描述对象的某个属性的一些特性的,分为数据描述符和存取描述符

  1. 两者都是
  • configurable(default: false):属性是否可配置(修改属性描述符)、删除
  • enumerable(default: false):属性是否可枚举(会忽略 enumerable = false 的属性的操作)
    • for...in:只遍历对象自身的和继承可枚举的属性。
    • Object.keys():返回对象自身的所有可枚举的属性的键名
    • JSON.strinify():只串行化对象自身可枚举的属性。
    • Object.assign():只拷贝对象自身可枚举的属性
  1. 数据描述符
  • value(defalut: undefined)
  • writable(defalut: false):value 是否可以被赋值运算符修改
var obj = {}Object.defineProperty(obj, 'a', {  writable: true,  value: 100})console.log(obj.a)obj.a = 1console.log(obj.a)复制代码
  1. 存取描述符
  • get(default: false):是一个隐藏函数,当访问该属性时,该方法会被执行,方法执行时没有参数传入,但是会传入 this 对象(由于继承关系,这里的 this 并不一定是定义该属性的对象)
  • setter(defalut: false):是一个隐藏 函数,当属性值修改时,触发执行该方法。该方法将接受唯一参数,即该属性新的参数值

setter 会覆盖单个属性默认的 [[Put]](也被称为赋值)操作。通常来说 getter 和 setter 是成对出现的

如果一个描述符同时有(value或writable)和(get或set)关键字,将会产生一个异常。

  • 用 get、set 的话,会产生一个属性的 u.u
Object.defineProperty(obj, 'b', {  configurable: true,  enumerable: true,  get () {    return this._b || 'haha'  },  set (value) {    this._b = value  }})console.log(obj.b)obj.b = 1console.log(obj.b)复制代码

相当于这样写

var obj = {    get b () {        return this._b || 'haha'    },    set b (value) {        console.log(this)        this._b = value    }}复制代码

seter 和 getter 可以拦截赋值和获取操作,实际上用的那个等号就可以理解成一个语法糖

// 本来可以直接这样的,不用写 get、set 的,但是!obj.b = 100复制代码
  • 可以用来解决 Object.assgin() 拷贝对象的时候,无法拷贝 get、set 属性的问题
const shallowMerge = (target, source) => Object.defineProperties(  target,  Object.getOwnPropertyDescriptors(source))复制代码

3.3.1 定义属性描述符

Object.defineProperty(obj, prop, descriptor)

上面说的默认值,都是在用 Object.defineProperty 定义属性及其描述符的时候才有效的;在其他时候(. 操作符、[])时,无影响(默认都是 true)

var o = {}Object.defineProperty(o, 'a', {})o.a = 10console.log(o.a) // undefinedObject.defineProperty(o, 'a', {  writable: true}) // Uncaught TypeError: Cannot redefine property: a复制代码

3.3.2 获取属性描述符

  1. Object.getOwnPropertyDescriptor(obj, prop)
/** * 获取对象的某个属性的描述对象 * Object.getOwnPropertyDescriptor(obj, prop) *  * @param {object} obj * @param {string} prop * @returns {object | undefined} */obj.c = 10console.log(Object.getOwnPropertyDescriptor(obj, 'c')) // {value: 10, writable: true, enumerable: true, configurable: true}console.log(Object.getOwnPropertyDescriptor(obj, 'b')) // {get: ƒ, set: ƒ, enumerable: true, configurable: true}复制代码
  1. Object.getOwnPropertyDescriptors(obj)
/** * 获取对象自身的所有属性的描述对象(非继承) * @param {object} obj * @returns {object} prop: descriptor */复制代码

3.4 遍历对象的方法

主要看,能不能遍历继承的、symbol、不可枚举的(只要是打 X 的,就不能访问到)

方法 继承 symbol 不可枚举
for...in X X
Object.keys(obj)、Object.values(obj)、Object.entries(obj) X X X
Object.getOwnPropertyNames(obj) X X
Object.getOwnPropertySymbols(obj) X (可以遍历 symbol)
Reflect.ownKeys(obj) X
  • 可以通过 for...in + obj.hasOwnProperty(prop) 来遍历自身属性(这样就相当于 Object.keys()
  • Object.getOwnPropertyNames(obj) + Object.getOwnPropertySymbols(obj) = Reflect.ownKeys(obj)
// 遍历相关function Super () {  this.super = 'superValue'  this[Symbol('superSymbol')] = 'haha' // 可枚举的 Symbol}function Sub () {  this.sub = 'subValue'  this[Symbol('subSymbol')] = 'xixi'}var sup = new Super()// 定义不可枚举的属性Object.defineProperty(sup, 'superEnum', {  enumerable: false,  configurable: false,  value: 'superEnumValue'})// 定义不可枚举的 SymbolObject.defineProperty(sup, Symbol('superEnumSymbolValue'), {  enumerable: false,  configurable: false,  value: 3})// 定义继承Sub.prototype = supvar sub = new Sub()Object.defineProperty(sub, 'subEnum', {  enumerable: false,  configurable: false,  value: 'subEnumValue'})Object.defineProperty(sub, Symbol('subEnumSymbolValue'), {  enumerable: false,  configurable: false,  value: 1})// 可遍历继承、不可遍历 symbol、不可遍历不可枚举的for (var i in sub) {  console.log(i)  // sub  // super}// 不可遍历继承、不可遍历 symbol、不可遍历不可枚举的console.log(Object.keys(sub)) // [ 'sub' ]console.log(Object.values(sub)) // [ 'subValue' ]console.log(Object.entries(sub)) // [ [ 'sub', 'subValue' ] ]// 不可遍历继承、不可遍历 symbol、可遍历不可枚举的(包括不可枚举的 Symbol)console.log(Object.getOwnPropertyNames(sub)) // [ 'sub', 'subEnum' ]// 遍历自身的所有 symbols,包括不可枚举的console.log(Object.getOwnPropertySymbols(sub)) // [Symbol(subSymbol), Symbol(subEnumSymbolValue)]// 不可遍历继承、可遍历 Symbol、可遍历不可枚举的console.log(Reflect.ownKeys(sub)) // [ 'sub', 'subEnum', 'subEnumSymbol', Symbol(subSymbol) ]// 不可遍历继承、可遍历 Symbol、可遍历不可枚举的console.log(Object.getOwnPropertyDescriptors(sub)) // 复制代码

4. 对象的扩展、密封、冻结(这个再看看高设)

属性描述符是针对对象的属性的,而扩展、密封、冻结则是针对对象的。

可配置、可写与扩展、密封、冻结没有什么关系

var o = {}Object.defineProperty(o, 'a', {})console.log(Object.getOwnPropertyDescriptor(o, 'a'))console.log(Object.isExtensible(o)) // trueconsole.log(Object.isSealed(o)) // falseconsole.log(Object.isFrozen(o)) // false复制代码
  • 可扩展:可以添加新属性

    • Object.isExtensible(obj):是否可扩展
    • Object.preventExtensions(obj):让一个对象永远不可扩展,返回操作后的对象
  • 密封:不可添加、删除属性,且所有属性不可配置(configurable: false

    • Object.isSealed(obj):是否密封
    • Object.seal(obj):密封对象,返回密封后的对象
  • 冻结:密封 + 不可修改所有属性的值(地址)(属性是对象的话,除非也是冻结,否则可改)

    • Object.isFrozen(obj):是否冻结
    • Object.frozen(obj):冻结对象,返回冻结后的对象

浅冻结与深冻结~

深冻结:如果属性是对象,那么那个对象也是冻结的

5. 解构赋值

看解构赋值一文

6. 与对象相关的操作

6.0 判断是否是对象

Object.prototype.toString.call(obj) === '[object Object]'复制代码

6.1 判断对象是否为空

这里是要看空对象的概念是什么,这里空对象表示:

  • 不考虑 null
  • 对象自身的不可枚举、非 symbol 的属性
  1. for...in
var obj = {}function objectIsEmpty (obj) {  for (var key in obj) {    if (obj.hasOwnProperty(key)) {      return false    }  }  return true}console.log(objectIsEmpty(obj))复制代码
  1. Object.keys()
function objectIsEmpty (obj) {  return Object.keys(obj).length === 0 ? true : false}console.log(objectIsEmpty(obj))复制代码
  1. JSON.stringify()
function objectIsEmpty (obj) {  return JSON.stringify(obj) === '{}' ? true : false}console.log(objectIsEmpty(obj))复制代码

总结:其实本质就是用对象遍历的方法而已,具体要看空对象的定义是什么。

6.2 复制对象(深浅拷贝)

看 深浅拷贝 一文

6.3 合并对象

特点:拷贝源对象自身可枚举属性(包括 Symbol 类型的属性)

o = Object.assgin({}, o1, o2) // 会修改目标对象复制代码

缺点:不能复制对象属性的 getset 属性。如果要避免这个问题,就用:

const shallowMerge = (target, source) => Object.defineProperties(  target,  Object.getOwnPropertyDescriptors(source))复制代码
  1. ... 扩展运算符
o = {...o1, ...o2}复制代码
  1. mixin 的实现(多个类的合并)
  • 拷贝实例属性和原型属性

6.4 操作原型对象

原型对象:当前对象的 prototype 对象

  1. Object.setPrototypeOf(obj, proto)
  • 设置对象的原型对象
  1. Object.getPrototypeOf(obj)
  • 获取对象的原型对象
  1. Object.create(obj)
  • 返回一个指定对象原型的对象

6.5 其他方法

  1. 判断两个值是否相等
  • Object.is
  1. 是否有某个属性
  • Object.prototype.hasOwnProperty(prop)

  • 返回布尔值,指示对象自身属性中是否包含具体指定的属性

  • in 操作符(prop in object)

  • 属性是否在对象或它的原型链上,返回 true 或者 false

var o = {a: 1}console.log('a' in o) // true复制代码
  1. Object.assign()
/** * 将所有可枚举属性的值从一个或多个源对象**浅拷贝**到目标对象 * 它将返回目标对象。(目标对象会被修改) * Object.assgin(targetObj, sourceObj1, sourceObj2, ...) *  * @param {object} targetObj * @param {object} sourceObj1 * @returns {object} targetObj */let obj = {  a: 1,  b: 2}Object.assign(obj, {a: 3, c: 4})console.log(obj) // { a: 3, b: 2, c: 4 }复制代码
  • target 如果不是对象,会自动转为对象. 如果是 null 或者是 undefined 就会报错
console.log(Object.assign(1, {a: 1})) // Number {1, a: 1}复制代码
  • obj1、obj2,原始类型会被包装为对象。
var v1 = "abc";var v2 = true;var v3 = 10;var v4 = Symbol("foo")var obj = Object.assign({}, v1, null, v2, undefined, v3, v4); // 原始类型会被包装,null 和 undefined 会被忽略。// 注意,只有字符串的包装对象才可能有自身可枚举属性。console.log(obj); // { "0": "a", "1": "b", "2": "c" }复制代码
  • 同名属性会发生替换。以后面出现的为准。
  • 无法正确拷贝 get 属性和 set 属性。Object.assign 方法总是拷贝一个属性的值,而不会拷贝它背后的赋值方法或取值方法。
var obj = Object.assign({}, {  get g () {    return 'abc'  }})console.log(obj) // { g: 'abc' }复制代码

用途

(1) 为对象添加属性、方法

let o = Object.assign({}, {  a: 1,  sayHi () {    console.log('hi')  }})console.log(o) // {a: 1, sayHi: ƒ}复制代码

(2) 克隆对象

  • 不含继承(只克隆对象自身可枚举属性)
function clone(origin) {  return Object.assign({}, origin);}复制代码
  • 克隆继承链
function clone (obj) {  return Object.assign(Object.create(Object.getPrototypeOf(obj)), obj)}复制代码

(3) 合并多个对象

const merge =  (target, ...sources) => Object.assign(target, ...sources);复制代码

转载地址:http://oqjhl.baihongyu.com/

你可能感兴趣的文章
gnome-terminal技巧
查看>>
jQuery插件开发全解析
查看>>
Visual Studio 2012/2010/2008 远程调试
查看>>
jsp页面传值的乱码问题总结
查看>>
名不副实的女解说员
查看>>
cacti批量添加主机和图形
查看>>
源代码安装
查看>>
dhcp在企业网的应用
查看>>
thinkphp U方法生成链接没有host
查看>>
ElasticSearch入门介绍之安装部署(二)
查看>>
continue与break的理解
查看>>
我的友情链接
查看>>
date用法示例_shell脚本
查看>>
Ubuntu命令行中文乱码的解决方法
查看>>
Linux 常用命令
查看>>
KVM启动报错qemu-kvm: cannot set up guest memory 'pc.ra
查看>>
软考中高项学员:2016年3月30日作业
查看>>
汇编语言---机器语言
查看>>
Vmware vSphere 5.0系列教程之六 虚拟机及主机配置文件的创建和模板部署
查看>>
python3-字典的一些常用方法
查看>>