什么是面向对象?

不同的语言,他们对于对象的解释都不相同,但无论如何,我们应该认识到,对象并不是只存在于计算机领域的一个概念,它是顺应人类思维模式产生的一种抽象。

那么,我们先来了解下人类思维模式下,对象是什么?

对象这一概念在人类的幼儿期形成,这远远早于我们编程逻辑中常用的值、过程等概念。在幼年期,我们总是先认识到某一个苹果能吃(这里的某一个苹果就是一个对象),继而认识到所有的苹果都可以吃(这里的所有苹果,就是一个类),再到后来我们才能意识到三个苹果和三个梨之间的联系,进而产生数字“3”(值)的概念

在《面向对象分析与设计》这本书中,Grady Booch替我们做了总结,他认为,从人类的认知角度来说,对
象应该是下列事物之一:

  1. 一个可以触摸或者可以看见的东西;
  2. 人的智力可以理解的东西;
  3. 可以指导思考或行动(进行想象或施加动作)的东西

有了对象的自然定义后,我们就可以描述编程语言中的对象了。在不同的编程语言中,设计者也利用各种不
同的语言特性来抽象描述对象,最为成功的流派是使用“类”的方式来描述对象,这诞生了诸如 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

  1. 杰哥
    杰哥
    Google Chrome Windows 10
    作者最近是看了什么书啊
    1. 木灵鱼儿
      木灵鱼儿
      FireFox Windows 10
      @杰哥???咋了
      1. 杰哥
        杰哥
        Google Chrome Windows 10
        @木灵鱼儿想学习一下,我刚刚看到你的tag是【重学前端】以外是一本书
        1. 杰哥
          杰哥
          Google Chrome Windows 10
          @杰哥看到你的tag是【重学前端】以为是一本书
        2. 木灵鱼儿
          木灵鱼儿
          FireFox Windows 10
          @杰哥我都准备放弃了,太晦涩了,无法理解,还是学学其他的先,动不动就是类,对象,各种概念

目录