本系列是学习整理js中的面向对象的第3篇,原型和构造函数的关系,接下来就要更深入的探究其中的原理了。
原型和构造函数到底有什么关系?
构造函数有原型对象,Person.prototype,此对象中有属性constructor,指向了构造函数Person,构造函数又有原型…
1 | Person.prototype.constructor===Person;//true |
构造函数是为了方便创建对象。
构造函数通过prototype来存储要共享的属性和方法。
prototype和__proto__([[Prototype]])又有什么关系?
类和构造函数:比如Array你可以看做一个类,也可以看成是Array的构造函数。
__proto__
:是实例的属性,指向构造函数的原型 constructor.prototype,每个对象都有。所以我们暂且称它为原型引用。
prototype
:原型对象,只有函数才有prototype,所以原型是构造函数(类)的原型。
我们先来回忆下new操作符到底做了什么【参见js中的面向对象2】。
就是new操作符实现了实例的__proto__
指向类的原型。
1 | // __proto__是new出来的实例内部包含的一个指针,指向constructor.prototype。每个对象都有 |
prototype和实例又有什么关系呢?
prototype是用来保存类的公共属性和方法的,其实也是个特殊的对象,可以理解为和实例是一个level的。但是他们之间有什么关系和区别呢
1 | // 联系 |
既然是一个level为啥不相等呢?因为原型肩负了继承的重要责任。
正是通过Person.prototype.__proto__.__proto__.__proto__.__proto__.__proto__
来一层层向上查找父类,这就是所谓的原型链
所以继承的写法就是
1 | Person.prototype=new Parent(); |
结合前面new的作用,可以明白此处实际上的最重要的作用就是
1 | Person.prototype.__proto__=Parent.prototype;// 将原型引用指向父类的原型 |
调用p.name时,会从p自身的属性中寻找是否有name,没有则到p对应的原型中寻找obj.__proto__.__proto__.__proto__
形成原型链,可以通过instanceof来验证obj是否是构造函数(类)的实例
继承的细节将在下节来详细解释
Object和Function的关系及特殊的原型对象
1 | var obj1= {x: 1}; |
原型的相关方法
1 | Object.getPrototypeOf(p) === Person.prototype; // true |
基本类型判断
但是instanceof也有力不从心的时候,回忆下我们判断isArray,isDate等类型的方法,instanceof假定只有一个全局作用域,在页面中有多个frame时,存在两个以上的全局执行环境,一个框架向另一个框架传值时,会有不一样的构造函数。建议使用以下方式来判断。
1 | function isType(type) { |
注意事项
1 | function Person(age, name, friends) { |
参考
https://github.com/creeperyang/blog/issues/9
https://www.zhihu.com/question/34183746