有道是,万物皆对象。
创建对象的几种方式
1.字面量创建
let obj = {name:"张三"}
优点:
- 简洁明了:使用字面量创建对象可以直观地展示对象的结构和属性,代码可读性较高。
- 快速创建:字面量创建对象不需要通过构造函数或者
new关键字来创建,直接使用花括号定义对象即可,省去了额外的步骤和代码。 - 可以直接添加和修改属性:使用字面量创建的对象可以直接通过点语法或者方括号语法来添加、修改、删除属性,非常方便。
缺点:
- 无法实现对象的复用:每次使用字面量创建对象时,都会创建一个新的对象,无法实现对象的复用,如果需要创建多个相同结构的对象,会造成冗余的代码。
- 无法继承其他对象的属性和方法:字面量创建对象无法继承其他对象的属性和方法,如果需要实现对象的继承,需要通过其他方式,如构造函数、类等。
2自定义对象 new Object()
let obj = new Object()
obj.name='张三'
优点:
- 灵活性:使用
new Object()创建对象可以灵活地添加和修改属性,可以根据需要动态地定义对象的结构和属性。 - 可以继承其他对象的属性和方法:通过
new Object()创建的对象可以通过原型链继承其他对象的属性和方法,实现对象的复用和继承。
缺点:
- 冗余的代码:使用
new Object()创建对象时,需要通过构造函数和new关键字来创建对象,需要额外的代码和步骤,相对于字面量创建对象来说,代码较为冗余。 - 不够直观:相比于字面量创建对象,使用
new Object()创建对象的方式不够直观,不够清晰地展示对象的结构和属性,可读性较差。
3.工厂模式
function chuangjian(name, age) {
var obj = new Object();
obj.name = name;
obj.age = age;
return obj;
}
var aa = chuangjian('张三', 23);
优点:
- 封装性:工厂模式函数将对象的创建过程封装在一个函数中,使得代码更加模块化和可维护,提高了代码的可读性和可复用性。
- 灵活性:通过工厂模式函数创建对象时,可以根据需要动态地调整创建对象的过程,可以根据传入的参数不同返回不同的对象。
- 可以实现对象的复用:工厂模式函数可以创建多个相同结构的对象,实现对象的复用,避免了重复的代码。
缺点:
- 无法继承其他对象的属性和方法:工厂模式函数创建的对象无法继承其他对象的属性和方法,每次创建对象都是独立的,无法实现对象的继承。
- 对象标识不明确:由于每次创建的对象都是通过工厂模式函数来创建的,对象的标识不明确,无法直观地看出对象的类型和结构。
4.构造函数
function Persou(name, age) {
this.age = age
this.say=function(){}
}
var aa = new Persou('张三', 12);
优点:
- 可以实现对象的继承:通过在构造函数中使用
this关键字来定义对象的属性和方法,可以通过原型链继承其他对象的属性和方法,实现对象的复用和继承。 - 对象标识明确:通过构造函数创建的对象具有明确的标识,可以直观地看出对象的类型和结构。
- 可以传递参数:构造函数可以接收参数,根据传入的参数不同,可以动态地创建不同的对象。
缺点:
- 无法实现对象的复用:每次通过构造函数创建对象时,都会创建一个新的对象,无法实现对象的复用,可能会导致内存的浪费。
- 对象的方法重复定义:通过构造函数创建的对象,每个对象都会有一份独立的方法定义,可能会导致内存的浪费。
5.通过原型
function Ren(name,age){
}
Ren.prototype.name='小明';
Ren.prototype.asy=function(){};
var xm= new Ren()
优点:
- 实现对象的复用:通过原型创建的对象可以共享原型上的属性和方法,避免了重复定义和内存的浪费,实现了对象的复用。
- 对象的方法共享:通过原型创建的对象,每个对象都共享一份原型上的方法定义,节省了内存空间。
- 可以动态地添加和修改对象的属性和方法:通过修改原型上的属性和方法,可以动态地为已创建的对象添加和修改属性和方法。
缺点:
- 对象标识不明确:通过原型创建的对象,无法直观地看出对象的类型和结构,对象的标识不明确。
- 对象的属性共享:通过原型创建的对象,每个对象都共享一份原型上的属性,如果某个对象修改了原型上的属性,会影响到其他对象。
6.混合模式
function Ren(name,age){
this.name=name;
this.age=age;
}
Ren.prototype.asy=function(){};
var xm= new Ren('小明',12)
优点:
- 实现对象的复用和继承:通过原型链继承其他对象的方法,可以实现对象的复用和继承。
- 对象标识明确:通过构造函数创建的对象具有明确的标识,可以直观地看出对象的类型和结构。
- 可以传递参数:构造函数可以接收参数,根据传入的参数不同,可以动态地创建不同的对象。
缺点:
- 对象的方法重复定义:通过混合模式创建的对象,每个对象都会有一份独立的方法定义,可能会导致内存的浪费。
- 原型链继承的缺点:通过原型链继承其他对象的方法,可能会导致对象属性的共享和修改的影响。
7.动态混合模式
function Person(name, age, no) {
this.no = no;
this.name = name
this.age = age;
console.log(typeof this.say);
//方法
if (typeof this.say != 'function') {
Person.prototype.say = function () {
console.log(this.name + " 哈哈哈");
}
}
}
var p1 = new Person("张三", 55, '001')
var p2 = new Person("李四", 56, '002')
优点:
- 灵活性高:动态混合模式可以根据需要在运行时动态地添加和修改对象的属性和方法,使得对象的结构和行为可以灵活地调整和扩展。
- 可以实现对象的复用和继承:通过将已有的对象作为基础,动态地添加新的属性和方法,可以实现对象的复用和继承。
缺点:
- 对象标识不明确:由于动态混合模式是在运行时动态地添加属性和方法,因此对象的标识可能不明确,难以直观地看出对象的类型和结构。
- 可能导致命名冲突:在动态混合模式中,如果不注意命名的唯一性,可能会导致属性和方法的命名冲突,影响对象的正常使用。
8.Object.create()
const person = {
age: 15,
fn: function () {
console.log(`姓名:${this.name},年龄:${this.age}`); //姓名:张三,年龄:15
},
};
const me = Object.create(person,);
me.name = '张三';
me.fn();
//参数
Object.create(proto)
Object.create(proto, propertiesObject)
//proto(必选) 新创建对象的原型对象。
//propertiesObject (可选) 用于定义新创建对象的属性和属性描述符。它是一个可选的参数,可以是一个对象,用于定义新对象的属性和属性描述符。
//value:属性的值,默认为 undefined。
//writable:属性是否可写,默认为 false。
//enumerable:属性是否可枚举,默认为 false。
//configurable:属性是否可配置,默认为 false。
//例如:
const obj = Object.create({}, {
name: {
value: '张三',
writable: true,
enumerable: true,
configurable: true
},
age: {
value: 30,
writable: true,
enumerable: true,
configurable: true
}
});
优点:
- 实现对象的继承:通过指定一个对象作为原型,新创建的对象可以继承原型对象的属性和方法,实现对象的继承。
- 对象的属性和方法可以动态修改:由于新创建的对象是基于原型对象创建的,可以动态地修改原型对象的属性和方法,从而影响到所有继承自该原型对象的对象。
缺点:
- 对象的标识不明确:通过Object.create()创建的对象,没有明确的标识和类型,难以直观地看出对象的结构和关系。
- 对象属性的共享:由于新创建的对象是基于原型对象创建的,如果修改了原型对象的属性,会影响到所有继承自该原型对象的对象,可能会导致对象属性的共享和修改的影响。
区别
字面量创建 和 new 关键字创建
字面量和new Object()都会继承原型上的属性和方法。
let obj = {}
obj.__proto__ == Object.prototype
let obj2 = new Object()
obj.__proto__ == obj2.__proto__ //true
- 语法:let obj = {} 是使用对象字面量语法直接创建一个空对象;new Object() 是通过 Object 构造函数创建一个空对象。
- 原型链:let obj = {} 创建的对象的原型是 Object.prototype;new Object() 创建的对象的原型是 Object.prototype 的实例。
- 方便性:let obj = {} 更加简洁和方便,不需要使用构造函数和关键字 new,直接使用对象字面量即可创建对象;new Object() 需要使用构造函数和关键字 new,相对来说更繁琐一些。
- 执行效率:let obj = {} 的执行效率通常比 new Object() 更高,因为{} 是 JavaScript 解释器内置的语法,不需要调用构造函数。
new Object() 和 Object.create(proto)
new操作生成新对象时,后面的Object()直接是构造函数
let obj = new Object()
obj.__proto__=== Object.prototype
使用create(proto)方法时,参数是一个原型对象,就还没有构造函数。
let obj = Object.create({name:"张三"})
obj.__proto__ === Object.prototype //false
obj.__proto__.__proto__ === Object.prototype //true
console.log(obj1) //{}
console.log(obj1.__proto__) //{name:"张三"}
- 语法:new Object() 是通过构造函数 Object() 创建一个新对象;Object.create(proto) 是通过静态方法 Object.create() 创建一个新对象,并将 proto 参数作为新对象的原型。
- 原型链:new Object() 创建的对象的原型是 Object.prototype;Object.create(proto) 创建的对象的原型是 proto。
- 属性和方法:new Object() 创建的对象没有继承任何属性和方法,需要手动添加;Object.create(proto) 创建的对象继承了 proto 对象的属性和方法。
- 参数:new Object() 不接受参数;Object.create(proto) 可以接受一个可选的参数 proto,用于指定新对象的原型。
- 兼容性:new Object() 是 ES3 中的语法,兼容性较好;Object.create(proto) 是 ES5 中的静态方法,兼容性相对较差。