JavaScript 的继承机制(图文)

jopen 10年前

一、JavaScript的一些语言特性

          1.当我们声明一个函数时,实际上是定义了一个函数类型的对象。如下所示,下面三种方式定义函数对象结果是一样的。

 var  func = function(){   //....define code goes there.  }    function func ()  {    // ...define code goes there.  }    var func  = new Function(....);

          而当我们使用它时,它会一次执行其内的代码。

          2. this 指针的作用。在函数的内部,函数的this指针的作用域是动态绑定的,即this 代表的作用域是 上面的func 变量的作用域。但是,当我们使用new func()时,此时会为函数 func 独立出一块内存区域,this 的作用域便是func自己的区域。

 var func = function()  {     this.name = "louis";    this.age  = 22;  }  func(); //此时函数运行后,在外部window 对象可以访问name,age    var a = new func();// 此时的函数运行后,a.name,b,name.

           总结:出现上面的情况是因为函数 是一个function 类型的对象,其中,内部定义的执行语句是不可识别的,都是以字符串的形式存储在相应的区域,当我们调用它们的时候,即使用() 的时候,这时候的代码才会被拿出来,在给定的一个作用域内解析并且执行。这就是所谓的动态绑定: 即只有在运行的情况下才知道其执行的上下文。

           3.根据上面的函数的特性,我们现在定义了一个Person类 ,和一个Woman 类,由Woman类要继承Person类,我们可以在Woman内,创建一个对Person 变量的一个引用,然后执行之,这时候函数执行的上下文是Woman内部,即Person函数执行后,Person 内部的变量、属性自然隶属于 Woman 创建的对象了.

function Person()  {          this.name="people";         this.speak = function(){                console.log("hello,Fellow");         }        }  // Woman要继承Person类    function Woman()  {              this.birthe = function(){                  console.log("brithing...");       }  }

这种继承的方式,叫做 对象冒充。

 function Woman()  {        //对象冒充方式,将函数Person动态在Woman内部执行        this.newMethod = Person;        this.newMethod();        delete this.newMethod;          this.birthe = function(){                        console.log("birthing....");        }         }

二、继承的方式介绍

             1. 对象冒充(如上所述)

             d1.png

            对象冒充可以实现多重继承:

 function ClassZ() {      this.newMethod = ClassX;      this.newMethod();      delete this.newMethod;        this.newMethod = ClassY;      this.newMethod();      delete this.newMethod;  }

      上面的模式有个弊端,就是ClassX和ClassY 的属性定义中,如果有重复的情况,则对于继承者ClassZ而言,要看其继承顺序,后面的声明继承的类会覆盖先声明的类,即:ClassY的属性和 ClassX重合的话,ClassY会覆盖ClassX内的属性。

        以对象冒充为原理,JavaScript提供了两个可以完成此继承的的方法:apply(),call();

         假设现在有对象a, 它要继承 B中的属性和方法,如下所示:

 function B (words)  {        this.name="hello";        this.say= function(){         console.log(words);  };    }  var a = new Object();  //a 继承B内的属性。  B.call(a,"hello");  B.apply(a,new Array("hello"));

   2. 原型模式

       在我们现实生活中,经常听到 某某东西出现了山寨货,那所谓的山寨货,则是以某个正品货为原型造出来的东西,即是仿的。javascript 内的“原型”,和这个意思差不多,都是以某一对象作为参考,进行对象的创建。故而,我们在对象的创建时,如果需要以某一对象作为原型,则如下操作:

 // 设定B 以A 为原型创建  function  A()  {        this.attr1;        this.attr2;        this.method1();       ///....  }  function B()  {  }  B.prototype = new A();    var b = new B();// 继承A内所有的属性

      另外A 也可以以其它对象作为原型进行创建对象,由此,便组成了原型链:

d2.png

    使用原型继承机制的一个弊端,就是B.prototype = new A(); A () 是不可以带参数的。如果使用参数,则可以使用对象冒充。

 function ClassA(sColor) {      this.color = sColor;  }    ClassA.prototype.sayColor = function () {      alert(this.color);  };    function ClassB(sColor, sName) {      ClassA.call(this, sColor);      this.name = sName;  }    ClassB.prototype = new ClassA();    ClassB.prototype.sayName = function () {      alert(this.name);  };