Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

对象

1. 创建对象的 5 种方式

  • 字面量表示法创建

    var Person = {
      name: "Jason",
      age: 21,
    };
    
  • 较高 ES 版本支持变量键,即

    var Name = "name" + "_example";
    var Person = {
      [Name]: "Jason",
      age: 21,
    };
    
  • 内置构造函数创建

    var Person = new Object();
    Person.name = "Jason";
    
    • 也可以通过中括号赋值,因此也支持变量键
      Person["name"] = "Jason";
      
  • 工厂模式创建(本质还是内置构造函数)

    function createPerson(name, age) {
      var o = new Object();
      o.name = name;
      o.age = age;
      return o;
    }
    var person1 = createPerson("Nike", 29);
    
  • 自制构造函数创建

    • 这里就相当于:直接用函数 A,搞个实例 C 当对象
      function Person(name, age) {
        this.name = name;
        this.age = age;
      }
      var person1 = new Person("Nike", 29);
      console.log(person1.name); //Nike
      console.log(person1.__proto__.name); //undefined
      
      • 这里能打印出person1.name,是因为 name 本身就是这个实例的私有属性,而原型上并不存在这个属性
    • 好处: 可用instanceof操作符检测对象具体类型
  • 原型创建

    • 这里相当于:手动改原型,再搞个实例 C 当对象

      function Person() {}
      Person.prototype.name = "Nike";
      Person.prototype.age = 20;
      Person.prototype.eat = function () {
        console.log("eat");
      };
      
      var person1 = new Person();
      console.log(person1.name); //Nike
      console.log(person1.__proto__.name); //Nike
      
      • 这里能打印出person1.name,是通过追溯原型上的属性找到的
    • 好处: 可让所有实例共享其中的属性和方法

2. 检查对象属性

  • in 检查对象中是否含某属性时,如果实例对象中没有但是原型中有,也会返回 true

    console.log("属性" in 对象名);
    
  • 可用hasOwnProperty()方法来检查实例对象自身中是否存在某属性,只有当自身含有时才返回 true

    对象名.hasOwnProperty("属性名");
    
  • 如何列举属性

    • keys 仅返回可遍历的属性
      Object.keys(对象名);
      
    • getOwnPropertyNames 返回可遍历和不可遍历属性
      Object.getOwnPropertyNames(对象名);
      

3. 对象的三种方法

实例方法 instanceFunc

  • 是在构造函数里面添加的:
    const Parent = function () {
      this.instanceFunc = function () {
        console.log("这个是实例方法");
      };
    };
    
  • 只有实例才能访问(每个实例单独有一份)
    const parent = new Parent();
    parent.instanceFunc();
    

原型方法 protoFunc

  • 是在构造函数外面添加的:

    Parent.prototype.protoFunc = function () {
      console.log("这个是原型方法");
    };
    
  • 不仅实例能访问(所有实例共享一份)

  • 而且构造函数本身也能访问

    • 只不过要加.prototype,使其借助原型上访问,并且要用 call 传入 this,在无实例情况下指明 this 内涵
    const parent = new Parent();
    parent.protoFunc();
    Parent.prototype.protoFunc.call();
    

静态方法 staticFunc

  • 是在构造函数外面添加的:
    Parent.staticFunc = function () {
      console.log("这个是静态方法");
    };
    
  • 只有构造函数才能访问(较少用到)
    Parent.staticFunc();
    

4. 属性描述对象

  • 是 js 提供的一个内部数据结构

    • 用来描述一个具体对象的某个属性,控制它的一些行为

    • 比如该属性是否可写、是否可遍历、是否可配置等等

    • 例子

      {
          value: undefined,
          writable: true,
          enumerable: true,
          configurable: true,
          get: undefined,
          set: undefined
      }
      
      • 以上皆为默认值,这 6 个属性称为“元属性”

      • writable 可写

        • 如果设置为 false,则 value 的值不可被重新赋值改变,强改的话严格模式下将报错
        • 但如果 configurable 为 true,那还是可以通过 defineProperty 去内部修改 value 元属性的值来改变
      • enumerable 可遍历

        • 如果设置为 false,则 for...in 循环、Object.keys()中将不会出现该属性,这时候可以借助Object.getOwnPropertyNames()去返回不可遍历的;同时 JSON.stringify 也不会编码该属性
      • configurable 可配置

        • 如果设置为 false,则会阻止改写这个属性描述对象,同时也无法删除该属性,但仍可以改变 value(前提是 writable 为 true),同时也允许 writable 从 true 改为 false(反向不行)
      • get

        • 是一个 getter 函数,没有参数,设置它并提供返回值,将会在取值时触发并返回这个返回值
        • 一旦自行定义了 get,那就不能将 writable 设为 true,也不能定义 value 属性,否则报错
      • set

        • 是一个 setter 函数,设置它,将会在设置值时触发执行
        • 会有一个参数,就是属性的值
  • 如何获得?

    • 使用静态方法:
      Object.getOwnPropertyDescriptor(obj, "key1");
      
      • 第一个参数是 对象 obj
      • 第二个参数是 目标属性值 key1
    • 注意
      • 只能用于自身属性,不能用于继承的
  • 如何修改原有的?

    • 单个修改,使用静态方法:

      Object.defineProperty(obj, "key1", attrObj);
      
      • 第一个参数是 对象 obj
      • 第二个参数是 目标属性值 key1
      • 第三个参数是 新的属性描述对象
      • 如果 obj 为{},那么会返回新的对象,否则在源对象上进行更新
    • 批量修改,使用静态方法:

      Object.definePropertys(obj, {
        key1: attrObj1,
        key2: attrObj2,
      });
      
    • 注意

      • 以上两种修改方法,如果不手动指定可写、可遍历、可配置,那一律默认为 false!!!
  • 如何判断某个属性是否可遍历

    • 使用原型方法
      对象实例.propertyIsEnumerable();
      
      • 只能用于自身属性,对于继承的一律返回 false