JavaScript学习总结(十七)——Javascript原型链的规律

一、JavaScript原型链

  ECMAScript中讲述了原型链的概念,并拿原来型链作为落实连续的基本点方式。其基本思维是以原型为一个引用类型继承另一个援类型的性与措施。在JavaScript中,用 __proto__
属性来表示一个靶的原型链。当找一个对象的属性时,JavaScript
向上遍历原型链,直到找到给定名称的性为止!

仍现在时有发生如下的代码:

扩展Object类,添加Clone和Extend方法

 1 /*扩展Object类,添加Clone,JS实现克隆的方法*/
 2 Object.prototype.Clone = function(){
 3     var objClone;
 4     if (this.constructor == Object){
 5         objClone = new this.constructor(); 
 6     }else{
 7         objClone = new this.constructor(this.valueOf()); 
 8     }
 9     for(var key in this){
10         if ( objClone[key] != this[key] ){ 
11             if ( typeof(this[key]) == 'object' ){ 
12                 objClone[key] = this[key].Clone();
13             }else{
14                 objClone[key] = this[key];
15             }
16         }
17     }
18     objClone.toString = this.toString;
19     objClone.valueOf = this.valueOf;
20     return objClone; 
21 }
22 
23 /*扩展Object类,添加Extend方法来实现JS继承, 目标对象将拥有源对象的所有属性和方法*/
24 Object.prototype.Extend = function (objDestination, objSource) {
25     for (var key in objSource) {
26         if (objSource.hasOwnProperty(key) && objDestination[key] === undefined) {
27             objDestination[key] = objSource[key];
28         }
29     }
30     return objDestination;
31 }

定义Person类

1 /*定义一个Person类*/
2 function Person(_name,_age){
3     this.name = _name;
4     this.age = _age;
5 }

  在JavaScript中,Object类是所有类的父类,所以Person类从Object类继承,继承了Object类的有着public属性和public方法,包括Object类新长的Clone和Extend方法**

得为此如下的代码证明,Person类确实是后续了Object类

 1 document.write("<pre>");
 2 
 3 var p  = new Person("孤傲苍狼",24);//创建一个人,名字是孤傲苍狼
 4 var cloneP = p.Clone();//p调用在Object类中定义的Clone方法来克隆自己,如果能得到一个cloneP,那就证明了Person类确实是继承了Object类,所以就拥有了Clone
 5 document.writeln("p是使用Person类以构造函数的方式创建出来的对象,p.name = "+p.name+",p.age = "+p.age);
 6 document.writeln("cloneP是p调用Clone方法克隆出来的对象,cloneP.name = "+cloneP.name+",cloneP.age = "+cloneP.age);
 7 document.writeln("cloneP对象和p对象是两个相互独立的对象,这两个对象的内存地址肯定是不相等,p == cloneP的结果是:"+(p == cloneP));
 8 cloneP.name="白虎神皇";//修改cloneP的名字
 9 document.writeln("cloneP的name被修改了,cloneP.name = "+cloneP.name);
10 document.writeln("cloneP的name修改了,但是不影响到p,p.name = "+p.name);
11 
12 document.write("</pre>");

运行结果:

  图片 1

  那么Person类通过神马方式来继承Object类的也,是运用原型(prototye)的办法持续的:

1  /*定义一个Person类*/
2  function Person(_name,_age){
3      this.name = _name;
4      this.age = _age;
5  }
6  Person.prototype = new Object();//让Person类继承Object类

  由于JavaScript规定,任何类似都累自Object类,所以”Person.prototype = new Object();//让Person类继承Object类”即使我们不写,我猜想JavaScript引擎也会见自行帮助咱添加这句话,或者是使用”Person.prototype = Object.prototype;“这种办法,让Person类去继承Object类。”Person.prototype = new Object();”,事实上这么即使相当于Object对象是Person的一个原型,这样即便一定给了将Object对象的性能与道复制到了Person上了。

第二、new运算符是怎么做事之

  我们事先看看这样平等段子代码:

1 var p  = new Person("孤傲苍狼",24);//创建一个人,名字是孤傲苍狼

  很粗略的均等段代码,我们来探望这个new究竟做了呀?我们可以拿new的进程拆分成以下三步:

  1.var p={};
初始化一个目标p。

  2.
p.__proto__=Person.prototype;,将对象p的 __proto__ 属性设置也
Person.prototype

  3.Person.call(p,”孤傲苍狼”,24);调用构造函数Person来初始化p。

关键在于第二步,我们来说明一下:

1 var p  = new Person("孤傲苍狼",24);//创建一个人,名字是孤傲苍狼
2 alert("p.__proto__ === Person.prototype的结果是:"+(p.__proto__ === Person.prototype));

 在火狐下的运转结果是:

  图片 2

