JavaScript之面向对象总结
前言:在ECMAScript中是没有类的概念的,所以它的对象与基于类的语言中的对象不同。ECMA-262把对象总结为:“无序属性的集合,其属性包含基本值、对象或者函数”。
一、理解对象
var person = new Object();
person.name = "张三";
person.age = 15;
person.say = function(){
alert('hello');
}
上面通过Object构造函数创建了一个对象,并为它添加了三个属性。
ECMA对象的属性有两种:数据属性和访问器属性。
var person = {
name: "聂赫留朵夫", // 数据属性
age: 25
}
Object.defineProperty(person, "year", { // 访问器属性
get: function(){
return 1922;
},
set: function(value){
this.age = 25 + value;
}
})
数据属性:包含一个数据值的位置,可以再这个位置写入和读取值
数据属性有4个描述其行为的特性:
- [[Configurable]]:表示能否通过
delete
删除属性从而重新定义属性,默认为true
- [[Enumerable]]:表示能否通过
for-in
循环返回属性,默认为true
- [[Writeable]]:表示能否修改属性,默认为
true
- [[Value]]:包含这个属性的数据值,默认值为
undefined
ps:要修改默认的特性,必须使用Object.defineProperty
访问器属性:包含一对儿getter
和setter
函数,不包含数据值
访问器属性也有4个特性:
- [[Configurable]]:表示能否通过
delete
删除属性从而重新定义属性,默认为true
- [[Enumerable]]:表示能否通过
for-in
循环返回属性,默认为true
- [[Get]]:读取属性时调用的函数,默认值为
undefined
- [[Set]]:写入属性时调用的函数,默认值为
undefined
访问器属性不能直接定义,必须通过Object.defineProperty
来定义
读取属性的特性,通过Object.getOwnPropertyDescriptor
方法
二、创建对象
1、通过字面量或者Object构造函数
var person = {
name: "尤瓦尔•赫拉利"
}
var car = new Object();
car.name = "法拉利"
优点:不清楚
缺点:使用同一个接口,会产生大量的代码
2、工厂模式
function createPerson(name, age){
var o = new Object();
o.name = name;
o.age = age;
return o;
}
var p1 = createPerson("方鸿渐", 14);
var p2 = createPerson("墨带", 20);
优点:解决了创建多个相似对象的问题
缺点:很明显,你不知道创建的对象的类型是什么
3、构造函数模式
function Person(name, age){
this.name = name;
this.age = age;
}
var person = new Person("智人", 25);
创建实例,必须要通过new
关键字,new
调用经历的步骤:
- 创建一个新的对象
- 将构造函数的
this
指向新的对象 - 执行构造函数中的代码
- 返回新对象
优点:可以将每个实例都标识为一种特定的类型
缺点:每个方法都要在实例上重新创建一遍
4、原型模式
function Person(){}
Person.prototype.name = "凯撒大帝";
Person.prototype.age = 500;
var p1 = new Person();
console.log(p1.name); // 凯撒大帝
var p2 = new Person();
特点:所有的属性都是被很多实例共享的,但这个也是一个缺点。这个共享对于函数来说挺好,对于基本类型来说也还可以(实例上添加的同名属性可以覆盖原型上的),但是对于引用类型来说就是比较突出的问题了(修改一个,其余的也会被修改)。另外,这个模式省略了为构造函数传参的方便。
5、构造函数模式和原型模式组合使用
function Person(name, age){
this.name = name;
this.age = age;
}
Person.prototype.getName = function(){
alert(this.name);
}
var p = new Person("贝多芬", 200);
这种是比较通用的一种方式,结合了构造函数模式和原型模式的优点,但是这种方式可能对于写OO语言的人来说,有点儿不友好,毕竟这种写法有点儿独特。
6、动态原型模式
function Person(name, age){
this.name = name;
this.age = age;
if (typeOf this.sayName !== "function") {
Person.prototype.sayName = function(){
alert(this.name);
}
}
}
这种模式的好处是把所有的属性全部都封装到一个函数里面,但是会对函数做一个检测,没有的情况下才会去创建
7、寄生构造函数模式
function Person(name, age){
var o = new Object();
o.name = name;
o.age = age;
o.printName = function(){
console.log(this.name);
}
return o;
}
var p = new Person("贝多芬", 55);
这个模式的一个适用场景是改写原生的对象
8、使用es6
class Person {
constructor(name){
this.name = name;
}
printName(){
console.log(this.name);
}
}
const p = new Person("巴菲特")
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。