JavaScript对象操作

上次介绍JavaScript简单的创建对象方式:https://blog.csdn.net/cleanHtroop/article/details/103842461

 

“JavaScript中万物皆为对象”,这是一个错误的说法。

事实上,JavaScript中包含有基本类型(string, boolean, number, null, undefined 和 symbol)。所以并不是所有都是对象。

 

判断对象

如果判断是否是一个对象,最常用的方法是 typeof

typeof {} // "object"

但typeof也有小缺陷,就是null会被当成对象类型

typeof null // "object"

如果需要更准确的判断方式,可以使用下面的方式去判断

function isObject(value) {
         return Object.prototype.toString.call(value) === "[object Object]"
}

isObject({}) // true

isObject(null) //false 因为Object.prototype.toString.call(null) === "[object Null]"

 

输出结果主要根据[[Class]]的内部属性,但这个属性不能直接访问,只能通过上面的方式来查看。[[Class]]与原生对象构造函数相对应,但是null和undefined除外,因为Null()和Undefined()的原生构造函数不存在,但是内部的[[Class]]属性仍然是”Null”和”Undefined”

对象属性和方法

var person = {
    name: "Howard",
    age: 20,
    job: "Front-End Engineer",
    sayName: function() {
         console.log(this.name);
    }
}

读取对象属性和调用对象方法的有两种形式:

person.name // "Howard"
person['name'] // "Howard"

最常用的第一种方式,但第二种方式可以支持变量的方式

var value = 'name';
person.value // undefined
person[value] // "Howard"

实际上,获取对象属性的时候,会触发[[Get]]操作,检查是否有名称相同的属性,如果找到就返回该值,没有就去查找prototype。当然,修改属性的时候就会触发[[Put]]操作,会进行属性描述符判断(可以见下文)。

我们可以对[[Put]]和[[Get]]操作进行修改。

var obj = {
    get a() {
        return 2;
    }
};

Object.defineProperty(
    obj, //对象
    'b', //属性名
    { //描述符
        get: function() {return this.a * 2}
    }
)

obj.a //2

obj.b //4

var obj = {
    get a() {
        return this._a_;
    },
    set a(val) {
        this._a_ = val * 2
    }
};

obj.a = 2;

obj.a //4

即使给obj赋值a,在读取属性的时候,也会使用修改的get方法

obj.a = 3;
obj.a // 2

复制对象

在Java里面,会提供一个clone的方法来帮助我们进行对象复制。但是JavaScript里面没有。

大部分面向对象语言,对于复制对象来说,分为深复制和浅复制,因为变量保存的是对象的引用,所以不小心就会导致浅复制:

var boy = {
    name: 'Boy',
    person: person
}


var girl = {
    name: 'Girl',
    person: person
}

boy.person.age = 10;

girl.person.age // 10

不仅仅是普通对象,常用的内置对象--数组,也容易出现这样的错误。

在ES6中,提供了一个非常常用的方法,经常用于React, angular等框架的代码中, Object.assign(target, ...sources),会返回一个新的对象引用,这样框架就可以进行脏值检测;

var boy = Object.assign({ name: ‘Boy’ }, person) // {name: "Howard", age: 10, job: "Front-End Engineer", sayName: ƒ}

对于深复制,需要解决问题有很多,例如如何解决相互循环引用,怎么复制一个函数等,会涉及不同引擎对于不同类型函数的处理方式

 

许多框架都有深复制的方法,例如jQuery的$.extend(true,object1, object2);

 

如果确保JSON安全(就是可以序列成一个JSON字符串并且根据这个字符串解析出一个结构和值完全一样的对象),可以这个方法:

var newObj = JSON.parse(JSON.stringify(someObj));

var person = {
    name: "Howard",
    age: 20,
    job: "Front-End Engineer",
    sayName: function() {
        console.log(this.name);
    },
    mon: {
        age: 50
    }
}

var boy = JSON.parse(JSON.stringify(person))

boy.mon.age = 40

person.mon.age // 50

 

属性描述符

在ES5之前,没有检测属性的方法,但ES5之后,所有属性都具有属性描述符,但是比较少使用到。只列出来。

1. Object.getOwnPropertyDescriptor(obj, prop) 方法返回指定对象上一个自有属性对应的属性描述符。

2. Object.getOwnPropertyDescriptors(obj) 方法用来获取一个对象的所有自身属性的描述符。

3. Object.defineProperties(obj, props) 方法直接在一个对象上定义新的属性或修改现有属性,并返回该对象。

4. Object.defineProperty(obj, prop, descriptor) 方法会直接在一个对象上定义一个新属性,或者修改一个对象的现有属性, 并返回这个对象。

属性描述符有:

  1. Writable // 决定是否可以修改属性的值
  2. Configurable //决定属性是否可以使用defineProperty方法去修改属性描述符
  3. Enumerable // 决定属性是否在对象的属性枚举中 例如for…in循环

 

a.常量

  当设置writable:false 和 configurable:false可以创建一个对象常量

b.禁止拓展

  Object.preventExtensions(obj) // 不能添加新属性

c.密封

  Object.seal() //调用perventExtension方法,并且设置configurable: false

d.冻结

  Object.freeze() //调用seal方法,并且设置writable: false

 

tip: Object.assign也是无法拷贝属性描述符的,MDN提供这个方法去进行拷贝。

Object.create(
  Object.getPrototypeOf(obj),
  Object.getOwnPropertyDescriptors(obj)
);

参考文献

《你不知道的JavaScript上卷》第三章对象

《JavaScript高级程序设计(第三版)》p596~p597

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值