JS的原型链的分析网上有大把,比如这种:
不过有必要把简单的东西复杂化吗?
其实理解JS原型链只需要理解一个准则,那就是:
var o = new Object();
在面向对象编程(OOP)的语言,比如Java或者c++ 中,这是我们创建对象的最简单途径。但是JS这门语言从它的诞生起就比较奇葩,因为它不是面向对象语言,但JS却又处处是对象,所以我们一般把JS称做基于对象的函数式动态语言,加上大家常说的弱类型这一点让JS非常灵活,但我觉得弱类型压根不是JS区别于OOP语言的最根本的原因。我们往下看:
在JS中创建对象,我们习惯于这样做:var o = {}; 或者直接 var o; 当然这只是语法糖罢了,我们也可以写全:var o = new Object();
说白了,JS的创建对象和OOP语言没有本质区别,甚至一模一样,那这和我们要说的原型链有什么关系呢?
当然有关系的,OOP的三个要素:封装,多态,继承。JS有很好的封装特性,因为JS处处是对象;但JS的多态和继承特性是很不明显的,因为JS没有类的概念。不过我们却可以在JS中实现类似“类”的功能,来满足继承需求。这个实现便是原型链(prototype):
var o1= new Class1(); // 这句话隐含了 o1.__proto__ == Class1.prototype,就是我们的实例化
var o2 = new Class2();
Class2.prototype.__proto__ == Class1.prototype;//这句话等同于Java的 Class2 extends Class1 ,让Class2继承了Class1
--XXX.prototype 其实就是一个XXX类的作用域对象,通过一个__proto__ 引用我们就实现了单根继承
--那么Class1.prototype.__proto__等于什么呢?我们没有手动改变之前,Class1.prototype.__proto__ == Object.prototype,即所有的类都默认继承于Object类。
所以很显然了,对于记不住原型链关系那一大串的,你只要知道prototype 是“类”标识,只要出现了prototype 那便是出现了“类”,对于一般的我们所说的“对象” 比如上面的o1,o2 他们是没有prototype 这个属性的,因为o1和o2是“对象”,而不是“类”。
总结一下:
1.任何对象都有一个__proto__引用,指向实例化它的类的prototype,对于JS就是指向一个函数。
2.任何“类”都有一个prototype原型对象,它定义了类作用域。
3.对象不是类,所以对象没有prototype;但是类却是特殊的对象,所以它不仅有prototype,当然也有__proto__。
讨论到这里,我想补充一点,上面讨论的“类”的这个概念都是我们自己定义的,因为JS(es6之前)没有这样的概念。
那么怎么定义一个“类”比如F1类呢?这个不多讲,用函数,我们先看看JS的函数定义:
function F1(){ } //其实这句话也是语法糖,它的本质是:var F1 = new Function();
//即F1.__proto__ == Function.prototype ,F1类是Function类的一个实例对象
//并且,系统自动多了一句 创建F1.prototype ,F1.prototype .__proto__ == Object.prototype ,F1类继承于Object类
聪明的你一定懂了,Function其实就是一个“类”,F1不过是这个类的一个实例对象罢了。然而问题来了,F1这个对象可不一般,因为它也是个类!
也就是说不仅Function是类,F1也成了类。你可以理解当类是Function ---这个特殊的本地代码实现的特别类时,实例化对象F1也自动变成了类,所以F1拥有了prototype属性(这个类标识属性)。
而对于Function这个特殊类:
Function.__proto__ == Function.prototype == nativeCode //我实现我自己。
而对于所有类的默认祖先Object类:
Object.__proto__ == Function.prototype == nativeCode //你可以理解为Object是Function的一个实例,自己也变成了类。和上面的F1是一样的,不过Object是所有普通类的根源罢了。
Object.prototype.__proto__ == null
除此之外,没有其他任何需要你记忆的
那么再总结一下:
1.JS中创建任何类都要通过“Function这个本地代码实现的超级类" 来实例化。
2..类可以实例化对象(通过new)
3..而Function类也可以实例化对象(也是new,不过变体成了function这个语法糖),不过这个实例化对象叫做“类”
Function是所有类的爹,类是所有对象的爹,Object类是所有类的老大。