我们创建的每一个函数,解析器都会向函数中添加一个属性 prototype
这个属性对应着一个对象,就是原型对象。
如果函数作为普通函数,调用 prototype 没有任何作用
当函数以构造函数的形式调用时,它所创建的对象都会有一个隐含的属性 __proto__,
我们可以通过 __proto__ 来访问原型对象
原型对象就相当于一个公共区域,同一个构造函数的实例都能访问到这个原型对象
我们可以将对象共有的内容,统一设置到原型对象中
创建构造函数时,可以将对象共有的属性和方法,统一添加到构造函数的原型对象中,
这样不用分别为每一个对象添加,也不会影响到全局作用域,就可以使每个对象都具有这些属性和方法了
当我们访问对象的一个属性或者方法时,他会先在对象自身中寻找,如果有则直接使用,
如果没有则会去原型对象中寻找,如果有则直接使用。
如果原型对象中也没有,则会在原型对象的原型对象中寻找,一层一层往上找,直到找到Object的原型对象,
如果没有,就没有这个属性或方法
拿到原型对象:
// 拿到原型对象:
function method1() {
// 构造函数
function Person() {
}
// 原型对象
let yuanxing = Person.prototype;
// 实例化对象
let person1 = new Person();
// 通过对象找到原型对象 person1.__proto__
console.log(yuanxing == person1.__proto__);
// 任何对象都可以找到原型对象 person2.__proto__
let person2 = new Person();
console.log(yuanxing == person2.__proto__);
}
调用对象属性和方法,先在自身找,自身没有在原型对象中找
//调用对象属性和方法,先在自身找,自身没有在原型对象中找
function method2() {
// 构造函数
function Person() {
}
// 向原型对象中添加属性和方法
Person.prototype.name = 'zhh';
Person.prototype.method = function (args) {
console.log('原型对象的方法>>>' + args);
}
// 调用对象属性和方法,先在自身找,自身没有在原型对象中找
let person1 = new Person();
let person2 = new Person();
console.log(person1.name = 'peson1');
person1.method('person1调用');
console.log(person2.name = 'perso2');
person2.method('person2调用');
}
原型对象也是对象,所以它也有原型(就是原型对象的原型对象)
当我们使用一个对象的属性或方法时,会先在自身找,
自身有,则直接使用
自身没有,则去原型对象中寻找,如果原型对象中有,则使用
如果原型对象中也没有,则去 原型对象的原型对象 中去寻找。
以此类推向上寻找,直到找到Object的原型对象,Object 的原型对象,没有原型对象,
如果依然没找到则返回 unedfined
function method3() {
// 构造函数
function Person() {
}
let person = new Person();
// person 对象中没有 toLocaleString() ; 调用的是原型对象中的方法
person.toLocaleString();
// 下面查找 toLocaleString() 在哪一级的原型对象里面
// hasOwnProperty() 对象自身是否含有某个属性或方法
// person 中是否有 toLocaleString 方法
console.log(person.hasOwnProperty('toLocaleString'));
// person的原型对象中是否有 toLocaleString 方法
console.log(person.__proto__.hasOwnProperty('toLocaleString'));
// person的原型对象的原型对象中是否有 toLocaleString 方法
// 打印结果是true
// 说明person.toLocaleString()调用的是person.__proto__.__proto__中的toLocaleString方法
console.log(person.__proto__.__proto__.hasOwnProperty('toLocaleString'));
}
OK,讲完了
下面是一个综合的例子:
下面对原型对象进行深层次的解析
1、原型对象在堆栈存储
看下面一段代码:
上面代码,堆栈是示意图,(很重要,这个图比上面Person示意图要详细)
2、构造函数和原型对象的相互指向
构造函数对象的 prototype 属性,指向原型对象
原型对象中的 constructor 指向构造函数对象
看下面一段代码:
图解:
3、几个重要概念和结论
I、两个概念:
1.显式原型对象 函数对象.prototype
2.隐式原型对象 实例对象.__proto__
II、Function 和Object 的三个重要结论
1、函数的原型对象都是Object的实例(但Object除外)
2、所有的函数对象都是 Function 的实例 (Function 是他自己的实例)
3、Object 的原型对象是原型链的尽头
上面3个结论的验证:
1、函数的原型对象都是Object的实例(但Object除外)
/*
* 1、函数的原型对象都是Object的实例(但Object除外)
*/
// Person的原型对象,是Object 实例
console.log(Person.prototype instanceof Object);
// Object的原型对象不是Object 实例
console.log(Object.prototype instanceof Object);
// Function的原型对象,是 Object 实例
console.log(Function.prototype instanceof Object);
2所有的函数对象都是 Function 的实例 (Function 是他自己的实例)
/*
* 2所有的函数对象都是 Function 的实例 (Function 是他自己的实例)
*/
{
// 例如:Dog函数对象,内部就是 new Function()得到的
// 所以 Dog 就是 Function 的实例
function Dog() {
}
// 实例化对象
let dog = new Dog();
// 对象中添加方法
dog.method = function() {
console.log('对象中添加方法');
}
dog.method();
}
{
// 上面的代码可以写成这样
// Dog是构造函数对象
let Dog = new Function();
// 实例化对象
let dog = new Dog();
// 对象中添加方法
dog.method = function() {
console.log('对象中添加的方法2');
}
dog.method();
}
// Function是自己的实例
// Function.prototype 的Function是函数对象
// Function.__proto__ 的Function是实例对象
console.log(Function.prototype == Function.__proto__);
3.Object 的原型对象是原型链的尽头
/*
* 3.Object 的原型对象是原型链的尽头
*/
console.log(Object.prototype.__proto__);
根据上面的三条结论验证 instanceof 判断时原型链的指向
例子1:
// 案例1
function Foo() {
}
let foo = new Foo();
console.log(foo instanceof Foo);
console.log(foo instanceof Object);
console.log(foo instanceof Foo); 结果是true,示意图如下:
console.log(foo instanceof Object);结果true,示意图如下:
例子2
// 案例2
console.log(Object instanceof Function);
console.log(Object instanceof Object);
console.log(Function instanceof Function);
console.log(Function instanceof Object);
function Fooo(){}
console.log(Object instanceof Fooo);
console.log(Object instanceof Function); 结果true,示意图如下:
console.log(Object instanceof Object);结果是true,示意图如下:
console.log(Function instanceof Function);结果是true,示意图如下:
console.log(Function instanceof Object);结果是true,示意图如下:
function Fooo(){}
console.log(Object instanceof Fooo);结果是 false 结果如下:
OK,原型对象全部讲完了
参考视频
http://www.gulixueyuan.com/my/course/58
http://www.gulixueyuan.com/course/194
js继承机制的设计思想
http://www.ruanyifeng.com/blog/2011/06/designing_ideas_of_inheritance_mechanism_in_javascript.html