Javascript对象是面向对象还是基于对象
什么是面向对象?
不同的语言,他们对于对象的解释都不相同,但无论如何,我们应该认识到,对象并不是只存在于计算机领域的一个概念,它是顺应人类思维模式产生的一种抽象。
那么,我们先来了解下人类思维模式下,对象是什么?
对象这一概念在人类的幼儿期形成,这远远早于我们编程逻辑中常用的值、过程等概念。在幼年期,我们总是先认识到某一个苹果能吃(这里的某一个苹果就是一个对象),继而认识到所有的苹果都可以吃(这里的所有苹果,就是一个类),再到后来我们才能意识到三个苹果和三个梨之间的联系,进而产生数字“3”(值)的概念
在《面向对象分析与设计》这本书中,Grady Booch替我们做了总结,他认为,从人类的认知角度来说,对
象应该是下列事物之一:
- 一个可以触摸或者可以看见的东西;
- 人的智力可以理解的东西;
- 可以指导思考或行动(进行想象或施加动作)的东西
有了对象的自然定义后,我们就可以描述编程语言中的对象了。在不同的编程语言中,设计者也利用各种不
同的语言特性来抽象描述对象,最为成功的流派是使用“类”的方式来描述对象,这诞生了诸如 C++、Java
等流行的编程语言
而 JavaScript 早年却选择了一个更为冷门的方式:原型
Javascript 对象特征
在我看来,不论我们使用什么样的编程语言,我们都先应该去理解对象的本质特征(参考GrandyBooch《面向对象分析与设计》)。总结来看,对象有如下几个特点。
- 对象具有唯一标识性:即使完全相同的两个对象,也并非同一个对象。
- 对象有状态:对象具有状态,同一对象可能处于不同状态之下。
- 对象具有行为:即对象的状态,可能因为它的行为产生变
对象具有唯一标识性
在js中,对象的唯一标识就是他在内存中的地址,因此我们知道,即便两个对象的内容相同,但是他们也不是相同的。
var o1 = { a: 1 };
var o2 = { a: 1 };
console.log(o1 == o2); // false
对象有状态和对象具有行为
在javascript中,模糊了状态和行为,他们统称为:属性;所以 JavaScript中的行为和状态都能用属性来
抽象。
var o = {
d: 1,
f() {
console.log(this.d);
}
}
在o对象中,d是一个属性,f也是一个属性,虽然他们两的写法不同,但是对JavaScript来说,d和f就是两个普通属性。
所以,总结一句话来看,在JavaScript中,对象的状态和行为其实都被抽象为了属性。如果你用过Java,一定不要觉得奇怪,尽管设计思路有一定差别,但是二者都很好地表现了对象的基本特征:标识性、状态和行为。
在实现了对象基本特征的基础上,我认为,JavaScript中对象独有的特色是:对象具有高度的动态性,这是因为JavaScript赋予了使用者在运行时为对象添改状态和行为的能力。
var o = {a:1};
o.b=2;
console.log(o.a,o.b); //1,2
o被声明后就已经运行了,运行后我们还给他添加了b属性,这就是运行时为对象添改状态和行为的能力。
Javascript对象的两类属性
对JavaScript来说,属性并非只是简单的名称和值,JavaScript用一组特征(attribute)来描述属性(property)。
先来说第一类属性,数据属性。它比较接近于其它语言的属性概念。数据属性具有四个特征:
- value:就是属性的值
- writable:决定属性能否被赋值
- enumerable:决定for in能否枚举该属性
- configurable:决定该属性能否被删除或者改变特征值
在大多数情况下,我们只关心数据属性的值即可
第二类属性是访问器(getter/setter)属性,它也有四个特征:
- getter:函数或undefined,在取属性值时被调用
- setter:函数或undefined,在设置属性值时被调用
- enumerable:决定for in能否枚举该属性
- configurable:决定该属性能否被删除或者改变特征值
访问器属性使得属性值在读写时得到完全不同的值。
我们通常用于定义属性的代码会产生数据属性,其中的writable、enumerable、configurable都默认为true。我们可以使用内置函数 Object.getOwnPropertyDescripter来查看,如以下代码所示:
var o = { a: 1 };
o.b = 2;
//a和b皆为数据属性
Object.getOwnPropertyDescriptor(o,"a");
//{value: 1, writable: true, enumerable: true,configurable:true}
Object.getOwnPropertyDescriptor(o,"b");
//{value: 2, writable: true, enumerable: true,configurable:true}
如果我们要想改变属性的特征,或者定义访问器属性,我们可以使用 Object.defineProperty,示例如下:
var o = { a: 1 };
//修改
Object.defineProperty(o, "b", {value: 2, writable: false, enumerable: false, configurable: true});
//获取
Object.getOwnPropertyDescriptor(o,"a");
//{value: 1, writable: true, enumerable: true,configurable:true}
Object.getOwnPropertyDescriptor(o,"b");
//{value: 2, writable: false, enumerable: false,configurable:true}
//我们定义b属性设置为是不能被修改的
o.b = 3;
console.log(o.b); //2
在创建对象时,也可以使用 get 和 set 关键字来创建访问器属性,代码如下所示:
var o = {
get a() { return 1 }
};
console.log(o.a); //1
访问器属性跟数据属性不同,每次访问属性都会执行getter或者setter函数。
这里我们的getter函数返回了1,所以o.a每次都得到1。
这样,我们就理解了,实际上JavaScript 对象的运行时是一个“属性的集合”,属性以字符串或者Symbol为key,以数据属性特征值或者访问器属性特征值为valu
对象是一个属性的索引结构(索引结构是一类常见的数据结构,我们可以把它理解为一个能够以比较快的速
度用key来查找value的字典)。我们以上面的对象o为例,你可以想象一下“a”是key
{writable:true,value:1,configurable:true,enumerable:true}是value。我们在前面的类型课程中,已经介绍了Symbol类型,能够以Symbol为属性名,这是JavaScript对象的一个特色。
到这里,我们可以知道,javascript的面向对象和目前主流的基于类的面向对象差异非常大。
但是它就是面向对象的语言。
本文系作者 @木灵鱼儿 原创发布在木灵鱼儿站点。未经许可,禁止转载。
全部评论 5
杰哥
Google Chrome Windows 10木灵鱼儿
FireFox Windows 10杰哥
Google Chrome Windows 10杰哥
Google Chrome Windows 10木灵鱼儿
FireFox Windows 10