Skip to content

JavaScript之创建对象的多种方式 #9

@zzyundragon

Description

@zzyundragon

new操作符

使用new操作符后跟Object构造函数

    let person = new Object()
    person.name = 'zyl'
    person.age = 26

对象字面量

对象字面量是对象定义的一种简写形式,目的在于简化创建包含大量属性的对象的过程。

    let person = {
        name: 'zyl',
        age: 26,
        5: true  // 数值属性名会自动转换为字符串
    }

虽然let person1 = {}new Object()相同,但通过对象字面量定义对象时,实际上不会调用Object构造函数(早期版本会调用,Firefox3后不会了)。这是因为字面量法创建对象,强调该对象仅是一个可变的hash映射,而不是从对象中提取的属性嚯方法。现代JS引擎会将{}解析为对象,并把该对象的_proto_指向了Object.prototype

对象字面量语法代码简洁,是向函数传递大量可选参数的首选方式。

访问对象可以通过点表示法,和方括号表示法,当属性名中包含会导致语法错误的字符,或使用了关键字、保留字,也可以使用方括号表示法。

    person['first name'] = 'z' // first name中包含了空格,会导致语法错误

缺点: 使用Object构造函数或对象字面量可以很方便地创建单个对象,但使用同一个接口创建多个具有相同属性和方法的对象时,会产生大量重复代码。为解决这个问题,人们开始使用工厂模式。

工厂模式

    function createPerson(name, age, job) {
        let o = new Object()
        o.name = name
        o.age = age
        o.sayName = () => {
            console.log(this.name)
        }
        return o
    }
    let person1 = createPerson('zyl', 26, 'teacher')
    let person2 = createPerson('zn', 28, 'singer')

缺点:Object构造函数实例的过程封装,虽然解决了创建多个相似对象的问题,但没有解决对象识别的问题,工程模式下所有实例均指向一个原型。

构造函数模式

    function Person(name, age, job) {
        this.name = name
        this.age = age
        this.job = job 
        this.sayName = function () {
            console.log(this.name)
        }
    }
    let person1 = new Pserson('zyl', 26)
    let person2 = new Pserson('zn', 28)

构造函数没有显式地创建对象,直接将属性和方法赋给了this对象,没有return语句。创建Person的实例,必须使用new操作符,以这种方式调用实际上会经历以下四个步骤:

  1. 创建一个新对象
  2. 将构造函数的作用域赋给新对象(因此this指向了新对象)
  3. 执行构造函数中的代码(为新对象添加属性)
  4. 返回新对象

person1person2分别是Person的实例,这两个对象都有一个constructor属性,该属性指向Person。使用instanceof操作符更可靠的检测对象类型。

    console.log(person1 instanceof Person) // true

缺点: 每个方法都要在每个实例上重新创建一遍。函数也是对象,每定义一次函数也就实例化了一个对象。

    this.sayName = new Function('console.log(this.name)') // 与声明函数在逻辑上是等价的
    console.log(person1.sayName == person2.sayName) // false

优化:

function Person(name, age) {
    this.name = name
    this.age = age
    this.sayName = sayName
}
function sayName() {
    console.log(this.name)
}
let person1 = new Person('zyl', 26)
let person2 = new Person('zn', 28)

如此,定义多个全局函数,那自定义的引用类型就丝毫没有封装性可言了。好在这个问题可以通过使用原型模式来解决。

原型模式

Metadata

Metadata

Assignees

No one assigned

    Labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions