函数的prototype解析
1、函数的prototype属性
(1) 每个函数都有一个prototype属性,它默认指向一个Object空对象。(称为原型对象)
例1:console.log(typeof Date.prototype,Date.prototype);
运行结果显示:
例2:定义一个新的函数:function Fun(){ }
console.log(Fun.prototype);
运行结果显示为:
可以看出,例1,2都指向了默认的Object空对象。那么什么是空对象?就是没有后定义(fun())自己的属性。
(2)原型对象中有一个属性constructor,它指向函数对象。
可以验证一下:
console.log(Date.prototype.constructor === Date); //结果为true
console.log(Fun.prototype.constructor === Fun);//结果为true
示意图如下:
当我们给原型对象添加属性(一般为方法),目的是让实例对象去访问。
例如:Fun.prototype.test = function(){console.log("test()");}
var fun = new Fun();//创建实例fun
fun.test();//输出test()
2、给原型对象添加属性(一般为方法)
作用:函数中的所有实例对象,自动拥有原型中的属性或方法。
3、显式原型与隐式原型
(1)每个函数function都有一个prototype,即显示原型。(默认指向一个空的Object对象)
(2)每个实例对象都有一个__proto__,可称为隐式原型。
可以通过 console.log(fun.__proto__); 来验证实例fun的__proto__属性。
其中,__proto__属性是在实例创建完之后自动添加的。
(3)对象的隐式原型的指对应其构造函数显式原型的值。
可以通过 console.log(fun.__proto__ === Fun.prototype);//结果为true 来验证。
通过上图可以看出实例对象调用原型方法的内部过程。
4、原型链
当访问对象的属性时,先在自身属性中查找,找到就返回;如果没有,则沿着__proto__这条链向上寻找,找到则返回。如果最后没有找到,则返回undefined。结构图如下:
首先在在fun中查找test1,可以在fun实例对象中找到test1方法,并返回结果test1;接下来找test2方法,先在自身中查找,不能找到,则查看__proto__属性,查找隐式原型对象,找到则返回test2;然后是查找toString方法,自身和根据隐式原型属性的隐式原型对象中都没有,然后根据Object的隐式原型属性找隐式原型对象则可以找到。最后找test3,可以知道自身、自身的隐式原型对象以及Object的隐式原型对象中都找不到,则返回undefined。可以知道原型链是按照隐式原型寻找的。原型链的本质就是隐式原型链。
补充:(1)函数的显示原型指向的对象默认是Object的空对象。(但Object不满足,因为object.__proto__=null)
例:console.log(Fun.prototype instanceof Object);//结果为true
console.log(Object.prototype instanceof Object);//结果为false
console.log(Function.prototype instanceof Object);//结果为true
(2)所有函数都是Function的实例(包含Function本身)
例:console.log(Function.__proto__ === Function.prototype);//结果为true
(3)Object的原型对象是原型链的尽头
例:console.log(Object.prototype.__proto__);//结果为null
5、原型链的属性
(1)读取对象属性值时,会自动到原型链中查找。
(2)设置对象属性值时,不会查找原型链,如果当前对象中没有此属性,则直接添加并且设置其值。
例: Fun.prototype.a = 'aaa';
var fun1 = new Fun();
console.log(fun1.a);//结果为aaa
var fun2 = new Fun();
fun2.a = 'bbb';
console.log(fun1.a,fun2.a);//结果为aaa bbb
(3)方法一般定义在原型中,属性一般通过构造函数定义在对象本身上。
例: function Person(name,age){
this.name = name;
this.age = age;
}
Person.prototype.setName = function(name){
this.name = name;
};
var p1 = new Person("Tom",12);
p1.setName("Bob");
console.log(p1);
var p2 = new Person("Helen",18);
p1.setName("Tina");
console.log(p2);
console.log(p1.__proto__ === p2.__proto__);//结果为true
结果显示为: