js整理一:原型的理解

自己对js中原型的理解整理

先介绍下几个属性,都是自己看着书上然后对这个概念的个人理解,如果有不对的地方,还请指出交流下~~,具体的参考见文章最下面  

##1.1每个对象中的proto介绍##

关于在函数的创建过程中,每一个实体都是一个对象,而每一个对象都有一个属性proto,有些浏览器不可以查看他,不过测试了下IE11下是可以查看的,不过可以用另外的方法来替代他,比如isPrototypeOf()的方法来确定对象之间是否存在某种关系,如果a的proto指向b,那么b.isPrototypeOf(a)将会返回true的结果。
在加一点个人对proto的一点理解,这个属性是原型链的关键,所有之后要做的原型链的属性的搜索正式靠这个指针不停往上搜索的。

##1.2每个函数中的prototype属性##

在js中函数也是一个对象,所有他也有前面所提到的proto属性,然后他还有他自己的一个特有的属性,就是prototype属性,这个属性跟proto一样可以理解为一个指针的形式,prototype指向了函数的函数原型对象,说了这么多,来一个具体的例子试试

function fTest(name){
    this.name = name;
}
fTest.prototype.getname = function(){
    console.log(this.name);
};
var oTest = new fTest("hello");

pic1
图中还写了俩个新的对象,一个是function.prototype,Object.prototype
  (1)function.prototype:按照前面提到的proto的理解,既然fTest是一个函数,那么他应有有函数所有的方法,所有它的proto当然是指向了function.prototype,这里面有函数的一些基本的方法;同理对于fTest.prototype属性,他是一个Object对象,所以他也有一些对象的基本的方法,所以fTest.prototype指向的是Object.prototype;然后对于function.prototype他也是一个对象所以同上也指向了Object.prototype。然后关于一个新的指针constructor,这个在后面再提到。
  (2) 当然Object.prototype已经是顶点了,他的proto就是NULL了。   

##1.3理解下组合使用构造函数和原型模式##
在上面的代码中function fTest中声明了一个变量name这个变量可以理解为是一个针对一个实例声明的变量,而在fTest.prototype中声明的getname方法是一个公用的方法,再看下面的代码

function fTest(name){
    this.name = name;
}
fTest.prototype.getname = function(){
    console.log(this.name);
};
var oTest1 = new fTest("hello");
var oTest2 = new fTest("hi");
//oTest1.getname === oTest2.getname true
//oTest1.name === oTest2.name false

可以理解为getname方法是共有的,而属性name是私有的,这个的话个人的理解是由于原型链的存在,当你使用oTest1.name的时候,他首先会在实例oTest1中去寻找name这个属性,如果找到了就停止,否则会继续沿着原型链向上寻找,比如getname这个方法,他不再实例中,所以要向上搜寻一次,然后便找到了这个方法,但是他是在两个实例所共享的一个fTest.prototype中的一个方法,所以他们的getname方法其实指向的是同一个方法,可以oTest1.getname === oTest2.getname测试下,返回为true。

##1.4原型链的实现##

在原型链的实现上,1.3中已经提到过一些了,现在稍微整理一下,(参考了javascript高级程序设计中的一些话),每当代码读取某一个对象的属性的时候,都会执行一次搜索,目标是具有给定名字的属性,首先在实例本身开始,如果实例中存在,则返回属性的值,否则继续搜索他指针指向的原型对象。
  当然如果在原来的基础上,如果实例添加了一个属性,而这个属性在原型中也有,此时他会覆盖在原型中的那个原来的属性,再看下面的代码,很多是看js高级程序设计上面的内容的

function fTest(name){}
fTest.prototype.name = "hello";
fTest.prototype.getname = function(){
    console.log(this.name);
};
var oTest1 = new fTest();
var oTest2 = new fTest();
oTest1.hasOwnProperty("name");//false
oTest2.hasOwnProperty("name");//false
oTest1.__proto__ === oTest2.__proto__;//true
console.log(oTest1.getname());//hello
console.log(oTest2.getname());//hello
//下面开始变化了
oTest1.name = "hi";
console.log(oTest1.getname());//hi
console.log(oTest2.getname());//hello
oTest1.hasOwnProperty("name");//true
oTest2.hasOwnProperty("name");//false
delete oTest1.name;//删除实例中的name属性
console.log(oTest1.getname());//hello
console.log(oTest2.getname());//hello
oTest1.hasOwnProperty("name");//false
oTest2.hasOwnProperty("name");//false

此时将这个状态定义为State1好了,这个时候的图如下所示:
pic2
对上诉代码大概的进行解释以下,前几步都是跟之前一样的风格跟理解,此时oTest1. proto和oTest2. proto都指向fTest.prototype,所以他们公用一个name属性,然后这里用了hasOwnProperty方法来测试,在实例oTest1中是否有name的属性,结果是没有。oTest2同理。
然后下一个状态定义为State2
pic3
然后再执行oTest1.name = “hi”;这个话使得在实例oTest1中添加了name属性,这一点可以通过oTest1.hasOwnProperty(“name”);来证明,测试结果返回的是true,根据前面提到js查找一个变量的方法,现在他先找到了实例中的name属性,所以console.log(oTest1.getname());结果是hi,而console.log(oTest2.getname());任然为hello,因为在实例oTest2中并没有属性name,所以在原型链的查找过程中很自然的找到的是在fTest.prototype中的name属性。

最后又执行了delete oTest1.name;删除实例中的name属性,是这些都回复到了状态1中~~

最后送上一个牛逼的图,作者貌似就是图最上面的那行
pic4