Advertisement

你认识JS对象吗?

阅读量:

文章摘要
对象是JavaScript中包含数据和方法的集合,通常由属性和方法组成。根据ECMA-262定义,对象是属性的无序集合,每个属性或方法由名称映射到值。创建对象的方法包括:
new操作符和Object构造函数:语法为let person = new Object();,适用于简单场景,但每次创建都需要重复代码。
对象字面量:语法为let person = {};,简化了语法,但需手动添加属性和方法。
工厂模式:通过函数创建特定对象,解决重复创建问题,但未解决对象标识问题。
构造函数模式:通过定义属性和方法,确保实例化为特定类型,但构造函数内部的函数会被多次创建,导致同名函数不相等。
每种方法都有其适用场景,但均存在不足,后续内容将介绍更全面的解决方案。

文章目录

根据ECMA-262标准,对象被定义为属性的无序集合。这表明对象仅包含一组无序的值。每个属性或方法都通过一个==名称==来标识,这个==名称==映射到一个==值==。

  • 🔰 总结

前言

注意:本篇内容需要你熟悉几个常见的概念,请看上篇 《写在初识对象前!!》


一、对象是什么?

对象可以被视为一个包含数据和操作的集合体,由一组字段和操作组成,在编程中,我们通常将对象的属性和方法称为对象的属性和方法。

按照ECMA-262的规定,对象被定义为属性的无序集合。从严格意义上说,这意味着对象就是一组没有特定顺序的值。每个属性或方法都通过名称来标识,这个名称映射到一个值。每个属性或方法都通过名称来标识,这个名称映射到一个值。

二、创建对象的方法

🌴 1. 使用 new 操作符和 Object 构造函数

🚩 语法:let person = new Object();

例如:

复制代码
    // new 操作符跟 Object 构造函数
    let person = new Object(); // 与 let person = {} 相同
     person.name = "袁华";
     person.age = 29;
     person.sayName = function () {
       console.log(`你好!我是 ${this.name}。`);
    };

早期JavaScript 开发者普遍倾向于使用 new Object() 这一机制来创建对象。然而,由于每次调用都需要明确写出 new Object(),这种做法显得繁琐。幸运的是,随着技术的发展,对象字面量逐渐演变为一种更简洁的表示方式。值得注意的是,这种简化的表示方法实际上是一种 语法糖,即 new Object() 的高级封装形式。

🌴 2. 对象字面量(object literal)表示法

对象字面量是一种简写方式,其主要目的是简化创建包含大量属性的对象的过程。对象字面量由一对大括号{ }包裹起来,包含键值对的集合。

🚩 语法:let person = {};

例如:

复制代码
    // 对象字面量 (object literal)
    let person = {
      name: ["夏洛", "马冬梅"],
      age: 32,
      bio() {
    console.log(`${this.name[0]} 和 ${this.name[1]} 现在 ${this.age} 岁了。`);
      },
      introduceSelf() {
    console.log(`你好!我是 ${this.name[0]}。`);
      },
    };

person对象中的属性值可以是任意类型的数据,其中包含一个数字、一个数组以及两个操作项。前两项属于对象的属性,而后面两项属于对象的方法。

不足

实际上,尽管前面介绍了两种创建 Object 实例的方法,但开发者更倾向于使用对象字面量表示法。这得益于对象字面量代码简洁,同时能够更直观地体现封装所有相关数据的特点。

因为上面介绍的 2种方式 都存在明显的不足,所以新的模式由此产生,即:工厂模式 。

🍄 3. 工厂模式

工厂模式是一种广为人知的设计模式,在软件工程领域中得到了广泛应用,用于抽象地创建特定对象的过程。

下面的例子展示了一种【用函数来封装以特定接口】创建对象的方式:

复制代码
    function createPerson(name, age) {
      let obj = new Object();
      obj.name = name;
      obj.age = age;
      obj.sayName = function () {
    console.log(`你好!我是 ${this.name}。`);
      };
      return obj;
    }
    let person1 = createPerson("夏洛", 32);
    let person2 = createPerson("马冬梅", 30);

在这里,函数 createPerson() 接受两个参数,基于这些参数生成了一个包含Person信息的对象。通过使用不同的参数组合,可以多次调用该函数,每次调用都会返回一个包含两个属性和一个方法的对象。

