任何函数都有prototype
属性,prototype
是原型的意思。
prototype
的属性值是个对象,它默认拥有constructor
属性指回函数。
构造函数的prototype
属性是它的实例的原型。
// 定义一个构造函数
function Person(name, age) {
this.name = name;
this.age = age;
}
// 使用 new 操作符创建一个对象实例
var person1 = new Person("Tom", 23);
console.log(person1.name); // Tom
console.log(person1.age); // 23
每个构造函数在创建时都拥有一个prototype属性,prototype属性也就是指向函数的原型对象。在默认情况下,所有的原型对象都会增加一个constructor属性, 并指向prototype属性所在的函数,即构造函数。
通过new调用构造函数创建的实例,实例拥有一个__proto__
属性,指向构造函数的原型对象,因此__proto__
属性可以看作是一个连接实例与构造函数的原型对象的桥梁。
function Person(name, age) {
this.name = name;
this.age = age;
}
var p1 = new Person("小明", 18);
var p2 = new Person("小花", 28);
console.log(Person.prototype === p1.__proto__); //true
console.log(Person.prototype === p2.__proto__); //true
console.log(Person.prototype.constructor === Person); //true
说明:构造函数Person的prototype
属性指向Person的原型对象,person1实例和person2实例的__proto__
隐式属性指向Person的原型对象。
对象的每个实例都具有一个__proto__
属性,指向的是构造函数的原型对象,而原型对象同样存在一个__proto__
属性指向上一级构造函数的原型对象,就这样层层往上,直到最上层某个原型对象为null
。
在JavaScript中几乎所有的对象都具有__proto__
属性,由__proto__
属性连接而成的链路构成了JavaScript的原型链,原型链的顶端是Object.prototype
,它的__proto__
属性为null
。
function Person() {}
var p = new Person();
console.log(p.__proto__ === Person.prototype); //true
console.log(Person.prototype.__proto__ === Object.prototype); //true
console.log(Object.prototype.__proto__ === null); //true
当我们通过对象的实例读取某个属性时,是有一个搜索过程的。它会先在实例本身去找指定的属性,如果找到了,则直接返回该属性的值;如果没找到,则会继续沿着原型对象寻找;如果在原型对象中找到了该属性,则返回该属性的值。
function Person() {
this.name = "小明";
}
Person.prototype.name = "小花";
var p = new Person();
console.log(p.name); //小明
通过使用 hasOwnProperty
可以确定访问的属性是来自于实例还是原型对象。
var person = {
name: 'Alice'
};
console.log(person.hasOwnProperty('name')); // true
console.log(person.hasOwnProperty('toString')); // false,toString是Object原型上的方法,不属于person对象自身
in操作符则是用来检查对象及其原型链上是否包含某个属性。
var person = {
name: 'Alice'
};
console.log('name' in person); // true
console.log('toString' in person); // true,toString属于Object原型,被person继承