1、字面量
const person = {
name: "Jessie",
age: 33,
sayName: function () {
console.log(this.name);
},
};
person.sayName();
2、Object 构造函数
const person = new Object();
person.name = "Jessie";
person.age = 33;
person.sayName = function () {
console.log(this.name);
};
person.sayName();
3、工厂模式
用函数来封装以特定接口创建对象的细节
工厂模式解决了创建多个相似对象的问题,但是没有解决对象识别的问题(一个对象的类型),所以出现了构造函数模式
function createPerson(name, age) {
var o = new Object();
o.name = name;
o.age = age;
o.sayName = function () {
console.log(this.name);
};
return o;
}
var person1 = createPerson("Jessie", 33);
var person2 = createPerson("Leo", 23);
person1.sayName();
person2.sayName();
4、构造函数模式
构造函数可以用来创建特定类型的对象
构造函数的问题就是每个方法都要在实例上创建一遍,所以需要把方法提出来,在构造函数中引用方法名。但随着方法变多,就没有封装性可言了。所以就有了原型模式。
function Person(name, age) {
// 与工厂函数相比:1、没有显式的创建对象;2、直接将属性和方法赋给了this;3、没有return语句
this.name = name;
this.age = age;
this.sayName = function () {
console.log(this.name);
};
}
// new 操作符调用过程:1、创建一个新对象;2、将构造函数的作用域赋给新对象(this);3、执行构造函数中的代码(给新对象添加属性);4、返回新对象。
var person1 = new Person("Jessie", 33);
var person2 = new Person("Leo", 23);
// 两个person实例的constructor都指向Person
console.log(person1.constructor == Person);
console.log(person2.constructor == Person);
// 但是检测对象类型,还是instanceof更可靠
console.log(person1 instanceof Person);
console.log(person1 instanceof Object);
5、原型模式
每一个函数都有一个prototype(原型)属性,这个属性是一个指针,指向一个对象,而这个对象的用途是包含可以由特定类型的所有实例共享的属性和方法
缺点就是全部实例都会共享原型上的属性,而实际情况实例都是要有属于自己的全部属性。所以就有了 组合使用构造函数模式和原型模式
function Person() {}
var friend = new Person();
// Person.prototype.name = "Jessie";
// Person.prototype.age = 33;
// Person.prototype.sayName = function () {
// console.log(this.name);
// };
// 对象字面量方式重写原型对象
Person.prototype = {
// cunstructor: Person,
name: "Jessie",
age: 33,
sayName: function () {
console.log(this.name);
},
};
Object.defineProperty(Person.prototype, "constructor", {
enumerable: false, // constructor 应该是不可枚举的
value: Person,
});
var person1 = new Person();
person1.sayName(); // Jessie
// 重写原型对象切断了现有原型与任何之前已经存在的对象实例之间的联系
friend.sayName(); // TypeError: friend.sayName is not a function
console.log(person1.constructor == Person);
console.log(Object.getOwnPropertyNames(Person.prototype));
6、组合使用构造函数模式和原型模式
构造函数用于定义实例属性,原型模式用于定义方法和共享的属性。最大限度节省了内存。
function Person(name, age) {
this.name = name;
this.age = age;
this.friends = ["Lucy", "Jack"];
}
Person.prototype = {
constructor: Person,
sayName: function () {
console.log(this.name);
},
};
var person1 = new Person("Jessie", 33);
var person2 = new Person("Leo", 23);
person1.friends.push("Vans");
console.log(person1.friends); // [ 'Lucy', 'Jack', 'Vans' ]
console.log(person2.friends); // [ 'Lucy', 'Jack' ]
console.log(person1.sayName == person2.sayName); // true
7、动态原型模式
在构造函数中初始化原型
function Person(name, age) {
// 属性
this.name = name;
this.age = age;
// 方法
if (typeof this.sayName !== "function") {
Person.prototype.sayName = function () {
console.log(this.name);
};
}
}
var friend = new Person("Van", 22);
friend.sayName();
console.log(friend instanceof Person);
8、寄生构造函数模式
在其他模式可以解决的情况下,不建议使用此模式
function SpecialArray() {
var values = new Array();
values.push.apply(values, arguments);
values.toPipedString = function () {
return this.join("|");
};
return values;
}
var colors = new SpecialArray("red", "blue", "green");
console.log(colors.toPipedString()); // red|blue|green
9、稳妥构造函数模式
没有公共属性,方法也不引用this,不使用new操作符调用构造函数。适合某些安全执行环境
function Person(name, age) {
// 创建要返回的对象
var o = new Object();
// 可以在此处定义私有变量和方法
// 添加方法
o.sayName = function () {
console.log(name);
};
return o;
}
var friend = Person("Van", 22);
friend.sayName(); // "Van"