众所周知JavaScript是一门面向对象语言。
与其他面向对象语言相比 JavaScript中的「对象」又显得很是特别。
说白了就是各语言对 Object(对象)的抽象描述不一样。
其中最成功的C++、Java、C# 等流行的编程语言,使用「类」的方式来描述对象。
还有一种就是基于原型的编程语言,它们利用「原型」来描述对象,我们的 JavaScript 就是其中代表。
「基于类」的编程提倡使用一个关注分类和类之间关系开发模型。在这类语言中,总是先有类,再从类去实例化一个对象。类与类之间又可能会形成继承、组合等关系。类又往往与语言的类型系统整合,形成一定编译时的能力。
与此相对,「基于原型」的编程看起来更为提倡程序员去关注一系列对象实例的行为,而后才去关心如何将这些对象,划分到最近的使用方式相似的原型对象,而不是将它们分成类。
ES6 引入了类的概念 使之“看起来更像类” 本质还是基于原型。
JavaScript 对象的特征
1. 对象具有唯一标识性:即使完全相同的两个对象,也并非同一个对象。
2. 对象有状态:对象具有状态,同一对象可能处于不同状态之下。
3. 对象具有行为:即对象的状态,可能因为它的行为产生变迁。
基于原型的对象设计使得 JavaScript对象具有高度动态性。
JavaScript 赋予了使用者在运行时为对象添改状态和行为的能力,而其他语言是无法实现的,这是因为任何语言运行时类的概念都是被弱化的。
(优点也同时是缺点)
var o = { a: 1 } o.b = 2 console.log(o.a, o.b) // 1 2
请参考 (js 原型原型链)
我们理解了什么是原型原型链,但这样的设计具有什么好处呢?
做一个实验:
function Person (name) { this.name = name this.getName = function () { return this.name } } var a = new Person('小红') var b = new Person('小明') console.log(a.getName === b.getName) // false
这表明是什么意思呢?a和b各自的getName是一个函数,但它们是两个不同的函数,虽然函数名称和代码都是相同的!
如果我们通过new Person()创建了很多对象,这些对象的getName函数实际上只需要共享同一个函数就可以了,这样可以节省很多内存。
那么如何解决这个问题呢?
我们知道(原型链四大理论第三条)「所有引用类型的隐式原型指向它构造函数的显式原型」也就是实例的__proto__指向构造函数的prototype,那么下述代码成立。
console.log(a.__proto__.getName === b.__proto__.getName) // true
我们尝试修改上面代码,直接把getName函数放到Person构造函数的prototype上。
function Person (name) { this.name = name } Person.prototype.getName = function () { return this.name } var a = new Person('小红') var b = new Person('小明') console.log(a.getName === b.getName) // true
答案估计小伙伴们早已经想到了(原型链四大理论第四条)「当试图得到一个对象的某个属性时,如果这个对象本身没有这个属性,那么它会去到__proto__中寻找」
再打个比方 我们声明一个新的空对象。
var obj = {}
这个操作其实并不真的去复制一个原型对象,而是使得新对象持有一个原型的引用。
世界奇奇怪怪 你却可可爱爱
下回见!