为了账号安全,请及时绑定邮箱和手机立即绑定

JavaScript 系列博客(四)

标签:
JavaScript

前言

本篇介绍 JavaScript 中的对象。在第一篇博客中已经说到 JavaScript 是一种‘’对象模型‘’语言。所以可以这样说,对象是 JavaScript 语言的核心概念,也是最重要的数据类型。

概述

生成方法

在 JavaScript 中声称对象相当方便,直接定义一个空字典就 ok。想要添加属性或者方法的话可以在定义结束之后动态添加。注意:对象时无序的复合数据集合。

https://img1.sycdn.imooc.com//5c1e51b00001d56311260616.jpg

上面代码中,大括号就可以直接定义一个对象,被赋值给变量 a,所以 a 就指向一个对象。该对象为一个空对象,但是会有一些默认的方法,像 constructor 是构造方法,想要动态的添加属性和方法就是这个方法的功劳。

https://img1.sycdn.imooc.com//5c1e51b70001d37d11360248.jpg

在这里添加了一个属性为name,那么 name 是键名(成员名称),字符串 musibii 是键值(成员的值)。键名与键值之间用冒号分隔。如果再添加一个属性,那么属性之间使用逗号分隔。

键名

对象的所有键名都是字符串(ES6又引入了 Symbol 值也可以作为键名:还没了解过),所以加不加引号都可以。如果键名是数值,会被自动转为字符串。如果键名不符合标识名的条件(比如第一个字符为数字,或者含有空格或运算符),且也不是数字,则必须加上引号,否则会报错。

对象的每一个键名又称为‘’属性‘’,它的键值可以是任何数据类型。如果一个属性的值为函数,通常把这个属性称为方法,调用方法和函数一样。

特别的如果属性的值指向的还是一个对象,那么就行成了链式引用。对象的属性之间用逗号分隔,最后一个属性后面可以加逗号,也可以不加。

对象的引用

如果不同的变量名指向同一个对象,那么它们都是这个对象的引用,也就是说指向同一个内存地址。修改其中一个变量,会影响到其他所有的引用。和 JavaScript 中的基本数据类型不一样,复合数据类型是传址传递。

https://img1.sycdn.imooc.com//5c1e51bf0001e00911380512.jpg

a 和 b指向同一个对象,因此为其中任何一个变量添加属性,另一个变脸都可以读写该属性。如果取消某一个对象的引用,不会影响到其他变量。

这种引用只局限于对象,在之前的博客也提到,两个变量指向同一个原始类型(基本数据类型)的值,那么变量只是对值得拷贝(传值传递)。

属性的操作

属性的读取

读取对象的属性,有两种方法,一种是使用点运算符;另一种是使用方括号运算符。(在 python 中,字典只能通过方括号取值;对象只可以通过点运算符取值。不过可以通过自定义字典类改写 getattr 魔术方法改变。)

注意:如果使用方括号运算符,键名必须放在引号里面,否则会被当做变量处理。

var foo = 'bar';var obj = {    foo: 1,    bar: 2};

obj.foo // 1obj[foo]// 2

上面代码中,引用对象obj 的 foo 属性时,如果使用点运算符,foo 就是字符串;如果使用方括号运算符,但是不使用引号,那么 foo 就是一个变量,指向字符串 bar。

方括号运算符内部还可以使用表达式:

obj['hello' + 'world']
obj[3 + 3]

数字键可以不加引号,因为会自动转为字符串。

var obj = {    0.7: 'hello world'};
obj['0.7'] // 'Hello World'obj[0.7] // 'Hello World'

上面代码对象的数字键0.7加不加引号都可以,因为会自动转为字符串。

var obj = {    123: 'Hello musibii'};

obj.123 // 报错obj[123] // 'Hello musibii'

如果对数值键名123使用点运算符,会报错,使用方括号运算符才是正确的方式。

属性的赋值

点运算符和方括号运算符,不仅可以用来读取值,还可以用来赋值。

JavaScript 允许属性的后绑定,也就是说可以在任意时刻新增属性,没必要在定义对象的时候就把属性全都定义好。

属性的查看

查看一个对象的所有属性使用 Object.keys 方法。

var obj = {    key1: 1,    key2: 2};Object.keys(obj); // [key1, key2]

属性的删除

delete 命令用于删除对象的属性,删除成功后返回 true。

var obj = {    p: 1;
}delete obj.p; // trueobj.p // undefinedObject.keys(obj) // []

上述代码中,delete 命令删除对象 obj 的 p 属性。删除后,再读取 p 属性就会返回 undefined,而且 Object.keys 方法的返回值也不再包括该属性。

