JavaScript的对象7种创建方式(总结)

ES5 创建对象

直接对象字面量
const obj = {
  name: 'dz',
  age: 23
}
使用内置构造函数
const obj = new Object()
obj.name = name
obj.age = age

1.工厂模式

  • 套路: 通过工厂函数动态创建对象并返回
  • 适用场景: 需要创建多个对象
  • 问题: 对象没有一个具体的类型, 都是Object类型
//返回一个对象的函数===>工厂函数
function createPerson(name, age) { 
 var obj = {
   name: name,
   age: age,
   setName: function (name) {
     this.name = name
   }
 }
 return obj
}

// 创建2个人
var p1 = createPerson('Tom', 12)
var p2 = createPerson('Bob', 13)

// p1/p2是Object类型

function createStudent(name, price) {
 var obj = {
   name: name,
   price: price
 }
 return obj
}
var s = createStudent('张三', 12000)
// s也是Object

缺点:

  1. 无法通过constructor识别对象,以为都是来自Object,无法得知来自Person
  2. 每次通过Person创建对象的时候,所有的say方法都是一样的,但是却存储了多次,浪费资源。

2.构造函数模式

  • 套路: 自定义构造函数, 通过new创建对象
  • 适用场景: 需要创建多个类型确定的对象,与上方工厂模式有所对比
  • 问题: 每个对象都有相同的数据, 浪费内存
//定义类型
function Person(name, age) {
 this.name = name
 this.age = age
 this.setName = function (name) {
   this.name = name
 }
}
var p1 = new Person('Tom', 12)
p1.setName('Jack')
console.log(p1.name, p1.age)
console.log(p1 instanceof Person)

function Student (name, price) {
 this.name = name
 this.price = price
}
var s = new Student('Bob', 13000)
console.log(s instanceof Student)

var p2 = new Person('JACK', 23)
console.log(p1, p2)

优点:

  1. 通过constructor或者instanceof可以识别对象实例的类别
  2. 构造函数简化了工厂模式的操作过程, 并且通过实例化对象, 可以知道该对象的标识, 能识别是被哪一个 构造函数 创造的, 使用instanceof 来判断是否属于某个构造函数的实例

缺点:

  1. 多个实例的say方法都是实现一样的效果,但是却存储了很多次(两个对象实例的say方法是不同的,因为存放的地址不同)
认识构造函数

JavaScript中的构造函数是怎么样的?

  • 构造函数也是一个普通的函数,从表现形式来说,和千千万万个普通的函数没有任何区别;
  • 那么如果这么一个普通的函数被使用new操作符来调用了,那么这个函数就称之为是一个构造函数;

3.原型模式

function Person() {}
	Person.prototype.name = 'lisi';
	Person.prototype.say = function() {
  	alert(this.name);
}
Person.prototype.friends = ['xiaofeixa'];
var person1 = new Person();

优点:

  1. say方法是共享的了,所有的实例的say方法都指向同一个。

  2. 可以动态的添加原型对象的方法和属性,并直接反映在对象实例上。

    var person1 = new Person()
    Person.prototype.showFriends = function() {
      console.log(this.friends)
    }
    person1.showFriends()  //['xiaofeixia']
    

缺点:

  1. 出现引用的情况下会出现问题具体见下面代码:

    var person1 = new Person();
    var person2 = new Person();
    person1.friends.push('zhangsan');
    console.log(person2.friends)  //['xiaofeixia', 'zhangsan']
    

    因为js对引用类型的赋值都是将地址存储在变量中,所以person1和person2的friends属性指向的是同一块存储区域。

  2. 第一次调用say方法或者name属性的时候会搜索两次,第一次是在实例上寻找say方法,没有找到就去原型对象(Person.prototype)上找say方法,找到后就会在实例上添加这些方法or属性。

  3. 所有的方法都是共享的,没有办法创建实例自己的属性和方法,也没有办法像构造函数那样传递参数。

  4. 但是有一个大问题就是, 大家都是共享的, 因此每一个实例都可能更改这个原型里面的属性, 后面创建的对象包含的属性会覆盖上次一创建的对象的属性

