javascript的原型理解
当一个函数被声明为构造函数的时候,就会出现一个属性叫做prototype,该属性类型为对象。
我们可以通过这个属性为构造函数添加其他的方法或者属性。
function Fish( name,color){
this.name= name;
this.color= color;
}
//可以通过prototype额外给他们赋值
Fish.prototype.width=1000;
Fish.prototype.swing =function(){ console.log(this.name+" I can swing")};
//现在创建两条鱼,查看他们是否都具有上面的方法和属性
var fish1 = new Fish("xiao hong","yellow");
var fish2 = new Fish("xiao bai "," green");
fish1.swing();//xiao hong I can swing
fish2.swing();//xiao bai I can swing
console.log(fish1.__proto__.width);//1000
console.log(fish1.__proto__.name);//undefined 说明只能找到原型的属性和方法
console.log(fish1.__proto__==Fish.prototype);//true
//从上面可以看出,通过prototype赋值不用逐个给每个实例赋值
每个实例对象中,还有一个内部属性叫做 proto,这个属性指向了它的构造器(Employee)的属性prototype。所有的函数对象都有"prototype"属性,该属性的值会被赋值给该函数创建的对象(即为实例)的"proto"属性.
换句话说,原型的值会被赋给实例中proto中去
proto也可以叫做实例属性
通过这个可以访问到
console.log(fish1.__proto__.width);
函数对象中自身声明的方法和属性与prototype声明的对象有什么差别?
有下面几个差别:
自身声明的方法和属性是 静态的, 也就是说你在声明后,试图再去增加新的方法或者修改已有的方法,并不会 对由其创建的对象产生影响, 也即 继承 失败
而prototype可以动态地增加新的方法或者修改已有的方法, 从而是 动态的 ,一旦 父函数对象 声明了相关 的prototype属性,由其创建的对象会 自动继承 这些prototype的属性.
既然有函数对象本身的属性, 也有prototype的属性, 那么是由其创建的对象是如何搜索相应的属性的呢?
基本是按照下面的流程和顺序来进行.
1.先去搜索函数对象本身的属性,如果找到立即执行
2.如果1没有找到,则会去搜索prototype属性,有2种结果,找到则直接执行,否则继续搜索 父对象 的 父对象 的prototype, 直至找到,或者到达 prototype chain 的结尾(结尾会是Object对象)
再看一个多重prototype链的例子:
// 多重prototype链的例子
function Employee(name)
{
this.name = "";
this.dept = "general";
this.gender = "unknown";
}
function WorkerBee()
{
this.projects = [];
this.hasCar = false;
}
WorkerBee.prototype = new Employee; // 第一层prototype链
function Engineer()
{
this.dept = "engineer"; //覆盖了 "父对象"
this.language = "javascript";
}
Engineer.prototype = new WorkerBee; // 第二层prototype链
var jay = new Engineer("Jay");
if (flag)
{
alert(jay.dept); //engineer, 找到的是自己的属性
alert(jay.hasCar); // false, 搜索到的是自己上一层的属性
alert(jay.gender); // unknown, 搜索到的是自己上二层的属性
}
每个原型prototype中都有一个constructor属性,这个constructor属性最初是指向了他的构造函数。
总结:
每个构造函数中有一个prototype属性,每个prototype中有一个constructor属性指向了构造函数,每个实例对象中有一个 proto属性,该属性指向了prototype对象。