马上段代码会回来true。说明我们步骤2的正确性。

  注意:__proto__这个特性只有在firefox或者chrome浏览器被才是公然允许看的,因此,其他根据IE内核的浏览器是勿会见回true的。

  那么__proto__凡是什么?在此处大概地说生。每个对象都见面当其中间初始化一个性,就是
__proto__,当我们访问一个对象的性能时,如果此目标中未存是特性,那么他就见面失去__proto__里摸索这特性,这个
__proto__再就是见面出投机之__proto__,于是就这么一直找下去,也就算是咱们平常所说的原型链的概念。

  按照专业,__proto__是勿对外公开之,也就是说是独个体属性,在IE下是无法访问__proto__特性的,但是Firefox的引擎将他暴露了出去改成了一个国有的属性,我们可对外访问同安装。

好,概念说根本了,让我们看一下底这些代码:

1 <script type="text/javascript">
2         var Person = function () { };
3         Person.prototype.Say = function () {
4             alert("Person say");
5         }
6         var p = new Person();
7         p.Say();
8 </script>

  这段代码很简单,我们看下为什么p可以拜Person的Say。

  首先

1 var p=new Person();

  可以汲取

1 p.__proto__=Person.prototype

  那么当我们调用p.Say()时,首先p中没有Say这个特性,
于是,他即需交外的__proto__惨遭失去搜寻,也不怕是Person.prototype,而我辈当上面定义了 

1 Person.prototype.Say=function(){
2         alert("Person say");
3 };

   于是,就找到了这办法。

 接下来,让我们看个又复杂的。

 1 <script type="text/javascript">
 2         var Person = function () { };
 3         Person.prototype.Say = function () {
 4             alert("Person say");
 5         }
 6         Person.prototype.Salary = 50000;
 7         var Programmer = function () { };
 8         Programmer.prototype = new Person();//让程序员类从人这个类继承
 9         Programmer.prototype.WriteCode = function () {
10             alert("programmer writes code");
11         };
12         Programmer.prototype.Salary = 500;
13         var p = new Programmer();
14         p.Say();
15         p.WriteCode();
16         alert(p.Salary);
17 </script>

   我们来做这样的推理:

1 var p=new Programmer();

  可以汲取

1 p.__proto__=Programmer.prototype;

  而于地方我们指定了

1 Programmer.prototype=new Person();

  我们来这样拆分,

1 var p1=new Person();
2 Programmer.prototype=p1;

  那么:

1 p1.__proto__=Person.prototype;
2 Programmer.prototype.__proto__=Person.prototype;

  由基于上面得到

1 p.__proto__=Programmer.prototype

  可以得到:

1 p.__proto__.__proto__=Person.prototype

  好,算清楚了后来我们来拘禁上面的结果,p.Say()。由于p没有Say这个特性,于是去
p.__proto__,也就是是Programmer.prototype,也就是是p1中失找寻,由于p1中为远非Say,那便失去
p.__proto__.__proto__,也就是Person.prototype中失追寻,于是便找到了Say方法。这吗就算是原型链的落实原理。

  以下代码展示了JS引擎如何寻找属性:

1 function getProperty(obj, prop) {
2     if (obj.hasOwnProperty(prop))
3         return obj[prop];
4     else if (obj.__proto__ !== null)
5         return getProperty(obj.__proto__, prop);//递归
6     else
7         return undefined;
8 }

   范例:查找p对象的Say方法

 1  <script type="text/javascript">
 2     /*查找obj对象的prop属性*/
 3      function getProperty(obj, prop) {
 4         if (obj.hasOwnProperty(prop))
 5             return obj[prop];
 6         else if (obj.__proto__ !== null)
 7             return getProperty(obj.__proto__, prop);//递归
 8         else
 9             return undefined;
10     }
11 
12     var Person = function () { };//定义Person类
13     Person.prototype.Say = function () {
14         alert("Person say");
15     }
16     Person.prototype.Salary = 50000;
17 
18     var Programmer = function () { };//定义Programmer类
19     //Programmer.prototype = new Person();//让程序员类从人这个类继承,写法一
20     Programmer.prototype = Person.prototype;//让程序员类从人这个类继承,写法二
21     Programmer.prototype.WriteCode = function () {
22         alert("programmer writes code");
23     };
24     Programmer.prototype.Salary = 500;
25     var p = new Programmer();
26     var SayFn = getProperty(p,"Say");//查找p对象的Say方法
27     SayFn.call(p);//调用找到的Say方法
28 </script>

当火狐下的运作结果:

  图片 3

  其实prototype只是一个假象,他当落实原型链中只是由及了一个赞助作用,换句话说,他只是在new的时段所有一定之值,而原型链的实质,其实在于__proto__。