title: JS对象(1)重新认识面向对象
date: 2016-10-05
tags: JavaScript
0x00 面向对象
从设想形式上看,对象是计算机笼统实际天下的一种体式格局。
面向对象编程(object-oriented programming)的最主要目标是进步顺序的重复运用性。
我们说,对象具有属性(property)和要领(function),(实在本质上要领也是一种属性)在面向对象的设想形式中,属性是一种形貌,形貌对象的状况,比方一个人一天 24 小时的心情,每一个时候他的心情都具有差别的状况,喜怒哀乐,烦闷癫狂,贪嗔痴念,固然心情只是生而为人的浩瀚状况中的一种罢了。而对象中的要领是一种功用,它的功用就是操纵对象的属性。比方,用饭可以转变一个人的状况,对吃货罢了,吃饱以后会以为迥殊幸运,用饭是一种功用,它转变了一个人的心情,让人以为幸运。
那末,反过来细想,人是一个对象,它具有心情,他还要用饭。所以可以说,对象是对属性和要领的一种封装。
0x01 南拳北腿
对象中的几个观点:
统统事物皆对象
对象具有封装和继续特征
对象与对象之间运用音讯通讯,各自存在音讯隐蔽
然则,面向对象仅仅是一个观点或许编程头脑罢了,它不应当依赖于某个言语存在。比方 Java 采纳面向对象头脑构造其言语,它完成了类、继续、派生、多态、接口等机制。然则这些机制,只是完成面向对象编程的一种手腕,而非必需。换言之,一门言语可以依据其自身特征挑选适宜的体式格局来完成面向对象。
JavaScript 言语是经由过程一种叫做原型(prototype) 的体式格局来完成面向对象编程的。
所以无论是基于类的(class-based)面向对象,照样 基于原型的 (prototype-based) 面向对象 也都只是为完成面向对象这一理念在构造客观天下的两种差别体式格局罢了。
0x02 类 or 原型
在基于类的面向对象体式格局中,对象(object) 依托 类(class) 来发生。而在基于原型的面向对象体式格局中,对象(object) 则是依托 构造器(constructor) 应用 原型(prototype) 构造出来的。
而关于这两种体式格局谁更加完整地表达了面向对象的头脑,现在另有争辩。
类是一个笼统观点而并不是实体,而对象的发生是一个实体的发生;
原型体式格局中的构造器 (constructor) 和原型 (prototype) 自身是其他对象经由过程原型体式格局构造出来的对象。
在类式面向对象言语中,对象的状况 (state) 由对象实例 (instance) 所持有,对象的行动要领 (method) 则由声明该对象的类所持有,而且只要对象的构造和要领可以被继续;而在原型式面向对象言语中,对象的行动、状况都属于对象自身,而且可以一同被继续。
JavaScript 是一种基于原型的编程言语,并没有 class 语句,而是把函数用作类。固然,ES6 供应了 class 的语法糖
0x03 JavaScript 中的面向对象
ECMAScript 是一门完整的面向对象的编程言语,JavaScript 是个中的一个变种 (variant)。它供应了 6 种基本数据类型,即 Boolean、Number、String、Null、Undefined、Object。为了完成面向对象,ECMAScript设想出了一种异常胜利的数据构造 – JSON(JavaScript Object Notation), 这一典范构造已可以离开言语而成为一种广泛应用的数据交互花样。
ECMAScript除了字面式声明(literal notation) 体式格局以外, 许可经由过程构造器(constructor) 建立对象。每一个构造器实际上是一个函数(function) 对象, 该函数对象含有一个prototype
属性用于完成基于原型的继续(prototype-based inheritance) 和同享属性(shared properties)。对象可以由 “new 关键字 + 构造器挪用” 体式格局来建立。
但须要指出的是,这与java言语的new寄义毫无关系,由于其对象构造的机理完整差别。ECMAScript 完整可以用别的非new表达式来用挪用构造器建立对象。
0x04 原型链
涉及到继续这一块,Javascript 只要一种构造,那就是:对象。在 javaScript 中,每一个对象都有一个指向它的原型对象(prototype)的内部属性_proto_属性。而这个原型对象又有本身的原型,直到某个对象的原型为 null 为止(也就是不再有原型指向),构成这条链的末了一环。这类一级一级的链构造就称为原型链(prototype chain)。
一张典范的 JavaScript 原型链图可以展现统统:
要邃晓上图,只须要搞邃晓两个属性(指针)的区分,等于_proto_ 属性和 prototype 属性。
每一个构造函数都有一个 prototype 属性,该属性是一个指针,指向该构造函数的原型。
而实例中包括一个属性 _proto_ 属性,该属性是一个指针,指向该实例所属的构造函数建立的原型。
差别的浏览器对实例中的 _proto_ 属性示意差别。
每建立一个构造函数便会响应的建立一个与其相对应的原型对象(由构造函数建立出来的原型对象,JS 引擎自动建立)。
在默许情况下,构造函数建立的原型对象都邑有一个 constructor 属性,而这个属性指向 prototype 属性地点的谁人函数。
所以,我们可以得出一个结论,构造函数的 prototype 和由该构造函数建立的实例的 _proto_ 指向的是内存中的的统一块地点,也正是如此,才使得在原型中定义的要领和属性具有同享的基本。
有了 原型链,便可以定义一种所谓的 属性隐蔽机制,并经由过程这类机制完成继续。ECMAScript 划定,当要给某个对象的属性赋值时,诠释器会查找该对象原型链中第一个含有该属性的对象(注:原型自身就是一个对象,那末原型链即为一组对象的链。对象的原型链中的第一个对象是该对象自身)举行赋值。
所以,当试图接见一个对象的属性时,它不仅仅在该对象上征采,还会征采该对象的原型,以及该对象的原型的原型,依此层层向上搜刮,直到找到一个名字婚配的属性或抵达原型链的末端。
0x05 JavaScript 的类式继续完成
基于原型的继续体式格局,虽然完成了代码复用,但其行文松懈且不够流通,可浏览性差,不利于完成扩大和对源代码举行有效地构造治理。不能不认可,类式继续体式格局在言语完成上更具健壮性,且在构建可复用代码和构造架构顺序方面具有显著的上风。
0x06 JavaScript 私有成员完成
JavaScript 没有完成面向对象中的信息隐蔽,即私有和公有。与其他类式面向对象那样显式地声明私有公有成员的体式格局差别,JavaScript 的信息隐蔽就是靠闭包完成的。