JavaScript 的继承机制(图文)
一、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. 对象冒充(如上所述)
对象冒充可以实现多重继承:
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 也可以以其它对象作为原型进行创建对象,由此,便组成了原型链:
使用原型继承机制的一个弊端,就是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); };