原型
在javascript中,原型分有两种:显示原型(prototype)和隐式原型(__proto__)。
__proto__(隐式原型)
JavaScript中任意对象都有一个内置属性[[prototype]],在ES5之前没有标准的方法访问这个内置属性,但是大多数浏览器都支持通过__proto__来访问。ES5中有了对于这个内置属性标准的Get方法Object.getPrototypeOf().
prototype(显式原型)
这是函数对象特有的属性。这个属性是一个指针,指向一个对象,这个对象的用途就是包含所有实例共享的属性和方法(我们把这个对象叫做原型对象)。原型对象也有一个属性,叫做constructor,这个属性包含了一个指针,指回原构造函数。
例如:
var a = {}; console.log(a.__proto__); // => Object {…} console.log(a.prototype); // => undefined function b(){} console.log(b.__proto__) // => function () { [native code] } console.log(b.prototype) // => Object {…}
注:Object.prototype的__proto__值为null。
区分__proto__与prototype
定义
这两个名次的概念在上文中已经做了解释,不赘述。
作用
prototype:用来实现基于原型的继承与属性的共享。
__proto__:构成原型链,同样用于实现基于原型的继承。
二者的关系
__proto__在es5里指向构造函数的prototype,在es6里指向该构造函数。
小结
1.任意对象(在javascript中,所有东西都是对象)都有属性__proto__,指向该对象的构造函数的原型对象(prototype)。
2. 函数对象除了有属性__proto__,还有属性prototype,prototype指向该方法的原型对象(prototype)。
原型链
在javascript中,每个对象和原型对象(prototype)都有一个原型(__proto__),对象的原型指向构造函数(父)的原型对象(prototype),而原型对象(prototype)的原型(__proto__)指向父的父的原型对象(prototype),这样便形成了通过原型层层连接起来的关系,我们把它称为原型链。听起来很拗口,我简单画了个图希望能帮助你理解:
由上图可见,__proto__是实现原型链的关键,而prototype则是原型链的组成。另外,所有构造器/函数的__proto__都指向Function.prototype,它是一个空函数(Empty function)。
原型链继承
在访问一个对象的某个属性时,首先在该对象的内部查找,若有则返回给属性值,若没找到,则从该对象的原型(__proto__)所指向的原型对象(构造器的prototype)中查找,若还是找不到,则继续从该原型对象(prototype)的原型(__proto__)所指向的原型对象中查找,以此类推,知道找到为止,若找不到则返回undefined。
利用这一思想,我们直接将子类的原型对象指向父类的某个实例,则子类创建的所有实例都会继承了父类的所有属性,这就是原型链继承。如:
function Parant (name, age) { this.name = name; this.age = age; } Parant.prototype.say = function(){ console.log(‘hello, my name is ‘ + this.name); }; function Child() { } Child.prototype = new Parant(‘pursue‘); var man1 = new Child(); man1.say(); //hello, my name is pursue var man2 = new Child(); console.log(man1.say === man2.say);//true console.log(man1.name === man2.name);//true