一、什么是原型
原型是继承中的基础,JavaScript的继承就是基于原型的继承。
JavaScript原型是指为其他对象提供共享属性访问的对象。在创建对象时,每个对象都包含一个隐式引用指向它的原型对象或者null。
原型对象也是对象,这个对象也有自己的原型对象,我们称为原型对象的原型对象。这样就构成一个原型链。
二、函数的原型对象
我们在创建函数的同时,浏览器会在内存中创建一个对象。这个函数中默认有一个prototype属性,指向了该对象。这个对象就是函数的原型对象,简称函数的原型。
每个构造函数都有一个原型对象存在,这个原型对象通过构造函数的prototype属性来访问。原型对象默认会有一个constructor属性指向构造函数。
三、原型的相关属性及方法
1、prototype属性
prototype是函数独有的,存在于构造函数中,它是从一个函数指向一个对象。
它的含义是函数的原型对象,也就是这个函数所创建的实例的原型对象。
它的作用是包含可以由特定类型的所有实例共享的属性和方法。
2、constructor属性
constructor属性是对象所拥有的,它是从一个对象指向一个函数。
3、__proto__ 属性
__proto__属性是对象所独有的,它是从一个对象指向一个对象,也即指向它们的原型对象。
它的作用是当访问一个对象的属性时,如果该对象内部不存在这个对象,那么就会去它的__proto__属性所指向的那个对象(即父对象)里面找,如果父对象也不存在这个属性,则继续往父对象的__proto__属性所指向的那个对象里面找,如果还没找到,就继续往上找,直到原型链顶端null。
4、hasOwnProperty() 方法
它的作用是判断函数的原型所在位置。一个对象本身添加的属性返回true,在原型中的属性和不存在的属性都会返回false。
以上属性及方法简单例子:
//创建构造函数
function Person(){}
//使用Person.prototype直接访问到原型对象
// 给Person函数的原型对象中添加一个属性name,值是"小明"
// Person.prototype.name = "小明";
Person.prototype = {
constructor:Person, //让constructor重新指向Person函数
/*如果直接给Person的原型指定对象字面量(没有上面这一行),
这个对象的constructor属性不再指向Person函数*/
name: "小明"
};
//创建一个实例对象p1
var p1 = new Person();
//访问p1对象的属性name
p1.age = 18;
console.log(Person.prototype.constructor === Person);
//输出结果是:true
//如果在Person.prototype中没有constructor:Person这一行代码则输出flase
//Person.prototype.name = "小明";这种写法输出也是true
console.log(p1.__proto__ === Person.prototype);
//输出结果是:true
//如果在Person.prototype中没有constructor:Person这一行代码则输出flase
//Person.prototype.name = "小明";这种写法输出也是true
console.log(p1.name);
//输出结果是:小明
/*虽然在p1对象中没有明确的添加属性name,但是仍然可以成功打印的原因是:
p1的__proto__属性指向的原型中有name属性,所以可以访问到属性name值。*/
console.log(p1.hasOwnProperty("age"));
//输出结果是:true
//因为age属性是直接在p1属性中添加的
console.log(p1.hasOwnProperty("name"));
//输出结果是:false
//因为name属性是在原型中添加的
console.log(p1.hasOwnProperty("sex"));
//输出结果是:false
//因为sex属性不存在
四、构造函数、原型对象、实例对象的关系
构造函数、原型对象、实例对象的关系:
①每个构造函数都有一个prototype属性,这个属性指向了原型对象。
②每个实例对象都有一个__proto__属性,这个属性指向了对象的原型对象。
③在原型对象里有一个constructor属性,该属性指向了构造函数。
三者关系示意图如下: