对象基础
-
简单类型 :数字、字符串、布尔值、
null、undefined -
对象类型:数组、函数、正则表达式、普通对象等
-
对象特性:
- 可变的键值对集合
- 属性名可为任意字符串(包括空字符串)
- 属性值可为任意类型(除
undefined) -undefined 不能作为属性值,但可以作为检索结果(表示属性不存在) - 无类别(class-free),可动态增删属性,动态增删属性非常灵活,但也容易出错
- 可嵌套其他对象,形成树形或图形结构
-
原型链 :对象可继承另一个对象的属性;- 原型链是继承的唯一机制:没有传统的"类继承",只有对象之间的委托
-
对象可通过2种形式定义:声明形式(即{}创建对象)和构造形式(例:var myObj = new Object(); myObj.key = value;)
一、对象字面量
- 使用
{}创建对象 - 属性名若为合法标识符且非保留字,可省略引号
- 属性名引号可省略的条件:必须是合法标识符(如
last_name)且不是保留字(如class、for)。带连字符first-name必须加引号 - 属性值可以是任意表达式,包括另一个对象字面量
javascript
ini
var empty = {};
var person = {
"first-name": "Jerome",
last_name: "Howard"
};
二、检索(属性访问、键访问)
- 使用
.(要求属性名满足标识符的命名规范)或[](接受任意UTF-8/Unicode字符串作为属性名) .优先于[]:可读性好,但不能用于动态属性名或非法标识符- 访问不存在的属性返回
undefined - 使用
||提供默认值 - javascript
ini
var middle = stooge["middle-name"] || "(none)";
var status = flight.status || "unknown";
- 使用
&&避免访问undefined的属性
三、更新与扩充
- 若属性存在,赋值会更新其值
- 若属性不存在,赋值会扩充对象
- 相同操作,不同结果:属性存在就是"更新",不存在就是"扩充"。无法通过语法区分,需留意属性是否可能来自原型链
javascript
ini
stooge["first-name"] = "Jerome";
flight.status = "overdue";
四、引用
- 对象通过引用传递,不会被拷贝;对象永远不会被隐式拷贝:赋值、传参都是传引用。若需要拷贝,必须手动实现
- 多个变量可指向同一个对象
- 例:a = b = c = {} :三个变量指向同一个对象,不是三个独立空对象
- var a = {} , b = {} , c = {} :三个都引用不同的空对象
javascript
ini
var x = stooge;
x.nickname = "Curly";
var nick = stooge.nickname; // "Curly"
五、原型
- 每个对象都连接到原型对象(通过字面量创建的连接到
Object.prototype) - 可通过
Object.create(或自定义beget)指定原型 - 原型链:检索属性时若对象本身没有,会沿原型链向上查找。原型链检索是"委托"而非"复制"
- 原型关系是动态的:添加属性到原型,所有基于它的对象都能看到,即所有子对象立即"看到"它
- 更新不影响原型:对象自身的修改不会影响其原型
- 常见误解 :修改子对象属性不会影响原型,但修改原型上的引用类型属性(如数组、对象)会影响所有子对象
javascript
ini
var another = Object.create(stooge);
another["first-name"] = "Harry"; // 不改变原型
stooge.profession = "actor";
another.profession; // "actor"
六、反射(检查属性)
- 使用
typeof判断属性类型 - 注意原型链中的属性也会被检索到(如
toString)- 即typeof也会返回原型链上的属性:flight.toString是function,可能不是你预期的数据 - 使用
hasOwnProperty判断是否为对象自身属性(不检查原型链)
javascript
ruby
flight.hasOwnProperty("number"); // true
flight.hasOwnProperty("constructor"); // false
七、枚举(遍历属性)
- 使用
for...in遍历所有可枚举属性(包括原型链上的);会遍历不可枚举属性(如数组的length或原生的toString - 常用过滤:
hasOwnProperty和typeof !== "function" - 过滤的必要性 :不过滤会遍历出原型链上的可枚举属性(如自定义的
toString) - 若需保证顺序,建议使用数组 +
for循环
javascript
ini
var props = ["first-name", "last-name"];
for (var i = 0; i < props.length; i++) {
console.log(props[i] + ": " + another[props[i]]);
}
八、删除属性
- 使用
delete删除对象自身属性(不影响原型链) - 删除后,若原型链上有同名属性,会"浮现"出来
javascript
ini
delete another_stooge.nickname;
\
var obj = Object.create({ x: 1 });
obj.x = 2;
delete obj.x; // 现在 obj.x 的值变回 1(来自原型)
九、减少全局变量污染
- 避免全局变量:只创建一个唯一的全局变量作为容器(命名空间)
- 单全局变量不是万能解 :它仍可能与其他库的单全局变量冲突(如都叫
APP)
javascript
ini
var MYAPP = {};
MYAPP.stooge = { ... };
MYAPP.flight = { ... };
-
优点:
- 减少命名冲突
- 提高代码可读性
- 便于管理应用资源