继续浏览精彩内容
慕课网APP
程序员的梦工厂
打开
继续
感谢您的支持,我会继续努力的
赞赏金额会直接到老师账户
将二维码发送给自己后长按识别
微信支付
支付宝支付

JavaScript 系列博客(四)

慕桂英546537
关注TA
已关注
手记 301
粉丝 31
获赞 200

前言

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

概述

生成方法

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

https://img2.mukewang.com/5c1e51b00001d56311260616.jpg

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

https://img1.mukewang.com/5c1e51b70001d37d11360248.jpg

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

键名

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

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

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

对象的引用

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

https://img2.mukewang.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://img2.mukewang.com/5c1e51cb0001cc8c10801170.jpg

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

https://img1.mukewang.com/5c1e51d80001ab3911420586.jpg

判断属性的存在

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

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

拿上面删除的 constructor 来说:

https://img2.mukewang.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  

打开App,阅读手记
0人推荐
发表评论
随时随地看视频慕课网APP