注意:删除一个不存在的属性,delete 不会报错而是返回 true。因此不能根据 delete 命令的结果认为某个属性的存在。(那么到底哪种方式才可以证明某个属性的存在与否)

如果删除属性时返回 false那就说明该属性存在,但是不可以删除。

var obj = Object.defineProperty({}, 'p', {    value: 'musibii',    configurable: false});

obj.p // 'musibii'delete obj.p // false

上述代码中,通过 Object 的defineProperty方法给对象 obj创建了一个属性,属性的configurable(可配置) 的值为 false,这样的一个属性就是不可以删除的。

另外需要注意的是,delete 命令只能删除对象本身的属性,无法删除继承的属性。

https://img1.sycdn.imooc.com//5c1e51cb0001cc8c10801170.jpg

可以看出虽然 delete 命令返回 true,但是删除的属性依然存在。但是如果通过 proto 删除的话就可以删除。

https://img1.sycdn.imooc.com//5c1e51d80001ab3911420586.jpg

判断属性的存在

in 运算符用于检出对象是否包含某个属性(注意,检查的是键名,不是键值)。如果包含就返回 true,否则就返回 false。它的左边是一个字符串,表示属性名,右边则是一个对象。

var obj = {p: 1};'p' in obj //true'toString' in obj // true

拿上面删除的 constructor 来说:

https://img1.sycdn.imooc.com//5c1e51e00001b63d11400144.jpg

in 运算符的一个问题是,它不能识别哪些属性时对象自身的,哪些属性是继承的。就像上面,对象 obj 本身并没有 toString 属性,但是 in 运算符会返回 true,因为这个属性是继承的。

这时可以通过对象的 hasOwnProperty 方法判断,是否为对象自身属性

var obj = {};if ('toString' in obj) {    console.log(obj.hasOwnProperty('toString')); // fasle}

属性遍历

for...in 循环用来遍历一个对象的所有属性。

for...in 循环有两个注意点;

  • 它遍历的是对象所有可遍历的属性,会跳过不可遍历的属性;

  • 它不仅遍历对象自身的属性,还遍历继承的属性。

如果继承的属性是可遍历的,那么就会被 for...in 循环遍历到。但是,一般情况下,都是只想遍历对象自身的属性,所以使用 for...in 的时候,应该结合使用 hasOwnProperty 方法,在循环内部判断一下,某个属性是否为对象自身的属性。

var person = {name: '老张'};for (var key in person) {    if (person.hasOwnProperty(key)) {        console.log(key);
    }
} // name

with 语句

with 语句的格式如下:

with (对象) {
    语句;
}

它的作用是操作同一个对象的多个属性时,提供一些书写的方便。

注意:如果 with 区块内部有变量的赋值操作,必须是当前对象已经存在的属性,否则会创造一个当前作用域的全局变量。

var obj = {};with (obj) {
    p1 = 4,
    p2 = 5}

obj.p1 // undefinedp1 // 4

上面代码中,对象 obj 并没有 p1属性,对 p1赋值等于创造了一个全局变量 p1.正确的写法应该是,先定义对象 obj 的属性 p1,然后在 with 区块内操作它。

这是因为 with 区块没有改变作用域,它的内部依然是当前作用域。这造成了with 语句的一个很大的弊病,就是绑定对象不明确。

with (obj) {    console.log(x);
}

单纯从上面的代码块,根本无法判断 x 到底是全局变量,还是对象 obj 的一个属性。这非常不利于代码的除错和模块化,编译器也无法对这段代码进行优化,只能留到运行时判断,这就拖慢了运行速度。因此,建议不要使用 with 语句,可以考虑用一个临时变量代替 with。

with (obj1.obj2.obj3) {    console.log(p1 + p2);
}// 可以写为var temp = obj1.obj2.obj3;console.log(temp.p1 + temp.p2);

原文出处:https://www.cnblogs.com/zuanzuan/p/10161642.html  

点击查看更多内容
TA 点赞

若觉得本文不错,就分享一下吧!

评论

作者其他优质文章

正在加载中
  • 推荐
  • 评论
  • 收藏
  • 共同学习,写下你的评论
感谢您的支持,我会继续努力的~
扫码打赏,你说多少就多少
赞赏金额会直接到老师账户
支付方式
打开微信扫一扫,即可进行扫码打赏哦
今天注册有机会得

100积分直接送

付费专栏免费学

大额优惠券免费领

立即参与 放弃机会
意见反馈 帮助中心 APP下载
官方微信

举报

0/150
提交
取消