注意:

  1. 优点②中存在一个问题就是直接通过对象字面量给Person.prototype进行赋值的时候会导致constructor改变,所以需要手动设置,其次就是通过对象字面量给Person.prototype进行赋值,会无法作用在之前创建的对象实例上

    var person1 = new Person()
    Person.prototype = {
    	name: 'Pan',
      	setName: function(name){
          this.name = name
      	}
    }
    
    person1.setName()   //Uncaught TypeError: person1.set is not a function(…)
    

    这是因为对象实例和对象原型直接是通过一个指针链接的,这个指针是一个内部属性[[Prototype]],可以通过__proto__访问。我们通过对象字面量修改了Person.prototype指向的地址,然而对象实例的__proto__,并没有跟着一起更新,所以这就导致,实例还访问着原来的Person.prototype,所以建议不要通过这种方式去改变Person.prototype属性

对于constructor丢失的解决办法:

手动添加

Person.prototype = {
  constructor: Person,
	name: 'Pan',
  setName: function(name){
    this.name = name
  }
}

上面的方式虽然可以, 但是也会造成constructor的[[Enumerable]]特性被设置了true.

  • 默认情况下, 原生的constructor属性是不可枚举的.
  • 如果希望解决这个问题, 就可以使用我们前面介绍的Object.defineProperty()函数了.
Object.defineProperty(Person.prototype, "constructor", {
  enumerable: false;
  value: Person
})

4.构造函数和原型组合模式(组合模式)

  • 套路: 自定义构造函数, 属性在函数中初始化, 方法添加到原型上
  • 适用场景: 需要创建多个类型确定的对象
  • 放在原型上可以节省空间(只需要加载一遍方法)
//在构造函数中只初始化一般函数
function Person(name, age) { 
 this.name = name
 this.age = age
}
Person.prototype.setName = function (name) {
 this.name = name
}

var p1 = new Person('Tom', 23)
var p2 = new Person('Jack', 24)
console.log(p1, p2)

优点:

  1. 解决了原型模式对于引用对象的缺点()
  2. 解决了原型模式没有办法传递参数的缺点
  3. 解决了构造函数模式不能共享方法的缺点

这种方式结合两者的有点, 每个实例拥有自己的属性和方法, 以及共享相同的方法, 用的较多一种模式

5.动态原型模式

function Person(name, age) {
  this.name = name
  this.age  = age
  if(typeof this.sayname != 'function') {
    Person.prototype.sayname = () => {
      console.log(this.name)
    }
  }
}
const p1 = new Person('dz', 23)
console.log(p1.sayname) // -> dz

优点:

  1. 可以在初次调用构造函数的时候就完成原型对象的修改

  2. 修改能体现在所有的实例中

  3. 这里只在sayname 方法不存在的情况下才添加到原型中, 只会在初次调用 构造函数时才会执行.

    这样的代码, 使得每个对象的name、age、sex都是各自的(不共有), 然后函数写在原型上, 就又是共享的.

注意: 使用动态原型模式时, 不能 使用 对象字面量重写原型. 如果在已经创建了实例的情况下重写原型, 那么就会切断现有实例与新原型之间的联系.

6.寄生构造函数模式

function Person(name) {
  var o = new Object()
  o.name = name
  o.say = function() {
    alert(this.name)
  }
  return o
}

var peron1 = new Person('xiaofeixia')

优点:

  1. 和工厂模式基本一样,除了多了个new操作符

缺点:

  1. 和工厂模式一样,不能区分实例的类别,所以如果用 instanceof 操作符来检测的话, 结果只能是 false

7.稳妥构造模式

function Person(name) {
  var o = new Object()
  o.say = function() {
    alert(name)
  }
}

var person1 = new Person('xiaofeixia');
person1.name  // undefined
person1.say() //xiaofeixia

优点:

  1. 安全,name好像成为了私有变量,只能通过say方法去访问

