关于函数与对象与原型链与继承
从头开始讲起,这依旧是个鸡生蛋还是蛋生鸡的问题。
函数是对象子类,但所有对象都是函数制造的。但当我们谈论函数时,强调的是它作为工具的特性,对象则是强调其键值对合集的特性。
而原型链可以分为作为普通对象的原型链,和作为构造函数的原型链两条路径,两条路径有共同之处,一是它们的原型链的顶点都是Object.prototype(当然最最终顶点还是null外),二是每个对象都有[[prototype]]属性,三是每个对象都可以使用__proto__或者Object.getProtoTypeOf来获取上级的原型属性。
第一点成立是因为每个对象都是函数制造的,而函数也是对象。
(这里被建议修改“大多数对象通过构造函数创建,形成了统一的创建模式”,但为了便于理解就先不修改只注释)
普通对象object实际上是原生构造函数Object()使用new关键词制造的实例化对象,实例没有.prototype属性,但作为构造函数的Object()有,即Object.prototype,即实例.__proto__ = 构造函数.prototype,在普通对象里则是object.__proto__ = Object.prototype;
而所有构造函数都是函数,都可以视作是原生构造函数Function()使用new关键词制造的实例化对象,function._proto_ = Function.prototype,所有函数原型链上都有Function.prototype,这是所有函数祖先。但与此同时所有原生构造函数都是对象,所有对象都有祖先Object.prototype,所以从原型链往上爬,Function.prototype的原型就是Object.prototype——Function.prototype.__proto__ == Object.prototype。
这证明了对象和函数互为因果,变换的关系。
function Cat(){}
const cat1 = new Cat()
console.log(cat1.__proto__ == Cat.prototype);
console.log(Cat.__proto__ == Function.prototype);
console.log(Function.prototype.__proto__ == Object.prototype);
const obj = {}
console.log(obj.__proto__ == Object.prototype);
第二点,所有普通对象与函数都有[[Prototype]]属性,也就是说所有对象都有,但函数的此类属性更“动态”一些,可以有机会拥有新的名字——当一个对象使用new来调用一个函数时,那个函数便可以变成对象的原型,成为构造函数,拥有.prototype属性,此属性继承了其原型链上级的对象属性与方法,原型链连接属性和方法。
(实际上并不是函数变成了对象的原型,是函数的.prototype属性成为了原型,但为了便于理解不修改只注释)
除此之外,任何对象都可以在原型链中扮演"原型"角色,当一个实例或普通对象被当做原型,那它们自身便可以成为原型链上的一环,被调用属性。