JavaScript 是一门面向对象的编程语言(Object Oriented Programming),面向对象编程具有灵活、代码可复用、容易维护和开发的优点,更适合多人合作的大型软件项目。
在 JavaScript 中,有这么一句话:“万物皆对象”。 对象是一组无序的相关属性和方法的集合,例如字符串、数值、数组、函数等。这即是说,对象是由属性和方法组成的:
-
属性:事物的特征,在对象中用属性来表示(常用名词)
-
方法:事物的行为,在对象中用方法来表示(常用动词)
这篇博客我们来讲讲 JavaScript 创建对象的几种方法。
创建对象的五种方法
1 原始模式
//1.原始模式,对象字面量方式
var person = {
name: 'Jack',
age: 18,
sayName: function() {
console.log(this.name)
}
};
//2.原始模式,Object构造函数方式
var person = new Object()
person.name = 'LoveLinqi'
person.age = 18
person.sayName = function () {
console.log(this.name)
};
2 工厂模式
看上面的原始模式,越看越可爱,因为我们绝大多数人第一次创建的对象可能都是以这种原始模式的。
但是,当我们要创建批量的对象person1、person2……时,你可能就不会觉得这种模式很可爱了。
于是我们开始创办“工厂”,让“工厂”来为我们生产对象,这就是创建对象的工厂模式:
function factoryPerson(name, age) {
var person = new Object();
person.name = name;
person.age = age;
person.sayName = function() {
alert(this.name)
};
return person;
}
var person1 = factoryPerson('LoveLinqi', 18);
console.log(person1 instanceof Object);//ture
console.log(typeof(person1));//Object
工厂模式虽然解决了创建多个相似对象的问题,但却没有解决对象识别的问题,即怎样知道一个对象的类型(上例中我们用 instanceof 只可识别对象person1为Object)。
另外,使用工厂模式,每次创建对象时都要创建一个独立的对象,代码臃肿。
3 构造函数
在ES6之前,JS中并没有引入类的概念,对象不是基于类创建的,而是用一种称为构造函数的特殊函数来定义对象和它们的特征。
function Person(name, age) {
this.name = name;
this.age = age;
this.sayName = function() {
alert(this.name);
};
}
var person1 = new Person('Linqi',18)
console.log(person1 instanceof Object)//true
console.log(person1 instanceof Person)//true
console.log(typeof(person1));//Object
Person('LoveLinqi', 18)
console.log(window.name);//Linqi
构造函数是一种特殊的函数,主要用来初始化对象,即为对象成员变量赋初始值,它总与 new 一起使用。我们可以把对象中一些公共的属性和方法抽取出来,然后封装到这个函数里面。
在 JS 中,使用构造函数时要注意以下两点:
-
构造函数用于创建某一类对象,其首字母要大写
-
构造函数要和 new 一起使用才有意义
3.1 new关键字
new 在执行时会做四件事情:
-
在内存中创建一个新的空对象。
-
让 this 指向这个新的对象。
-
执行构造函数里面的代码,给这个新对象添加属性和方法。
-
返回这个新对象(所以构造函数里面不需要 return )。
3.2 静态成员和实例成员
构造函数中的属性和方法我们称为成员, 成员可以添加。
1. 实例成员:
-
实例成员就是构造函数内部通过this添加的成员,如上例代码中 name、age、sayName就是实例成员。
-
实例成员只能通过实例化的对象来访问;
2. 静态成员:
-
静态成员是在构造函数本身上添加的成员,如上例代码中的sex就是静态成员;
-
静态成员只能通过构造函数来访问。
function Person(name, age) {
this.name = name;
this.age = age;
this.sayName = function() {
alert(this.name);
};
}
var person1 = new Person('LoveLinqi',18)
console.log(Person.age)//undefine,不可以用构造函数访问实例成员
Person.sex = 'fale'//定义静态成员
console.log(Person.sex)//fale,可以用构造函数访问静态成员
console.log(person1.sex)//undefine,不可以用实例访问静态成员
4 构造函数+原型
构造函数方法很好用,但是存在浪费内存的问题。 现在比较常用的创建对象的方式是构造函数+原型。
什么意思呢?
假如我们为一个构造函数创建两个实例:
function Person(name, age) {
this.name = name;
this.age = age;
this.sayName = function() {
alert(this.name);
};
}
var person1 = new Person('科比',18)
var person2 = new Person('詹姆斯',19)
那么它们调用sayName() 方法时,指向的是不同的内存地址,这就造成了内存浪费,我们理应将共享的方法提取出来。
在这篇 blog 中,我只告诉你这种方式的做法是:将独立的属性方法放入构造函数中,而可以共享的部分则放入原型中,这样做可以最大限度节省内存而又保留对象实例的独立性。
(关于 JavaScript 中原型链的知识请见下篇 blog)
function Person(name, age) {
this.name = name;
this.age = age;
}
Person.prototype.sayName = function() {
this.sayName = function() {
alert(this.name);
};
}
var person1 = new Person('Linqi', 18)
console.log(person1)
/*打印内容:
* age: 18
* name: "Linqi"
* __proto__:{
* hobbies: (2) ["sleep", "weibo"]
* sayName: ƒ ()
* constructor: ƒ Person(name, age)
* __proto__: Object
* }
*/
Person.prototype.hobbies = ['sleep', 'weibo']
console.log(person1.__proto__)
/*打印内容:
* hobbies: (2) ["sleep", "weibo"]
* sayName: ƒ ()
* constructor: ƒ Person(name, age)
* __proto__: Object
*/
5 类
还有一种创建对象的方法就是类了。类是ES6中新增的语法,用class关键字创建一个类。
class Person {
constructor(name,age) { // constructor 构造器或者构造函数
this.name = name;
this.age = age;
}
sayName() {
console.log(this.name);
}
}
var person1 = new Person('LoveLinqi', 18)