你不知道的JavaScript(上卷):第三章:对象
一:这一章到底在说什么?
详细介绍对象。
- 语法
- 类型
- 内容
- 可计算属性
- 属性和方法
- 数组
- 复制对象
- 属性描述符
- 不变性
- [Get]
- [Put]
- Getter和Setter
- 存在性
- 遍历
二:作者具体说了什么,怎么说的?
3.1:语法
创建对象的两种方式:声明形式和构造形式。
声明形式:
Var myObject = {
key: value,
// ….
}
构造形式:
Var myObj = new Object();
myObj.key = value
两种形式的区别:
- 声明形式可以添加多个键/值对(一般也都是这种方式创建对象)
- 构造形式必须逐个添加属性
3.2: 类型
对象是JavaScript的基础,其中有一些对象子类型,被称为内置对象。如下:
- String
- Number
- Boolean
- Object
- Function
- Array
- Date
- RegExp
- Error
这些内置对象很像其他语言中的type或class,但是实际上只是一些内置函数。这些内置函数可以当作构造函数来使用,从而构造出一个对应子类型的新对象。比如:
Var strObject = new String(“i am a stirng”)
Typeof strObject; // object
3.3: 内容
3.3.1:可计算属性名
可以在文字形式中使用[]包括一个表达式当作属性名
代码如下:
var preFix = “foo”;
var myObject = {
[preFix + “bar”]: “hello”,
[preFix + “baz”]: “world”
};
myObject[“foobar”]; // hello
myObject[“foobaz”]; // world
可计算属性命最常用的场景可能是es6的符号(Symbol) ,这是一种新的基础数据类型,包含一个不透明且无法预测的值。比如:
var mySymbol = {
[Symbol.SomeName]: “hello world”
};
3.3.2 属性与方法
3.3.3: 数组
数组其实也是对象的一种,你可以给数组添加属性,但是不推荐这么用。
比如:
var myArr = [“foo”, 3, “bar”]
myArr.baz = “baz”;
myArr.length; // 3
myArr.baz; // baz
3.3.4: 复制对象
会有深复制、浅复制的区别,同时JSON.toString方法。
3.3.5:属性表述符
对象属性对应的属性描述符。比如
var myObject = {
a: 2
}
Object.defineProperty(myObject, “a”, {
value: 2,
writable: true, //是否可以修改属性的值
configurable: true, // 是否可配置
enumerable: true //是否出现在for…in等枚举中
})
3.3.6:不变性
举个例子:我不想让myArr.first的值发生变化,有哪几种方式?
myArr.first; // [1,2,3]
myArr.first.push(4);
myArr.first; // [1,2,3,4]
- 对象常量:结合 writeable:false和configurable:false设置
- 禁止拓展:Object.preventExtensions(myArr.first)
- 密封:Object.seal(myArr.first); 该方法会创建一个密封的对象,这个方法实际上会在一个现有对象上调用Object.preventExtensions并把所有现有属性编辑位configurable:false
- 冻结:Object.freeze(…):该方法会创建一个冻结对象,这歌方法会在现有对象上调用Object.seal(…)并把所有数据访问属性标记为writeable:false
3.3.7 [Get]
看如下代码:
var myObject = {
a: undefined
}
myObject.a; // undefined
myObject.b; // undefined
myObject.a 实际上执行了[get]操作(有点像函数调用:[get])。对象内置的[get] 操作首先在对象中查找是否有名称相同的属性,如果找到就会返回这个值。
而像myObject.b没有找到的话,会执行另一个种非常重要的行为。(即原型链)。尽管myObject.a和myObject.b 都返回了undefined ,但是实际上底层的[get]对object.b进行了更复杂的处理。
3.3.8: 【Put】
【Put】被触发时,实际的行为取决于许多对象,包括对象中是否已经存在这个属性。
如果已经存在这个属性,会检查以下内容:
- 属性是否是访问描述符?如果是并且存在setter就调用setter
- 属性的数据描述符中writable 是否是false?如果是,在非严格模式下静默失败,在严格模式下抛出TypeError异常。
- 如果都不是,将该值设置为属性的值。
3.3.9 Getter和Setter
分别可以控制属性值的设置和获取。
3.3.10存在性
我们可以在不访问属性值的情况下判断对象中是否存在这个属性。
var myObecjt = {
a: 2
}
myObject.hasOwnProperty(“a”); // true
myObject.hasOwnProperty(“b”); // false
3.4: 遍历
有几种遍历的方式呢?
- fo…in :用了遍历对象的可枚举属性列表(包含Prototype链)
- forEach(…):会遍历数组中的所有值并忽略回调函数的返回值。
- every(…):一直运行直到回调函数返回false
- some(…):一直运行直到回调函数返回true
- for…of: 首先会访问被访问对象请求一个迭代器对象,然后通过调用迭代器对象的next()方法来遍历所有返回值。
var myArray = [1, 2, 3];
var it = myArray[Symbol.iterator]();
it.next(); // {value:1, done: false}
it.next(); // {value:2, done: false}
it.next(); // {value:3, done: false}
it.next(); // {done: true}
三:这一章跟你有什么关系?
对象的全面解析,是js语言的重点啊,熟悉底层原理是很重要的。
四:本章小结:
- Js中的对象有字面形式(var a = {…})和构造形式(var a = new Array(…))。字面形式更常用,不过有时构造形式可以提供更多选项。
- 许多人都认为“JavaScript 中万物都是对象”,这是错误的。对象是6个基础类型之一。对象有包括function在内的子类型,不同子类型具有不同的行为,比如内部标签[object Array ]表示这是对象的子类型数组。
- 对象就是键/值 对 的集合,可以通过.propName或者 [“propName”]语法来获取属性值。访问属性时,引擎实际上会调用内部的默认[Get]操作,[Get]操作会检查对象本身是否包含这个属性,如果没找到的话还会查找[Prototype]链
- 属性的特性可以通过属性描述符来控制,比如writable和configurable.此外,可以使用Object.preventExtensions(…) \ Object.seal(…) \ Object.freeze(…)来设置对象的不可变性级别。
- 属性不一定包含值—它们可能是具备getter/setter 的“访问描述符”。此外,属性可以时可枚举或者不可枚举的,这决定了它们是否会出现在for…in循环中。
- 你可以使用for…of语法来遍历数据结构(数组、对象,等等)中的值,for…of会寻找内置或自定义的@@iterator对象并调用它的 next()方法来遍历数据值。