• JS 对象总结


    对象

    创建对象

    有两种方式:

    • 通过 new 操作符实例化一个对象,再添加属性。
    let person = new Object(); 
    person.name = "孤城浪人"; 
    person.sayName = function() { 
     console.log(this.name); 
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5

    构造函数,若不需要传参,那么在实例化时可以省略后边小括号。这种方式的缺点是每个实例的属性和方法都是新创建的,实例之间无法共享方法和属性。

    function Person() {
      this.name = '孤城浪人';
    }
    const person1 = new Person();
    const person2 = new Person;
    console.log(person1);//Person {name: '孤城浪人'}
    console.log(person2);//Person {name: '孤城浪人'}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    将属性和方法定义再原型对象上就可以共享属性和方法了。

    function Person() {} 
    Person.prototype.name = "孤城浪人"; 
    Person.prototype.age = 29; 
    Person.prototype.sayName = function() { 
     console.log(this.name); 
    }; 
    let person1 = new Person(); 
    person1.sayName(); // "孤城浪人"
    let person2 = new Person(); 
    person2.sayName(); // "孤城浪人"
    console.log(person1.sayName == person2.sayName); // true
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 对象字面量。这种方式更方便。
    let person = { 
     name: "孤城浪人", 
     sayName() { 
     	console.log(this.name); 
     } 
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    属性

    属性分为数据属性和访问器属性。JS 中可以在给对象添加属性时可以通过定义一个描述对象来限制属性的行为,我们不能直接拿到描述对象。

    数据属性

    数据属性就是一个保存数据值的“键”。如下例中name就是属性孤城浪人就是值。

    let person = { 
     name: "孤城浪人" 
    };
    
    • 1
    • 2
    • 3

    描述对象的四个特性:

    • [[Configurable]]:表示属性是否可以通过 delete 删除并重新定义,是否可以修改属性的描述对象,以及是否可以把它改为访问器属性。默认为 true,如前面的例子所示。
    • [[Enumerable]]:表示属性是否可以通过 for-in 循环返回。默认为 true。
    • [[Writable]]:表示属性的值是否可以被修改。默认为 true。
    • [[Value]]:属性实际的值。默认值为 undefined。

    要修改属性的默认特性,就必须使用 Object.defineProperty()方法。这个方法接收 3 个参数:

    • 要给其添加属性的对象。
    • 属性的名称和一个描述符对象。
    • 描述符对象。

    如下例子,person 对象的 name 属性既不能删除(严格模式下会抛出错误)也不能修改值。注意属性一旦被定义为不可配置之后,就不能再变回可配置

    let person = {}; 
    Object.defineProperty(person, "name", { 
     writable: false, 
     Configurable:false,
     value: "孤城浪人" 
    }); 
    console.log(person.name); // "孤城浪人" 
    person.name = "Greg"; 
    console.log(person.name); // "孤城浪人"
    delete person.name;
    console.log(person.name); // "孤城浪人"
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    访问器属性

    访问器属性只能是一个获取(getter)函数或一个设置(setter)函数,这两个函数不是必需的。在读取访问器属性值时,会调用获取函数返回一个有效的值。在写入访问器属性时,会调用设置函数将值设为新值。访问器属性也有 4 个特性描述它们的行为。

    • [[Configurable]]:表示属性是否可以通过 delete 删除并重新定义,是否可以修改属性的描述对象,以及是否可以把它改为数据属性。默认为 true。
    • [[Enumerable]]:表示属性是否可以通过 for-in 循环返回。默认为 true。
    • [[Get]]:获取函数,在读取属性时调用。默认值为 undefined。
    • [[Set]]:设置函数,在写入属性时调用。默认值为 undefined。
      访问器属性是不能直接定义的,必须使用 Object.defineProperty。下面是一个例子:
    let person = { name_: '' };
    Object.defineProperty(person, "name", {
      get() {
        console.log('读取函数');
        return this.name_;
      },
      set(newValue) {
        console.log('设置函数');
        this.name_ = newValue;
      }
    });
    person.name = '孤城浪人';
    console.log(person.name_); 
    console.log(person.name);
    // 设置函数
    // 孤城浪人
    // 读取函数
    // 孤城浪人
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    上边例子中,person 对象中有一个不愿被外部方法访问的name_属性,所以定义了访问器属性 name,通过 name 来间接读取和设置 name_

    获取函数和设置函数是可选的。只定义获取函数那么修改属性会被忽略。在严格模式下,尝试写入只定义了获取函数的属性会抛出错误。只定义设置函数的属性不能读取,非严格模式下读取返回 undefined,严格模式下会抛出错误。

    同时添加多个属性

    由于 Object.defineProperty方法一次只能添加一个属性,当需要添加多个属性时就会变得很麻烦,因此有了 Object.defineProperties方法,可以一次添加多个属性。它接收两个参数:

    • 添加或修改属性的对象
    • 描述符对象,其属性与要添加或修改的属性一一对应。

    如下例:

    let person = {};
    Object.defineProperties(person, {
      name_: {
        value: 'WPF'
      },
      age: {
        value: 22
      },
      name: {
        get() {
          console.log('读取函数');
          return this.name_;
        },
        set(newValue) {
          console.log('设置函数');
          this.name_ = newValue;
        }
      }
    })
    person.name = '孤城浪人';
    console.log(person.name_);
    console.log(person.name);
    console.log(person.age);
    // 设置函数
    // WPF
    // 读取函数
    // WPF
    // 22
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28

    注意:数据属性的 configurable、enumerable 和 writable 特性值都是 false。 所以在上边例子中可以看到修改 person.name 并没有成功。

    获取属性的描述对象

    前边说过了我们不能直接在 JS 中拿到属性的描述对象,但是我们可以通过 JS 提供的Object.getOwnPropertyDescriptor方法拿到属性的描述对象。

    let person = {};
    Object.defineProperty(person, 'name', {
      writable: false,
      value: '孤城浪人'
    })
    console.log(Object.getOwnPropertyDescriptor(person, 'name'));
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    在这里插入图片描述

    同时获取多个属性的描述对象

    若想获取多个属性的描述对象Object.getOwnPropertyDescriptor方法就没那么方便了,所以 ECMAScript 2017 新增了 Object.getOwnPropertyDescriptors 方法,接收一个参数:需要查询的对象。这个方法实际上会在每个属性上调用Object.getOwnPropertyDescriptor并在一个新对象中返回它们。如下例

    let person = {};
    Object.defineProperties(person, {
      name_: {
        value: 'WPF'
      },
      age: {
        value: 22
      },
    })
    console.log(Object.getOwnPropertyDescriptors(person));
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    在这里插入图片描述

    合并对象

    把源对象所有的本地属性一起复制到目标对象上,这种操作也叫“混入”(mixin)。

    Object.assign方法接收一个目标对象和一个或多个源对象作为参数,将每个源对象中可枚举属性和自有属性浅复制到目标对象。符合条件的属性,本方法会使用源对象上的 [[Get]] 取得属性的值,然后使用目标对象上的 [[Set]] 设置属性的值。

    如果多个源对象有相同的属性,则后面的会覆盖前面的值。不能在两个对象间转移获取函数和设置函数。

    如下例就会调用 person 的 get 访问器属性并会调用目标对象 person1 的同名 set 访问器属性。且通过打印结果可以看到目标对象上并没有叫 name 的 get 访问器属性。

    const person1 = {
      set name(val) {
        console.log(`set执行,拿到 ${val}`);
      }
    };
    const person = {
      get name() {
        console.log('get执行');
        return 'foo';
      }
    };
    Object.assign(person1, person);
    console.log(person1)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    在这里插入图片描述
    注意:如果赋值期间出错,则操作会中止并退出,同时抛出错误。所以可能只会完成部分属性的复制。

    const person1 = {};
    const person = {
      age: 22,
      get name() {
        throw Error('出错啦!')
      },
      sex: 'man'
    };
    try {
      Object.assign(person1, person);
    } catch (error) {
      console.log(error)
    }
    console.log(person1)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    在这里插入图片描述

    对象语法增强

    Object.is

    接收两个参数,判断两个参数是否相同,很像 ===

    console.log(Object.is(+0, -0)); // false 
    console.log(Object.is(+0, 0)); // true 
    console.log(Object.is(-0, 0)); // false 
    console.log(Object.is(NaN, NaN)); // true
    
    • 1
    • 2
    • 3
    • 4

    属性值简写

    属性名和变量名是一样可以,只要在对象中使用变量名即可,若未找到同名变量则会报错。

    let name = '孤城浪人';
    let age = 22;
    let person = {
      name,
      age
    }
    console.log(person);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    可计算属性

    可计算属性可以在对象字面量中完成动态属性赋值,中括号中的内容会被当作 JavaScript 表达式求值。

    注意:如果表达式抛出错误,那么之前完成的计算是不能回滚的

    let myName = 'name';
    function getAge() {
      return 'age';
    }
    let person = {
      [myName]: '孤城浪人',
      [getAge()]: 22
    }
    console.log(person);//{name: '孤城浪人', age: 22}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    in

    in 操作符会在可以通过对象访问指定属性时返回 true,无论该属性是在实例上还是在原型上。

    function Person() {
      this.name = '孤城浪人';
    }
    Person.prototype.age = 22;
    const person1 = new Person;
    console.log("name" in person1);//true
    console.log("age" in person1);//true
    console.log(person1.hasOwnProperty('name'));//true
    console.log(person1.hasOwnProperty('age'));//false
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    对象的迭代

    Object.values & Object.entries

    ECMAScript 2017 新增两个静态方法Object.valuesObject.entries接收一个对象作为参数,返回它们内容的数组。Object.values返回对象值的数组Object.entries返回键/值对的数组

    function Person() {
      this.name = '孤城浪人';
      this.age = 22;
    }
    const person = new Person;
    console.log(Object.values(person));
    console.log(Object.entries(person));
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    在这里插入图片描述
    注意,非字符串属性会被转换为字符串输出。并且这两个方法对对象属性是浅复制:

    Object.keys & for in

    Object.keys接收一个对象作为参数,返回包含该对象所有可枚举属性名称的字符串数组,该字符串数组不包含原型对象上的可枚举属性。for in迭代该对象和原型对象上的所有可枚举属性名称。

    function Person() {
      this.name = '孤城浪人';
      this.age = 22;
    }
    Person.prototype.sex = 'man';
    const person = new Person;
    console.log(Object.keys(person));//['name', 'age']
    for (let key in person) {
      console.log(key + ':' + person[key]);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    在这里插入图片描述
    注意:for-in 循环和 Object.keys的枚举顺序是不确定的,取决于 JS 引擎,可能因浏览器而异。

    我是孤城浪人,一名正在前端路上摸爬滚打的菜鸟,欢迎你的关注。

  • 相关阅读:
    Bootstrap Blazor 开源UI库介绍-Table 虚拟滚动行
    asp.net酒店管理系统VS开发sqlserver数据库web结构c#编程Microsoft Visual Studio
    丢失vcruntime140_1.dll怎么解决,vcruntime140_1.dll怎么安装?
    docker和虚拟机的异同
    mybatis-plus学习笔记
    JS高阶:深入理解数据、变量、内存
    傅里叶在图像中的应用FFT算法---fft实战应用案例
    三、NFS服务 - 多机器数据共享
    【小程序】微信公众号模板消息跳转小程序发送失败:errcode=40013 , errmsg=invalid appid rid:...
    spring boot中的标注@Component、@Service等
  • 原文地址:https://blog.csdn.net/weixin_46015333/article/details/127855351