Macmillan的解释是:
a thing that you can see and touch that is not alive and is usually solid 一种你能够触摸到的实物,并非活物。
新华字典中,对象的基本含义是:
“你是我的研究对象,你是我的学习对象,这是今天的讨论对象”但如果单独用,就成了恋爱对方。“这是我对象”
因此对象在中文世界中并非像英文所指的那么普世,于是对象成了计算机领域中的专有名词,代表一切事物的总称。
而从英文解释中,可以体会到,object是人类认知世界,而产生的一种思维抽象。什么意思呢?也就是人类成长过程中,对眼前事物的感知。
我是两个孩子的爸爸,我认真观察过他们,他俩小时候都是先用眼睛看,进入口欲期后用嘴巴感知,这个东西是红色,那个东西冰冰凉,再然后大人们教他们数数,OK,这是两个苹果。于是对象有了属性和值。
《面向对象分析与设计中》,Grady Booch 说,从人类认知角度来说,对象是:
对象的特征是:
在计算机语言的设计中,不同的设计者利用着他们对object理解,来对object进行了描述,也就是我们今天耳熟能详的,比如Java、C++ 中基于“类”的面相对象编程的概念。
但Javascript有点特立独行,使用了“原型(Prototype)”。
the first form of something new, made before it is produced in large quantities
这里先不展开。
由于产生之时的政治原因,JS受管理层要求模仿Java,于是你看到了创始人 Brendan Eich 在“原型运行时”的基础上引入了 new、this 等语言特性,使之“看起来更像 Java”。ES6规范之前,甚至有大量的框架将JS改造成基于类来编程,而这样做的弊端明显要大于收益。
幸运的是,任何语言的运行时,类的概念都会被弱化。
对照上面说的,面向对象的三个特征:唯一、状态、行为
一般,对所有的语言来说,对象的唯一标识性都是通过内存地址来实现的,对象具有唯一标识的内存地址,也就具有唯一标识了。
也就是为什么,下面的返回为false:
var o1 = { a: 1 };
var o2 = { a: 1 };
console.log(o1 === o2);
对不同的语言来说,状态和行为会使用不同的描述:
而在JS中,状态和行为统一抽象成了属性(函数也是一种特殊的对象)。
如下例中,对对象o来说,d 和 f 就是两个普通的属性
var o = {
d: 1,
f() {
console.log(this.d);
}
};
也就是说,JS能很好地体现对象的基本特征。
但为什么很多人说“JS不是面向对象”的呢?因为JS的对象设计有其独有的特点,那就是:
对象具有高度的动态性,因为JS能在运行时被修改状态和行为。
你试过Java在运行时添加向对象添加属性吗?JS 能做到!
var o = { a: 1 };
o.b = 2;
console.log(o.a, o.b); //1 2
JS为了提高抽象能力,将属性设计成了(比别的语言)更加复杂的形势,提供了数据属性和*访问器属性*两类。也就是说,JS的属性并非简单的名称(键)和值,而是用了一组attribute(特征)来描述property(属性)。
数据属性类似其他语言的“属性”,具有四个特征。
虽然,我们通常只关系值。
也就是getter/setter属性,它也有四个特征。
也就是说,读和写的时候,访问器属性可以执行代码,让读和写得到完全不同的值,可以看作一种函数的语法糖。
这位客官问了,我怎么没设置过什么writable、enumerable、configurable啊?因为通常我们定义属性时,其默认值都是true,那我们怎么看到呢?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}
那如何改变呢?defineProperty
var o = { a: 1 };
Object.defineProperty(o, "b", {value: 2, writable: false, enumerable: false, configurable: true});
//a和b都是数据属性,但特征值变化了
Object.getOwnPropertyDescriptor(o,"a"); // {value: 1, writable: true, enumerable: true, configurable: true}
Object.getOwnPropertyDescriptor(o,"b"); // {value: 2, writable: false, enumerable: false, configurable: true}
o.b = 3;
console.log(o.b); // 2
那访问器属性呢?
var o = { get a() { return 1 } };
o.a = 2
console.log(o.a); // 1
每次访问属性都会实行getter 或者setter 函数,因此o.a 每次都得到1。
总结一下, JS中的对象,实际上是一个“属性的集合”:
上面例子中的的a就是key,而它的value,是{writable:true,value:1,configurable:true,enumerable:true}
因此,JS的对象与其他语言相比,有些另类。
正如我们前面说到的:
任何语言的运行时,类的概念都会被弱化。
因此JS可以模仿多数面向对象编程范式,比如基于原型,甚至基于类。也正因此,JS是正如其语言标准所说的:JS是一门面向对象的语言。
既然这样,我们就不要机械地用JS来模仿其他语言,充分利用它的高度动态性的属性集合这一对象系统,挖掘它的能力吧。
领取专属 10元无门槛券
私享最新 技术干货