Javascript学习笔记-Object

Object对象.png

1. 基础

1.1 基本类型

曾经听说Javascript万物皆对象,没对这句话有过更多的考虑,总觉得是对的,但是实际上并不一定妥当,对象类型是Javascript的6个基本类型之一。Javascript包含六种基本类型,分别是number, string, boolean, null, undefined, object
其中,虽然typeof null === 'object',但是null确实被认为是独立的基本类型,之所以会有这样的结果,是因为object是数据根据二进制转后前三位来判断的,前三位是0的会被认为是object类型,因为null全部都是0,所以也被认为是object

1.2 内置对象

除开基本类型,在object基础上,存在9个常用的内置对象Number, String, Boolean, Object, Function, Array, Date, RegExp, Error
为什么会存在这些内置对象?因为基本类型是没有提供任何的方法的,我们在Javascript的字面量或者对象调用的属性/方法,实际上是来自于内置对象。也就是说对于基本类型string,并没有length,我们在获取length属性的时候,基本类型会转换为对应的内置对象而使用内置对象的方法获取相关内容

2. 对象创建

Javascript对象创建通常有两种方法:字面量和构造方法
通过字面量的方式进行创建是最常见的。

var o = {} // 字面量,使用大括号进行创建
var o = new Object() // 构造方法,使用new的方式创建
var o = Object.create({}) // 也可以使用Object提供的方法也可以创建一个对象

3. 属性增加

3.1 计算属性

以字面量的方式为例,我们要给对象增加属性,一般在创建对象的时候同时进行属性赋值,在ES6引入了计算属性,使得属性名可以通过计算的方式设置,计算属性使用[],将需要计算的内容放到[]内部。

var pname = 'abc';
var o = {
    x: 1,
    ['a'+'b']: 2, // 计算属性
    [pname]: 3 // 计算属性,使用变量作为属性名
}

但是需要注意的一点,对于object而言,所有的属性名在设置的时候都会调用toString()的方法

var po = {};
var o = {
  [po]: 1 // po会调用toString方法
}
// 上面的对象实际上会变为
var o = {
  '[object Object]': 1
}

3.2 属性描述符

Javascript对象属性有5个属性描述符,用于对属性增加限制,分别是:writable, enumerable, configurable, get, set
我们可以使用Object.defineProperty()的给对象定义属性的时候增加属性描述

  var o = {};
  Object.defineProperty(o, 'x', {
    value: 1, // 设置属性的值, 默认undefined
    writable: false, // 设置属性是否可写,默认false
    enumerable: false, //设置属性是否可枚举,默认false
    configurable: false, // 属性描述是否可修改,默认false
    get: function(){return xxx}, // 属性get方法,也可以写作get() {}, 默认undefined
    set: function(val){}, // 属性set方法,也可以写作set(){}, 默认undefined
  })

不过要注意,这里的valuewritable不能和get(),set()同时进行设置
对于属性描述符configurable,如果设置为false,那么则不能再对对象的属性描述进行修改(writable属性从true->false是例外),否则将抛出异常

var o = {};
Object.defineProperty(o, 'x', {
  value: 1,
  configurable: false
})
Object.defineProperty(o, 'x', {
  value: 1,
  configurable: true
}) // 抛出异常Uncaught TypeError: Cannot redefine property

3.3 属性不变性

由于属性描述符可以对属性增加限制,所以可以利用这些限制来创建一些特定要求的属性,使得属性不能进行修改和重新配置,主要是用Object对象所提供的方法,来对现有对象中的属性进行处理

3.3.1 阻止对象扩展Object.preventExtensions()

使用该方法可以阻止当前的对象扩展新的属性

var o = {};
Object.preventExtensions(o) // 阻止对象增加新的属性
o.a = 1; // 严格模式下会抛出异常
console.log(o.a) // undefined
3.3.2 密封Object.seal()

使用该方法,会在Object.preventExtensions()的基础上,将对象当前所有属性的configurable设置为false

var o = {a: 1};
Object.seal(o); //密封
o.b = 1; //严格模式下抛出异常
console.log(o.b) //undefined
Object.defineProperty(o, 'a', {
    configurable: true
}) //抛出异常
3.3.3 冻结Object.freeze()

使用该方法,会在Object.seal()基础上,将当前对象所有属性的writable设置为false

var o = {a: 1};
Object.freeze(o); //冻结
o.a = 2; //严格模式下抛出异常
console.log(o.a); // 1
o.b = 1; //严格模式下抛出异常
console.log(o.b) //undefined
Object.defineProperty(o, 'a', {
    configurable: true
}) //抛出异常

3.4 数组对象中的属性

数组本身是内置对象,所以可以增加属性,当属性名为数字或者可以转换为数字时,将对数组内容进行修改,属性名为其他内容的时候并不会扩展数组对象长度

var o = [1, 2, 3];
o[3] = 4;
console.log(o.length); // 4
o['a'] = 4;
console.log(o.length); // 4

3.5 __proto__属性

对象中__proto__属性是一个特殊属性名,进行设置时如果属性值是一个object或者null,则可以改变该属性的结果,否则不能修改该属性。

var o = {__proto__: 1}
console.log(o.__proto__); // 并不等于1
var o = {__proto__: null}
console.log(o.__proto__); // undefined

3.6 方法属性

对象中的方法也是一种属性,只是和普通属性设置时存在一定的区别。从某些方面上来说,方法并不属于某个对象,因为如果方法中使用this关键字,这个this并不一定就一定指代该对象。

var o = {
  foo: function(){},
  bar() {},  // ES6新增的声明方式
  ['a'+'b']() {} // 使用计算属性进行声明
}

3.7 generator和async方法

