啃一啃犀牛书--对象(1)

啃一啃犀牛书–对象

本次断更一个星期,真的惭愧。连更两章进行补偿~~

对象定义

对象可以看做是属性的无序集合,每个属性都是一个名/值对。也可以说是可变的键控集合。当然这里要说一下null,这个也是对象,但是跟前面的命名有点差异,这个可以理解为空对象。

创建对象

我们经常使用的创建对象的方法应该是对象直接量(对象字面量):

1
var obj = {};

另一种创建对象的方法就是通过new运算符来进行对象的创建,我们通常也称构造函数:

1
var obj = new Object();

但是在蝴蝶书中,将new运算符划归为糟粕里面了,解释如下:

javascript的new运算符创建一个继承于其运算符的原型的新对象,然后调用该运算符,把新建的对象绑定给this。这给运算数(它应该是一个构造函数)一个机会
在返回给请求者前自定义新创建的对象。

如果你忘记了使用new运算符,你得到的就是一个普通的函数调用,并且this被绑定到全局对象,而不是这个新创建的对象。这意味着当你的函数尝试去初始化新成员属性时
它将会污染全局变量。这是一件非常糟糕的事情。而且既没有编译时警告,也没有运行时警告。

综上来看,其实主要也是自己的错误,但是人总会犯错,想从根源上来解决问题,那就是不用new。(也看个人习惯喽)

1
2
3
4
5
function car(name, type){
this.name = name;
this.type = type;
}
var new = new Car('aodi','small')

我们当然也可以使用Object.create()方法进行对象的创建。
Object.create()接收两个参数,第一个参数是这个对象的原形,第二个参数为可选参数,该参数对象是一组属性与值,该对象的属性名称将是新创建的对象的属性名称。
接下来通过对比的方式来进行解释会更容易理解一点:

1
2
3
4
5
6
7
8
//对象创建
var o = {};
var o = new Object();
var o = Object.create({});
var o = Object.create(Object.prototype);
//以上的定义都是一致的,创建了一个新的对象,该对象可继承原型上的一些方法,比如toString();
var p = Object.create(null);
//通过传入null来创建一个没有原型的对象,原型上的所有方法都不会继承。

属性的查询与设置

这个应该前面有说过,我们可以通过”.”或者”[]”运算符来获取或设置属性的值。在ECMAscript3中,点运算符后的标识符不能是保留字。(ps:我们在命名一些属性的时候,其实从根本上也不建议命名与保留字冲突)
此时我们应使用方括号来进行访问。严格来讲,方括号也是有一点限制的,方括号内的表达式必须返回字符串或者返回一个可以转换为字符串的值。这一点可以很好的解释es6中的属性名表达式。

1
2
3
4
5
var key = 'foo';
var obj = {
[key]:true,
['a'+'bc']: 222
}

这里面的属性名都是用表达式的方式来定义的,它们都遵循上面的规则,返回字符串或者可以转为字符串的值。但是这里一定要注意一点,加入你的属性名的表达式是一个对象,
那么它将返回[object Object]。(对象里面的方法亦可如此)

继承

js对象具有”自有属性”,也有一些属性是从原型对象继承而来的。

假设要查询对象o的属性x,如果o中不存在x,那么将会继续在o的原型对象中查询属性x。如果原型对象中也没有x,但这个原型对象也有原型,那么继续在这个原型对象的原型上执行查询,直到找到x或者查找到一个原型为null的对象为止。
可以看到,对象的原型属性构成了一个”链”(原型链),通过这个”链”可是实现属性的继承。

在js的对象操作中,只有查询属性时才会体会到继承的存在,而设置属性和继承无关。

属性访问错误

我们可能经常看到这样的错误:

1
2
3
var o = undefined;
console.log(o.x);
//Uncaught TypeError: Cannot read property 'x' of undefined

这和如果o存在但是o没有x可是不一样的哦~对于基础的开发中,经常出现的问题可能是在我们获取数据之后,我们来渲染视图的时候出现,
如果后端返回异常,可能就导致我们的js代码报错。这个时候我们可都是要先判断这个对象是否存在的哦~~

删除属性

在前面说运算符的时候已经说过了delete运算符,delete运算符可以删除对象的属性。

检测属性

我们可以通过in运算符、hasOwnpreperty()和propertyIsEnumerable()方法来完成这个工作,或者仅通过属性查询也可以做到这一点。

  • in运算符
1
2
3
4
var obj = {x:1};
"x" in obj; //true,x是o的属性
"y" in obj; //false,y不是o的属性
"toString" in obj; //true,o继承toString
  • hasOwnProperty() 检测给定的名字是否是对象的自有属性,继承属性也会返回false。
1
2
3
4
var o  = {x:1};
o.hasOwnProperty('x'); //true,o有一个自有属性x
o.hasOwnProperty('y'); //false,o不存在属性y
o.hasOwnProperty('toString'); //false,toString是继承属性,并不是自有属性
  • propertyIsEnumerable() 是hasOwnProperty()的增强版,只有检测到是自有属性且这个属性是可枚举性为true时才返回true。(某些内置属性是不可枚举的。通常有js代码创建的属性都是可枚举的)

当然,我们在平时的代码中经常会用是否存在来判断,即检测属性。但是在有些时候并不是非常完美的适用。

1
2
3
4
5
6
7
8
9
var o = {x: 1};
o.x !== undefined; //true
o.y !== undefined; //false
o.toString !== undefined; //true
//如果o中的x的值本身就是undefined的话,上面的检测就变得没有意义了。
//这个时候我们就使用in运算符来区分不存在的属性,和存在但值为undefined的属性。
var o = {x:undefined};
o.x !== undefined; //false
"x" in o ; //true

枚举属性

一般可枚举的属性都是我们通过js代码给对象所赋值的属性,一些内置方法一般为不可枚举。
js本身提供了函数来获取对象的可枚举属性,Object.keys(),返回一个数组,数组内的元素是该对象可枚举的自由属性的集合。

本章先介绍到这里~(ps:后面介绍的getter,setter等,但是平时用的很少,自己先过一遍之后再来分享喽~)