1. 语法

对象的创建

  • 声明(文字)形式

    1. var myObj={
    2. key:value
    3. }
  • 构造形式

    1. var myObj = new Object();
    2. myObj.key = value;

2. 类型

简单基本类型
string,number,boolean,null,undefined,symbol
复杂基本类型
object

函数就是对象的一个子类型,本质上和普通对象一样,还有数组之类的

  1. var strPrimitive = "I am a string";
  2. typeof strPrimitive; // "string"
  3. strPrimitive instanceof String; // false
  4. var strObject = new Object("I am a string");
  5. typeof strObject; // "object"
  6. strObject instanceof String; // true

变量strPrimitive只是一个字面量,不是一个对象,是个不可变的值,如果当你要在这个字符串的字面量做一些获取长度,访问某个字符串的时候,它会自动转换成String对象

  • null,undefined没有对应的构造形式,只有文字形式
  • Date只有构造形式
  • Object,Array,Function,RegExp,无论是构造形式和文字形式,都是对象

3.内容

对象的属性赋值和属性访问,可以通过.操作符或者[]操作符

  1. var myObject = {a:2};
  2. myObject.a; //2
  3. myObject["a"]; //2

对象的属性都会被转换到字符串中

3.1 可计算属性名

ES6添加的语法

  1. var prefix = "foo";
  2. var myObject = {
  3. [prefix+"bar"]:"hello",
  4. [prefix+"baz"]:"world"
  5. }
  6. myObject["foobar"];// "hello"
  7. myObject["foobaz"];// "world"

一般这个会配合ES6的符号(Symbol)使用,这个符号可以是用来确定这个属性名的唯一性

3.2 数组

  1. var myArr = ["foo", 42, "bar"];

对于数组来说,属性名的访问是数字
⚠️:如果你试图向数组添加一个属性是“看起来”是个数字,它会默认转化成一个真的数字,然后是变成数组的一个小标

3.3 复制对象

复制一个对象远比想象中来得更加复杂

  1. function anotherFunc(){/*...*/}
  2. var anotherObj = {c:true};
  3. var anotherArr = [];
  4. var myObj = {
  5. a:2,
  6. b:anotherObj, // 引用了,不是复制
  7. c:anotherArr, // 引用了,不是复制
  8. d:anotherFunc // 引用了,不是复制
  9. }

区分浅复制和深复制这两个概念:
浅复制:针对上面代码来看,浅复制myObj就是将一些简单类型的数据直接拷贝,但是复杂类型的还是引用
深复制:无论是简单类型还是复杂类型的数据都进行拷贝

浅拷贝的方法

  • 利用JSON的序列化成字符串的方法

    1. var newObj = JSON.parse(JSON.stringify(someObj));
  • ES6的Object.assign(…),第一个参数是目标对象,之后可以跟一个或者多个源对象,他会遍历后面所有源对象的可枚举的key/value,并把它们复制到目标对象,最后返回目标对象;也是使用=操作符来赋值

    1. var newObj = Object.assign({}, myObj);
    2. newObj.a; //2
    3. newObj.b === anotherObj;// true


    3.4 属性描述符

    1. var myobj={a:2};
    2. Object.getOwnPropertyDescriptor(myobj,"a");
    3. // value: 2
    4. // writable: true
    5. // enumerable: true
    6. // configurable: true

创建普通属性,可以使用,Object.defineProperty(…)

  1. var myObj = {};
  2. Object.defineProperty(myObj, "a",{
  3. value:2,
  4. writable: true, // 决定是否可以修改属性的值
  5. configuable: true, // 决定是否修改属性描述符,改成了false就无法撤回了
  6. enumerable: true // 决定是否可以枚举,例如for...in
  7. })
  8. myObj.a;// 2

3.5 不可变性

当你希望属性或者对象是不可改变的话,有办法,但是现在所有的方法都是浅不变性,只影响一些直接属性,对于复杂类型的引用还是可以改变的

对象常量

  1. // 主要用的是writable和configurable
  2. var myObj = {};
  3. Object.definedProperty(myObj, "NUMBER", {
  4. value:42,
  5. writable:false,
  6. configurable:false
  7. })

禁止扩展

  1. var myObj={};
  2. Object.preventExtensions(myObj); // 禁止扩展
  3. myObj.b = 3; // 非严格模式,undefined;严格模式下会抛出typeError的错误

**
密封

  1. var myObj={
  2. a:2
  3. };
  4. Object.seal(myObj); // 会创建一个“密封”的对象
  5. // 实际是调用了禁止扩展和congfigurable:false


冻结**

  1. Object.freeze() // 会创建一个冻结对象,
  2. // 实际上是使用了密封和writable:false

“深度冻结”一个对象,首先在这个对象上面使用“冻结”Object.freeze,然后遍历它引用的所有对象并在这些对象上调用Object.freeze,要注意的是有可能会无意中冻结了其他(共享)对象

3.6 Getter和Setter

  1. var myObj = {
  2. // 给a定义一个getter
  3. get a(){
  4. return this._a_
  5. }
  6. // 给a定义一个setter
  7. set a(val){
  8. this._a_=val*2
  9. }
  10. }
  11. // 或者
  12. Object.definedProperty(myObj,"a",{
  13. // 设置一个getter
  14. get:function(){return this._a_;},
  15. // 设置一个setter
  16. set:function(){this._a_*2;}
  17. // 确保该属性会在属性列表中
  18. enumerabletrue
  19. });
  20. myObj.a = 2;
  21. myObj.a//4
  22. // 变量_a_只是自己起的惯例,没有任何特殊行为,getter和setter都是成对出现的

3.7 存在性

为了处理访问对象的属性有可能的值是设置成undefined,也有可能这个值不存在而返回undefined

  1. var myObj = {a:2};
  2. ("a" in myObj); // true
  3. ("b" in myObj); // false
  4. myObj.hasOwnProperty("a");// true
  5. myObj.hasOwnProperty("b");// false

in操作符,不仅会检查属性名是否在当前对象里面,而且[prototype]原型链上
hasOwnProperty(…),只会检查属性名是否在当前对象里面

枚举
在对象应用上面👆使用for…in循环,数组的话就使用传统的for循环

  1. var myObj= {};
  2. Object.definedPrototype(myObj, "a",{
  3. // 设置值为2
  4. value:2,
  5. // 设置不可枚举
  6. enumrable: false
  7. })

能够去判断属性是否可枚举的,也是使用for…in遍历每个属性名,或者是Objec.keys(…),会返回一个数组

4. 遍历

ES5有一些数组辅助迭代器

  • forEach(..),会遍历数组中的所有值并忽略回调函数的返回值
  • every(…),会一直运行直到回调函数返回false
  • some(…),会一直运行直到回调函数返回true

every(…)和some(…),有点类似普通for循环的break语句,会提前终止遍历

ES6提供一个可以直接遍历数组的值的循环,for…of

  1. // for...of原理,是使用了@@iterator返回迭代器的函数
  2. var myArr=[1,2,3];
  3. // 使用符号Symbol.iterator来获取对象的@@itrator内部属性
  4. var it = myArr[Symbol.iterator]();
  5. it.next(); // {value:1,done:false}
  6. it.next(); // {value:1,done:false}
  7. it.next(); // {value:1,done:false}
  8. it.next(); // {done:true}
  9. // 和数组不一样,普通对象没有内置的@@iterator,无法自动完成for...of遍历,
  10. // 但是你也可以自己改造普通对象,使用Object.defineProperty(...),添加这个属性