缺点:

  1. 不能区分实例的类别
  2. 即使有其他代码会给这个对象添加方法或属性, 但也不可能有别的办法访问传入到构造函数中的原始数据 .
  3. 和工厂模式一样,不能区分实例的类别,所以如果用 instanceof 操作符来检测的话, 结果只能是 false
  • 3
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
### 回答1: JavaScript对象是用来存储数据和处理数据的一数据类型。对象是由一些键值对组成的,其中键是唯一的字符串,值可以是任意数据类型。 例如,我们可以创建一个表示人的对象,其中包含姓名、年龄和职业信息: ``` const person = { name: 'John', age: 30, job: 'software developer' }; ``` 我们可以访问对象中的值使用点语法或方括号语法: ``` console.log(person.name); // 'John' console.log(person['age']); // 30 ``` 我们还可以给对象增加新的属性或更新现有属性的值: ``` person.location = 'New York'; person.age = 31; ``` JavaScript对象还可以包含方法,即可以在对象内部定义的函数。例如,我们可以为人对象添加一个方法来打印出自我介绍: ``` person.sayHi = function() { console.log(`Hi, my name is ${this.name} and I am ${this.age} years old.`); }; person.sayHi(); // 'Hi, my name is John and I am 31 years old.' ``` JavaScript对象可以通过继承从其他对象中继承属性和方法。这被称为对象的原型链,并且可以使用JavaScript内置的`Object.create()`函数来创建。 例如,我们可以创建一个基本对象,然后从中创建更多特定的对象,继承基 ### 回答2: JavaScript对象是一复合数据类型,用于存储多个相关属性和方法的集合。对象由一对大括号{}表示,其中包含了若干个键值对(properties)。键(key)是一个字符串或者Symbol类型,值(value)可以是任意类型,包括基本数据类型和其他对象对象的属性可以通过两方式访问:点运算符(.)和方括号运算符([])。通过点运算符,可以根据属性名称直接访问对象的属性。例如,obj.name将返回对象obj的名为name的属性值。若属性名称是一个变量、表达式或含有特殊字符,可使用方括号运算符。例如,obj[varName] 将返回obj中varName变量对应属性的值。 对象的方法是对象属性的一特殊类型,它是可以被调用的函数。方法可以通过对象的属性来定义。例如,obj.method = function(){...} 定义了一个名为method的方法。方法可以访问对象的属性,并且使用this关键字引用方法所属的对象。 当通过new关键字创建一个对象时,会使用构造函数来初始化对象的属性和方法。构造函数是一特殊的函数,用于创建对象实例。由构造函数创建对象称为实例。每个对象实例都具有构造函数定义的属性和方法。 JavaScript对象还支持对象的扩展。通过Object.create()方法可以创建一个对象,该对象的原型(prototype)是传递的参数或者null。在ES6中引入了class关键字,可以创建类来定义对象,并使用extends关键字继承其他类的属性和方法。 总结起来,JavaScript对象是一存储多个相关属性和方法的集合。对象通过属性和方法来定义和访问数据。构造函数可以初始化对象的属性和方法,而对象扩展和类机制则提供了更灵活和可扩展的对象创建方式。 ### 回答3: JavaScript对象是一数据类型,用于存储和组织相关数据和功能。它是由一组属性和方法组成的。对象可以通过字面量形式创建,也可以通过构造函数创建对象属性是用键值对表示的,其中键是字符串类型,值可以是任何数据类型,甚至可以是另一个对象。属性值可以通过点操作符或方括号操作符来进行访问和修改。 对象方法是对象属性的一特殊类型,它是一个函数。方法可以通过对象引用和点操作符来调用。方法可以访问和修改对象的属性,也可以执行其他操作。 JavaScript对象是动态的,可以随时添加和删除属性和方法。这使得对象非常灵活,可以根据需要进行扩展和修改。 JavaScript还提供了一些内置对象,如数组、日期和正则表达式对象。这些对象提供了特定类型数据的功能和方法。 对象可以通过原型继承来共享方法和属性。原型是每个对象都具有的一个属性,它指向另一个对象。当访问对象的属性或方法时,如果对象本身没有该属性或方法,JavaScript会沿着原型链一直向上查找,直到找到该属性或方法为止。 通过使用对象,我们可以创建复杂的数据结构,组织和管理相关数据和功能。对象在Web开发中非常常见,常用于处理DOM元素、处理用户输入、发送Ajax请求等。 总结来说,JavaScript对象是一用于存储和组织相关数据和功能的数据类型。对象由属性和方法组成,可以动态地添加和删除属性和方法。对象可以通过原型继承来共享方法和属性,并且在Web开发中非常常用。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

程序媛小y

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值