重学JavaScript 对象
JavaScript栏目为大家介绍JavaScript的对象,从新认识。
这里我们连续学习两个比力重要的类型,就是 Object
和 Symbol
。我们主要讲的是 Object,相对 Object 来说 Symbol 只是一个配角。
关于对象这个概念大家非常早就会接触到了,其实人大约在 5 岁的时候就会发生对象的抽象。许多时候我们看起来仿佛对象是我们学编程的时候才知道有面向对象。但是从认知的角度来说,应当是比我们平常对数字中的值这个类型的认知要早的多。所以历史的角度也不断被评论为,对象是更切近人类的天然思维的。
刚刚说到我们从小时候就已经发生了对象的概念了,那为什么说从小就有呢?Object 在英文里其实它的意思是一个非常广泛的东西,他是任何一个物体,可以是抽象的物体,也可以是一个实际的物体。但是在我们中文里,寻不到一个适宜的词,可以代表保罗万物的词来表达 Object 的含义。所以在中文中我们就直接翻译成 “对象”。
所以这个中文翻译过来的词,就造成了我们对 Object 的必然曲解。由于对象在英文中,我觉得更接近 target 这个单词的意思。其实在台湾就会把 Object 翻译成 “物件”。物件这个词在语义上确实会更贴合一些,但是物件这个词大家也不是特殊熟知,所以它就演化成了一个技术的专用名词。
但是不管怎样,我们脑子里面应当是有这么一个概念的,从小我们就应当知道我们有三条千篇一律的鱼,但是其实他是三个不一样的对象。那为什么千篇一律的鱼,他们是不一样的对象呢?
我们可以这么懂得哈,忽然有一天其中一条鱼的尾巴被咬掉了。很惊讶的发明,别的两条鱼并不会受到影响。因此,当我们在运算机中描写这三条鱼的时候,那必定是三组雷同的数据的对象,但是是独自贮存了三份,互相独立的。
这种鱼和鱼之间的不同其实就是,他们的对象的一个特性的表现。一些认知学的研讨认为我们人在小时候大约 5 岁的时候就有
这样的认知了,其实此刻的孩子发育的比力早,5岁已经是一个最低的年龄了。2 ~ 3 岁的时候大家都知道这个iphone和阿谁iphone是不一样的,这个咬一口,别的一个iphone安然无恙。
所以假如我们在运算机里面描写这三条鱼的时候,我们就必需要把数据独自储备三份,由于是三个对象的状态,而不是我们把统一个数据存了三份,而是刚巧他们是相等罢了。其实这个正是所有的面向对象编程的一个根基,也就是说,他是这条鱼就是这条鱼,不是这条鱼就不是这条鱼,不会由于对象本身的状态改动而变得有不同。
所以我们对对象的认知是?
任何一个对象都是独一的,这与它本身的状态无关,状态是由对象决议的
即便状态完全一致的两个对象,也并不相等。所以有时候我们会把对象当数据用,但是这个其实是一种说话的使用技巧罢了,并不是把对象当做对象用,比方我们传一个 config,其实传 config 的历程其实它并不是把对象当对象去传,而是我们把对象当做一种数据载体去传。这个时候就触及到我们对对象类型的使用,跟说话本身的设计用处的偏向。
我们用状态来描写对象,比方我们有一个对象 “鱼”,然后他的状态就是,它有没有 “尾巴”、“眼睛多大”,我们都会用这些状态值来描写一个对象。
我们的状态的改动既是行动,状态的改动就是鱼的尾巴没有了,被咬掉了。然后过了一段时间它又长出一条新尾巴了,然后尾巴还可以来回摆动。这些都属于它的状态的改动。而这些状态的改动都是行动。
Object 三要素
- Identifier —— 独一标识
- State —— 状态
- Behavior —— 行动
其实哲学家他们就会研讨一个 Object,比方鱼的独一标识是啥,这条鱼的骨头全部挑出来看还是不是这条鱼。然后把肉都切下来,再拼起来看是不是这一条鱼,这就是闻名的哲学问题 “忒修斯之船”。
这个我们就不消关怀,我们就说变量它是有一个独一标识性,这个也是对象的一个中心要素具备了。
对象就要有状态,状态是可以被改动的,改动就是行动。这样对象的三要素就成立了。
我们脑子里的任何一个概念和实际中的任何一个物品,都可以成为一个对象,只要三要素是齐备的。
Object —— Class(类)
第一
Class
类 和Type
类型是两个不一样的概念。
我们认识对象的一个重要的方式叫做分类,我们可以用分类的方式去描写对象。比方我们研讨透测一条鱼之后,它与所有同类型的鱼特性都是相似的,所以我们就可以把这些鱼归为一类,叫 “鱼类”(Fish Class)。
其实在鱼的分类上还有更大的为 “动物分类 (Animal)”,那么动物下面还有其他动物的分类,比方说羊 (Sheep)。所以说鱼和羊之间他们的共性就会用 “动物” 来描写。然后我们一层一层的抽象,在 "Animal" 之上还会有 Object。
类是一个非常常见的描写对象的一种方式,比方说我们刚刚讲到的生物,用对象可以把所有的生物分成界门纲目科属种,是一个巨大的分类体系。在写代码的时候,分类是一个为业务效劳的,我们没有必要分的那么细。平常我们会把有共性的需要写在代码里的,我们就把 Animal 提出来,就不再分这个哺乳动物,还是卵生,还是脊索动物等等。
分类有两个流派,一种是归类
,一种是分类
。
归类
—— 就是我们去研讨单个对象,然后我们从里面提取共性变成类,之后我们又在类之间去提取共性,把它们变成更高的抽象类。比方我们在 “羊” 和 “鱼” 中提取共性,然后把它们之间的同享再提取出来变成 “动物” 的类。关于 “归类” 办法而言,多继承是非常天然的事情,如 C++ 中的菱形继承,三角形继承等。分类
—— 则是把世界万物都抽象为一个基类 Object,然后定义这个 Object 中有什么。采纳分类思想的运算机说话,则是单继承构造。并且会有一个基类 Object。
JavaScript 这个说话比力接近 “分类” 这个思想,但是它也不完全是分类的思想,由于它是一个多范式的面向对象说话。
Object —— Prototype(原型)
接下来我们讲一讲 JavaScript 描写对象的方式。
其实分类 Class Based 的 Object 并不是一个独一的认识对象的办法,我们还有一个更接近人类天然认知的。分类的能力大概至少要到小学才有的。但是我们认识对象之后,几乎是立刻就可以得到别的一种描写对象的方式。那就是 “原型”。
原型其有用 “如法炮制” 来懂得 ,其实如法炮制就是用的一种原型办法。由于猫和虎很像,所以我们只需要把它们直接的有不同的地方分出来就可以了。
比方说我们此刻想研讨鱼,那么寻一种典型的鱼,比方寻一条详细的鲤鱼,然后我们把这条鲤鱼所有的特点都加到鱼类的原型上。其他的鱼只要有对象,我们就按照鱼的原型停止修改。比方说鲶鱼比鲤鱼更能吃,它是吃肉的,并且身上还是滑滑的,所以我们就可以在鲤鱼的原型根基上把这些特点加上,这样我们就能描写出鲶鱼了。
那么在羊类里面,我们也选中一只小绵羊来做我们的根基原型。然后假如我们寻到一只山羊,我们剖析出它的特性是多胡子,足是弯点,又长又硬又能登山,那么我们就在小绵羊的原型上加上这些特性,那我们就描写了一只山羊了。
那么在上级的 “动物” 中我们也选一只典型的动物,比方说老虎,有四个蹄,但是不必然所有动物都有4个蹄子,不外原型选中相对来说它是比力自在的。比方说我们选中蛇作为动物的原型的话,那么我们在描写鱼的时候就特殊费力了,描写猫的时候就更费力了。
原型里面也会有一个终究版的原型叫 Object Prototype
,这个就是所有物品的典型的物品,也可以说是我们所有对象的老祖宗。我们描写任何对象都是从它与描写对象的不同来停止描写的。
然后在 Object Prototype
之上一样来说是不会再有原型了,但是有一些说话里面会同意有一种 Nihilo
原型。Nihilo 的意思就是虚无空虚,这个是说话中立的讲法。假如我们用 JavaScript 的详细的设备来描写,那这个 Nihilo
原型就是 null
,这个大家就很容易懂得了,我们很容易就可以简历一个 null
对象的原型。
小总结:
- 我们这种原型是更接近人类原始认知的描写对象的办法
- 所以面向对象的各种办法其实并没有绝对的对错,只存在在不一样场景下不一样的代价
- 原型的认知成本低,选错的成本也比力低,所以原型适合一些不是那么清楚和描写上比力自在的场景
- 而分类(Class)更适合用在一些比力严谨的场景,而 Class 有一个长处,它自然的跟类型系统有必然的整合的,所以许多的说话就会选中把 Class 的继承关系整合进类型系统的继承关系傍边
小练习
我们假如需要编写一个 “狗 咬 人” 的 Class,我们需要如何去设计呢?
假如我们依照一个比力朴素的办法,我们就会去定义一个 Dog
Class,然后里面给予这个 Class 一个 bite
的办法。
class Dog { bite(Human) { // ...... } }复制代码
这样的一段代码是跟我们的问题是千篇一律的,但是这个抽象是一个错误的抽象。由于这个违反了面向对象的根本特点,不管我们是如何设计,只要这个 bite
发生在狗身上就是错误的。
为什么?
由于我们前面讲到了面向对象的三要素,对象的状态必需是对象本身的行动才能改动的。那么假如我们在狗的 Class 中写 bite
这个动作,但是改动的状态是 “人”,最为狗咬了人之后,只会对人造成损害。所以在这个行动中 “人” 的状态是发生转变的,那么假如行动是在狗的 Class 中就违反了面向对象的特点了。
当然假如是狗吃人,那我们牵强是可以成立的,由于狗吃了人狗就饱了,那对狗的状态是有发生改动的。但是狗咬人,我们根本可以认为这个行动对狗的状态是没有发生任何改动的。
所以我们应当在 “人” 的 Class 中设计一个行动。那么有些同学就会问,我们是应当在人的身上参加一个 biteBy
行动吗?就是人被咬的一个行动?好像也不合错误,由于人 Class 里面的行动应当是用于改动人的状态的,那这个行动的命名应当是如何样的呢?
这里愈加合理的行动应当是 hurt
表示被损害了,然后传入这个行动的参数就是受到的损害程度 damage
。由于这里人只关怀它受到的损害有多少就可以了,他是不需要关怀是狗咬的还是啥咬的。
class Human { hurt(damage) { //...... } }复制代码
狗咬人在实际开发场景中,是一个业务逻辑,我们只需要设计改动人 Human
对象内部的状态的行动,所以它准确的命名应当是 hurt
。这里的 damage
,可以从狗 Class 中咬 bite
, 的行动办法中运算或者生成出来的一个对象,但是假如我们直接传狗 Dog
的对象进来的话,必定是不相符我们对对象的抽象原则的。
终究我们的代码实现逻辑如下:
class Human { constructor(name = '人') { this.name = name; this.hp = 100; } hurt(damage) { this.hp -= damage; console.log(`${this.name} 受到了 ${damage} 点损害,剩余生命中为 ${this.hp}`); } }class Dog { constructor(name = '狗') { this.name = name; this.attackPower = 10; // 攻击力 } bite() { return this.attackPower; } }let human = new Human('三钻');let dog = new Dog(); human.hurt(dog.bite()); // 输出:三钻 受到了 10 点损害,剩余生命中为 90复制代码
设计对象的原则:
- 我们不该该受到说话描写的干扰(特殊是业务需求的干扰)
- 在设计对象的状态和行动时,我们总是遵照 “行动改动状态” 的原则
- 违反了这个原则,整个对象的内聚性就没有了,这个对架构上会造成宏大的毁坏
相关免费学习引荐:javascript(视频)
以上就是重学JavaScript 对象的具体内容,更多请关注百分百源码网其它相关文章!