ES6中新增的generator和async方法,也可以在对象方法属性中进行设置

var o = {
  // generator方法创建方式1 :*在方法名之前
  *g() {},  
  // generator方法创建方式2: *在function之后
  ge: function*() {}, 
  // async方法创建方式1: async关键字在方法名前
  async as() {}, 
  // async方法创建方式2: async关键字在function之前
  asy: async function() {}
};

其中关于generator和async方法的内容可以参考MDN相关说明

3.8 get和set方法

在属性设置的时候可以使用getset方法替代直接对属性进行赋值,使用getset方法替代以后,则可以在数据设置和获取时添加逻辑,进行监听了

var o = {
  get x() {return this._x_},
  set x(val) { this._x_ = val }
};
o.x = 1;
console.log(o.x); // 1

4. 属性获取

对象属性获取有两种常见的方式:使用.和使用[]

4.1 属性访问(使用.)

如果需要获取的属性名不是数字,不包含空格,那么我们通常都是使用.的方式来获取,但是对于如果属性名为数字或者包含空格,则没办法通过这样的方式获取

var o = {a: 1, 1: 'a'};
console.log(o.a); // 1
console.log(o.1); // error

4.2 键访问(使用[])

因为使用.获取对象属性的时候存在限制,所以在不能使用.的场合,我们可以使用[]来获取,但是也需要注意,对于使用[]来获取的时候,[]中的内容会调用toString()后进行属性名的匹配

var pname = {};
var pname2 = {a: 1};
var o = {a: 1, 1: 'a'};
console.log(o['a']); // 1
console.log(o[1]===o['1']); // true
o[pname] = 2; // 会被转换为o['[object Object]'] = 2;
console.log(o[pname2]); // 2,因为会被转换为 o['[object Object]']

5. 循环

5.1 in和for in

使用in关键字,可以判断一个属性是否存在对象中,但是这里会遍历对象的原型链去查找该属性

function F() { this.a = 1};
function G() { this.b = 1};
G.prototype = new F;
var o = new G;
console.log('a' in o); // true
console.log('b' in o); // true

使用for in循环,可以循环对象中所有的enumerable:true属性,同样遍历时会查找该对象原型链上的属性

function F() { this.a = 1};
function G() { this.b = 1};
G.prototype = new F;
var o = new G;
Object.defineProperty(o, 'c', {
  value: 2,
  enumerable: true // enumerable默认为false
})
for(let key in o){
  console.log(key); //  b c a
}

为了判断属性是否只在该对象中,可以使用Object.hasOwnProperty()的方法来处理结果

function F() { this.a = 1};
function G() { this.b = 1};
G.prototype = new F;
var o = new G;
for(let key in o){
  if (o.hasOwnProperty(key)) {
    console.log(key); // b
  }
}

除此之外,使用Object.keys()Object.getOwnpropertyNames()可以获取对象的属性名数组,只是这两个方法都只能获取当前对象的属性,不能获取原型链上的属性名

function F() { this.a = 1};
function G() { this.b = 1};
G.prototype = new F;
var o = new G;
console.log(Object.keys(o)); // ['b']
console.log(Object.getOwnPropertyNames(o)); // ['b']

5.2 for of

ES6中增加了for of方法来对对象进行循环,对象想要实现for of循环,需要定义[Symbol.iterator]属性,通过返回一个next方法,next方法返回一个{value:value, done: boolean}的对象,来定义对象的遍历逻辑

var o = {
  [Symbol.iterator]: function() {
    var self = this;
    var keys = Object.keys(this);
    var idx = 0;
    return {
      next() {
          return {value: self[keys[idx]], done: idx++ >= keys.length } //当done返回true的时候,循环停止
      }
    }
  }
}
o.a = 1;
o.b = 2;
for(let val of o) {
  console.log(val); // 1 2
}

6. 其他

6.1 对象复制

对象复制是一个比较复杂的内容,如果想要实现浅复制可以使用ES6新增加的Object.assign()的方法来进行,但是深复制因为需要考虑的因素很多(例如如果对象出现自引用这种复制该如何进行?),所以对于深复制并没有很好的手段,但是对于一般情况来说,可以使用JSON.parse(JSON.stringfy(obj))的方式来实现一个深复制。

6.2 新特性

对象增加了一些新特性

var o1 = {a: 1};
var o2 = {b: 2};
var o = {o1, o2} // 相当于 var o = {o1: o1 , o2: o2};
var separateO = {...o1, ...o2} // 分离属性,结果为var separateO = {a: 1, b: 2},但目前支持浏览器有限

7. 参考

《你不知道的Javascript(上篇)》
MDN Object initializer
MDN Property accessors
MDN Method definitions
MDN getter
MDN setter
MDN function*

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

推荐阅读更多精彩内容

  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,585评论 18 139
  • 这是一个运营行业,有近十年工作经验的中老司机的书,对于刚刚萌生运营意愿的小鲜肉来说,可以浏览浏览,以下是几个关键词...
    王平钢阅读 511评论 0 1
  • Docker环境搭建redis集群(主从模式) 序 本文将介绍如何在docker中部署redis集群(主从模式)。...
    袁志健阅读 5,351评论 3 2
  • 桃花树下,月半圆,酒微酣。 “干杯~”举着那灌满酒的杯子,连翘朝着天上的月亮敬酒,便咧着嘴将杯中之酒一饮而尽。 喝...
    蘇瑶阅读 654评论 0 2
  • 今天从悬崖村下山,走了两个半小时的山路。 我们先走了非常陡的钢梯,有些地方几乎是垂直90度的,必须手脚并用才行。 ...
    周一秩禾阅读 380评论 4 3