js中对象分为普通对象
和函数对象
,区别在于,普通对象
的__proto__
属性直接指向Object.prototype
,所以对我们来说,讨论普通对象的原型并没有意义,下面我们主要讨论的是函数对象
。
函数对象
(也叫构造函数的实例),顾名思义是由函数构造的对象
function Person() {}
var person = new Person();
console.log(typeof person);
// object
接下来我们来了解与原型有关的几个属性:
原型
1. prototype
函数才会有prototype
function Person() {}
Person.prototype.name = "zhang";
var person = new Person();
console.log(person.name);
// zhang
每一个构造函数
都会有一个prototype
属性,他指向了该构造函数的原型对象
2. constructor
构造函数
的prototype
指向了该构造函数的原型
,那反过来构造函数的原型有没有指向构造函数的属性呢,答案是有的,就是constructor
function Person() {}
var person = new Person();
console.log(Person.prototype.constructor === Person);
// true
3. __proto__
对象才会有__proto__
实例对象
有一个__proto__
属性,他指向了该构造函数的原型对象
function Person() {}
var person = new Person();
console.log(person.__proto__ === Person.prototype);
// true
这就是原型链的开始!
原型链
原型对象也是对象,所以Person.prototype
也会有__proto__
属性,
Person.prototype.__proto__
指向的是Object.prototype
,也就是构造函数的终点,因为Object.prototype.__proto__ === null
。
在对象中,查找变量的方式是从自身开始,如果没有就查找原型,原型再没有就查找原型的原型...,如果查找到就停止,如果没有就直到查找到null
结束。
function Person() {}
Person.prototype.name = "zhang";
var person = new Person();
console.log(person.name);
// zhang
更新!
7-2e46944f58df.png)图中绿色的线为原型链
原型继承
原型继承是js继承方法的一种,也是用的最多的一种。
function Person(name, age) {
this.name = name;
this.age = age;
}
function Gender(gender) {
this.gender = gender;
}
Person.prototype = new Gender("男");
Person.prototype.constructor = Person;
var a = new Person("zhang", 12);
console.log(a.gender);// 男
原型继承的方法只需要将要继承的构造函数挂载到原构造函数的prototype
上,这样一来,在对象里找不到变量的时候,变会去找该对象的__proto__
属性,也就是Person.prototype
。
这里有一个问题就是我们在给Person.prototype赋值的时候,constructor属性也一并带过去了,这就会出现Person.prototype.constructor === Gender的现象,但这明显是不合理的,所以在12行,重新使Person.prototype.constructor指向Person,这样我们再回溯整个原型链的时候不至于混乱。