js原型继承深入

js采用原型继承来实现类的派生,但是原型链再深入点,我们又知道多少呢,现在不妨往下看:

先来一个原型继承:

var M1 = function() {
    this.param = "m1's param";
    this.showParam = function() {
        alert(this.param);}
    this.insideObj = {
        "name" : "stefan",
        "age"    :   15   
};
  this.arr = ["arr1", "arr2"];
};

var M2= function() {
     this.clone = function() {
        return this;
}        
};

var m1 =new M1();
M2.prototype = m1;

  好吧,现在M2的原型是m1,也就是说m2继承了m1对象所有共有属性,这样一来,我们的探索开始,第一个测试

1.先尝试改变m2.param属性,输出m2.param,再删除m2.param,再输出m2.param,

m2.param = "m2's param";  //改变m2.param
m2.showParam();                //输出    m2's param
delete m2.param;               //删除m2.param
m2.showParam();               //输出     m1's param

一般人会认为因为原型的机制,在子作用域中对原型(即m1)的属性param进行修改,是不可能实现修改的作用的。一旦对m2.param赋值,m2会在它的作用域内(子作用域内)创建一个param属性,并赋值“m2's param”,其中对m2.param作的任何改动都不会影响到原型中的param属性,这就是原型的安全机制体现。 将m2.param删除后,因为m2作用域不含param属性,此时将进入m2的原型链中查找param属性,若原型链中有多个子作用域,并且在该作用域中含有param属性,则将返回最近的子作用域的param属性值,若都没有,将返回m1作用域的param值。比如,

 1 function M3(){
 2    this.param = "m3's param";
 3  }
 4  
 5  M3.prototype = m1;
 6 var m3 = new M3();
 7  M2.prototype = m3;
 8  delete m2.param;        //删除m2作用域的独立属性param
 9  m2.showParam();        //输出  "m3's param"
10 delete m3.param;         //删除m3作用域的独立属性param
11 m2.showParam();           //输出   'm1's param'

 

 

2.以上的都是对一个基本类型的属性,比如"int ,float,string,boolean"讨论,如果是 “数组(其实数组本身就是对象,只不过特殊一点),一般对象 ”类型的属性呢?会是怎么样的一个结果,现在我们修改以下insideObj这个“对象类型”的属性,重新赋予一个新的对象或者数组,

 

 

 

m2.arr = ["m2 arr1", "m2 arr2"];
delete m2.arr;                 
alert(m2.arr);                    //毫无疑问是  ["m2 arr1", "m2 arr2"];
m2.insideObj = {
name :  "john",
age :  153
};

delete m2.insideObj;
alert(m2.insideObj.name)   //输出是  "stefan"

以上的结果毫无争议可言是吧,原因跟上面所阐述的一样,看看接下来再改动一下arr或者insideObj里面的变量,看下会发生什么事,  

m2.arr[0] = "m2's arr1";
alert(m1.arr[0]);             //此时“居然”输出是, “m2's arr1"
delete m2.arr[0];          //数组arr的第一个数组元素
alert(m1.arr);                 //输出是   ["arr2"],第一个元素不见了
m2.insideObj["name"] = "m2";
alert(m1.insideObj["name"]); //输出是 "m2"

  这个是怎么一回事呢?我们居然直接对原型中的数组arr和内部对象进行了修改,这也说明了一个现象:m2没有在它的独立作用域中创建arr和insideObj这两个属性

现在来理清以下,大家请注意,以上我们并没有对属性的引用进行任何改动    也就是说,我们一直持有的是原型m1的arr和insideObj这两个对象的引用,所谓的“牵一发而动全身”,就是这样啦。而我们之前为什么没有对原型m1的属性造成任何改动,是因为我们都是赋值上了新的引用,再仔细回顾以下:

m2.arr = ["m2 arr1", "m2 arr2"];              

m2.insideObj = {
name :  "john",
age :  153
};

 

 没错,就是这样。非常浅显易懂,这个就不多解释了。

3.在这里,也顺便介绍以下一些对象的原型相关的特性,

(1)hasOwnProperty(propertyname)

它是用于判断某个属性是否原型继承而来,比如

for (var field in m2)
    document.write(field);
//当然输出是param,insideObj,arr,showParam,clone

//使用hasOwnProperty判断以下
for (var field in m2)
   if(m2.hasOwnProperty(field))
       document.write(field);
//只会输出clone,因为这是在m2内部定义的,而其他的属性都是从m1继承来的

 

(2)isPrototypeOf(obj)

它是用于判断该对象是否是obj对象的原型,像

if(m1.isPrototype(m2))
    alert("true");
//m1是m2的原型,当时是true啦

  

ok,小弟不才,对原型就只研究到这地步,再深入点就要花时间去慢慢琢磨探究啦。有什么错误,欢迎指出

 

posted @ 2013-10-28 10:52  stefanlee  阅读(212)  评论(0)    收藏  举报