该工厂模式虽然能够处理创建多个类似对象的问题,但未能解决对象标识问题,即新创建的对象属于何种类型。

于是,随着 JavaScript 的发展,由一个新模式出现了 - - > 构造函数模式

🍄 4. 构造函数模式

ECMAScript 中的构造函数是用于创建特定类型对象的。像 ObjectArray 这样的原生构造函数 ,运行时可以直接在执行环境中使用。
当然也可以自定义构造函数,以函数的形式为自己的对象类型定义 属性方法
比如,上一个例子使用构造函数模式可以这样写:

复制代码
    function Person(name, age) {
      this.name = name;
      this.age = age;
      this.sayName = function () {
    console.log(`你好!我是 ${this.name}。`);
      };
    }
    let person1 = new Person("夏洛", 32);
    let person2 = new Person("马冬梅", 30);
    person1.sayName(); // 你好!我是 夏洛。
    person2.sayName(); // 你好!我是 马冬梅。

在本例中,Person() 构造函数 替代了 createPerson()工厂函数 。值得注意的是,Person() 内部的代码基本上一致于 createPerson() ,但存在一些差异。

🔸 没有显式地创建对象。
🔸 属性方法 直接赋值给了 this。
🔸 没有 return。

Person的首字母大写了,按照惯例,构造函数名称的首字母通常大写,而非构造函数则以小写字母开头——(行业规范)这样有助于在ECMAScript中区分构造函数和普通函数。

为创建 Person 实例 ,应采用 new 操作符 。该方法将执行以下操作:( **new 的作用是什么?????)

💥💥💥 重要:
1️⃣ 生成一个新的对象到内存中。
2️⃣ 该新对象的 prototype 属性被设置为构造函数的 prototype 属性。
3️⃣ 在构造函数内部,this 指针指向该新对象。
4️⃣ 运行构造函数内部的代码以添加对象属性。
5️⃣ 如果构造函数返回非空对象,则返回该对象;否则,返回刚生成的新对象。

person1和person2各自存储了不同实例的Person对象,每个对象都具有一个**constructor属性**指向Person类。

复制代码
    console.log(person1.constructor == Person); // true 
    console.log(person2.constructor == Person); // true

constructor 本来是用于标识对象类型的。不过,普遍认为 instanceof 操作符 是确定对象类型更可靠的方式。前面例子中的每个对象都是 Object 的实例,同时也是 Person 的实例,如下调用 instanceof 操作符 的结果表明:

复制代码
    console.log(person1 instanceof Object); // true 
    console.log(person1 instanceof Person); // true 
    
    console.log(person2 instanceof Object); // true 
    console.log(person2 instanceof Person); // true

定义自定义构造函数【确保实例被明确标识为特定类型

尽管构造函数具有一定的价值,但它们也存在一些问题。其主要问题在于,每次定义方法都会在每个实例上创建一次。因此,在前面的例子中,person1和person2都拥有名为sayName()的方法,但这些方法并非同一个Function实例。我们都知道,在ECMAScript中,函数被视为对象,因此每次定义函数都会初始化一个新的对象。

复制代码
    function Person(name, age) {
      this.name = name;
      this.age = age;
      this.sayName = new Function( "console.log(`你好!我是 ${this.name}。`)" ); // 逻辑等价
    }
    let person1 = new Person("夏洛", 32);
    let person2 = new Person("马冬梅", 30);
    person1.sayName(); // 你好!我是 夏洛。
    person2.sayName(); // 你好!我是 马冬梅。

明明是做的同一件事情,不同实例上的 函数虽然同名却不相等 ,如下所示:

复制代码
    console.log(person1.sayName == person2.sayName); // false

看到这里是不是跟这个表情包一样?

在这里插入图片描述

列举了诸多方式,各自存在不足,那是否有一种方式能够包容所有不足呢?

答案: 肯定有了啊,程序员的智慧可是无止境的,哪里不足补哪里~~,静待更新。。。


🔰 总结

🎉🎉:知其然,才能知其所以然。不想再做搬运工,后续会持续更新~~

全部评论 (0)

还没有任何评论哟~