JavaScript 常被描述为一种基于原型的语言 (prototype-based language)——每个对象拥有一个原型对象,对象以其原型为模板、从原型继承方法和属性。
原型对象也可能拥有原型,并从中继承方法和属性,一层一层、以此类推。这种关系常被称为原型链 (prototype chain),它解释了为何一个对象会拥有定义在其他对象中的属性和方法。
原型
JavaScript 有七种基本类型 String 、 Number 、 Boolean 、 Null 、 Undefined 、 Symbol 、 Object ,前六种为基本数据类型, Object 为引用类型。函数本质上是 Object 类型, Object 继承自己, Function 继承自己,并且相互继承对方,即 Object 和 Function 既是函数也是对象。
console.log(Function instanceof Object); // true
console.log(Object instanceof Function); // true
Object 是 Function 的实例,而 Function 是它自己的实例。
console.log(Function.prototype); // ƒ () { [native code] }
console.log(Object.prototype); // Object
prototype
每个函数对象都会有一个 prototype 属性, prototype 就是调用构造函数所创建的那个实例对象的原型, prototype 可以让所有对象实例共享它所包含的属性和方法。
function Student() {}
Student.prototype = {
from: "sdust"
}
var stu1 = new Student();
var stu2 = new Student();
console.log(stu1.from) // sdust
console.log(stu2.from) // sdust
JS 中所有的对象,都有一个 __proto__ 属性,指向实例对象的构造函数原型。
__proto__
__proto__ 是原型链查询中实际用到的,它总是指向 prototype ,就是指向构造函数 Student 的原型对象 prototype 。例如实例化的 stu 会使用 __proto__ 向 Student 的 prototype 寻找方法或属性。若 stu 寻找到了调用的方法或属性,则不会使用 __proto__ 寻找原型对象。
constructor
每个原型都有一个 constructor 属性指向关联的构造函数 Student ,实例的 constructor 指向构造函数 Student
function Student() {}
var stu = new Student();
console.log(Student.prototype.constructor === Student) // true
console.log(stu.constructor === Student) // true
原型链
原型链可以简单理解为将原型连成一条链, js 每一次获取对象中的属性都是一次查询过程,如果在自有属性中找不到就会去原型对象中查找,如果原型对象中还查不到,就回去原型对象的原型中查找,也就是按照原型链查找,直到查找到原型链的顶端,也就是 Object 的原型。
function parent() {
this.parentInfo = "parent";
}
parent.prototype.getParentInfo = function() {
return this.parentInfo;
};
function child() {
this.childInfo = "child";
}
parent.prototype.getChildInfo = function() {
return this.childInfo;
};
child.prototype = new parent();
var instance = new child();
console.log(instance.getChildInfo()); // child
console.log(instance.getParentInfo()); // parent
console.log(instance.parentInfo); // parent
console.log(instance.__proto__ === child.prototype); //true
console.log(instance.__proto__.__proto__ === parent.prototype); //true
console.log(instance.__proto__.__proto__.__proto__ === Object.prototype); //true
console.log(instance.__proto__.__proto__.__proto__.__proto__ === null); //true
// function student(){}
// console.log(student.__proto__ === Function.prototype) // true
// console.log(Function.__proto__ === Function.prototype) // true
// console.log(Object.__proto__ === Function.prototype) // true
// console.log(Object.prototype.__proto__ === null) // true