prototype
只有函数有prototype属性
let a = {}let b = function () { }console.log(a.prototype) // undefinedconsole.log(b.prototype) // { constructor: function(){...} }
其实Object
是一个全局对象,也是一个构造函数,以及其余根本类型的全局对象也都是构造函数:
function outTypeName(data, type) { let typeName = Object.prototype.toString.call(data) console.log(typeName)}outTypeName(Object) //[object Function]outTypeName(String) // [object Function]outTypeName(Number) // [object Function]
为什么只有函数有prototype属性
JS通过new
来生成对象,然而仅靠构造函数,每次生成的对象都不一样。
有时候须要在两个对象之间共享属性,因为JS在设计之初没有类的概念,所以JS应用函数的prototype
来解决这部分须要被共享的属性,通过函数的prototype
来模仿类:
当创立一个函数时,JS会主动为函数增加prototype
属性,值是一个有constructor
的对象。
以下是共享属性prototype
的栗子:
function People(name) { this.name = name}People.prototype.age = 23 // 岁数// 创立两个实例let People1 = new People('OBKoro1')let People2 = new People('扣肉')People.prototype.age = 24 // 长大了一岁console.log(People1.age, People2.age) // 24 24
People1
和People2
的原型是People.prototype
原型链
__proto__
和Object.getPrototypeOf(target)
: 对象的原型
__proto__
是对象实例和它的构造函数之间建设的链接,它的值是:构造函数的`prototype。
也就是说:__proto__
的值是它所对应的原型对象,是某个函数的prototype
Object.getPrototypeOf(target)
全等于__proto__
。
它是ES6的规范,兼容IE9,支流浏览器也都反对。
不要再应用__proto__
:
__proto__
属性没有写入 ES6 的注释,而是写入了附录。- 起因是它实质上是一个外部属性,而不是一个正式的对外的 API,只是因为浏览器广泛支持,才被退出了 ES6。
- 规范明确规定,只有浏览器必须部署这个属性,其余运行环境不肯定须要部署,而且新的代码最好认为这个属性是不存在的。
- 所以无论从语义的角度,还是从兼容性的角度,都不要应用这个属性,应该应用:
Object.getPrototypeOf(target)
(读操作)、Object.setPrototypeOf(target)
(写操作)、Object.create(target)
(生成操作)代替
构造函数是什么
所谓的构造函数,实际上就是通过关键字new
来调用的函数:
let newObj = new someFn() // 结构调用函数
原型继承就是利用结构调用函数的个性:
SubType.prototype = new SuperType(); // 原型继承:SubType继承SuperTypeSubType.prototype.constructor = SubType // 从新指定constructor指向 不便找到构造函数// 挂载SuperType的this和prototype的属性和办法到SubType.prototype上
- 结构调用的第二点:将新对象的
Object.getPrototypeOf(target)
指向函数的prototype
- 结构调用的第三点:该函数的this会绑定在新创建的对象上。(所以父类
this
申明的属性被所有子类实例共享) - 新对象赋值给
SubType.prototype
原型链是什么
来看个例子:
function foo() { }const newObj = new foo() // 结构调用foo 返回一个新对象const newObj__proto__ = Object.getPrototypeOf(newObj) // 获取newObj的原型对象newObj__proto__ === foo.prototype // true 验证newObj的原型指向fooconst foo__proto__ = Object.getPrototypeOf(foo.prototype) // 获取foo.prototype的原型foo__proto__ === Object.prototype // true foo.prototype的原型是Object.prototype
能够用以下三句话来了解原型链:
- 每个对象都领有一个原型对象:
newObj
的原型是foo.prototype
。 - 对象的原型可能也是继承其余原型对象的:
foo.prototype
也有它的原型Object.prototype
。 - 一层一层的,以此类推,这种关系就是原型链。
原型链的起点: Object.prototype
Object.prototype
是原型链的起点,所有对象都是从它继承了办法和属性。
Object.prototype
没有原型对象:
const proto = Object.getPrototypeOf(Object.prototype) // null