javascript 小白学习指南 继承

来源:互联网 发布:linux ftp服务安装 编辑:程序博客网 时间:2024/05/16 17:59

首先我们要明白,javascript中的继承是通过原型链来体现的

function Foo(){};var f1 = new Foo();f1.a = 10;Foo.prototype.a = 100;Foo.prototype.b = 200;console.log(f1.a) //10;console.log(f1.b) //200 

这里写图片描述

以上代码中,f1是Foo函数new出来的对象,f1.a是f1对象的基本属性,f1.b是怎么来的呢?——从Foo.prototype得来,因为f1.proto指向的是Foo.prototype
访问一个对象的属性时,先在基本属性中查找,如果没有,再沿着proto这条链向上找,这就是原型链。

介绍完了原型链,下面我们来看看javascript中的几种继承方式
第一种:借用构造函数
我们来看看JS高程中的例子

function SuperType(){this.colors = ["red", "blue", "green"];}function SubType(){//继承了 SuperTypeSuperType.call(this);}var instance1 = new SubType();instance1.colors.push("black");alert(instance1.colors); //"red,blue,green,black"var instance2 = new SubType();alert(instance2.colors); //"red,blue,green"

这里写图片描述
这里写图片描述
这里写图片描述
通过使用 call()方法(或 apply()方法也可以),我们实际上是在(未来将要)新创建的 SubType 实例的环境下调用了 SuperType 构造函数。
这样一来,就会在新 SubType 对象上执行 SuperType()函数中定义的所有对象初始化代码。结果,
SubType 的每个实例就都会具有自己的 colors 属性的副本了。

相对于原型链而言,借用构造函数有一个很大的优势,即可以在子类型构造函数中向超类型构造函
数传递参数。

function SuperType(name){this.name = name;}function SubType(){//继承了 SuperType,同时还传递了参数SuperType.call(this, "Nicholas");//实例属性this.age = 29;}var instance = new SubType();alert(instance.name); //"Nicholas";alert(instance.age); //29

以上代码中的 SuperType 只接受一个参数 name,该参数会直接赋给一个属性。在 SubType 构造
函数内部调用 SuperType 构造函数时,实际上是为 SubType 的实例设置了 name 属性。为了确保
SuperType 构造函数不会重写子类型的属性,可以在调用超类型构造函数后,再添加应该在子类型中
定义的属性。

第二种 组合式继承

组合式继承指的是原型链和借用构造函数的技术组合到一块,从而发挥二者之长的一种继承模式。其背后的思路是使用原型链实现对原型属性和方法的继承,而通过借用构造函数来实现对实例属性的继承。

function SuperType(name){this.name = name;this.colors = ["red", "blue", "green"];}SuperType.prototype.sayName = function(){alert(this.name);};function SubType(name, age){//继承属性SuperType.call(this, name);this.age = age;}//继承方法SubType.prototype = new SuperType();SubType.prototype.constructor = SubType;SubType.prototype.sayAge = function(){alert(this.age);};var instance1 = new SubType("Nicholas", 29);instance1.colors.push("black");alert(instance1.colors); //"red,blue,green,black"instance1.sayName(); //"Nicholas";instance1.sayAge(); //29var instance2 = new SubType("Greg", 27);alert(instance2.colors); //"red,blue,green"instance2.sayName(); //"Greg";instance2.sayAge(); //27

在这个例子中, SuperType 构造函数定义了两个属性: name 和 colors。 SuperType 的原型定义
了一个方法 sayName()。 SubType 构造函数在调用 SuperType 构造函数时传入了 name 参数,紧接着
又定义了它自己的属性 age。然后,将 SuperType 的实例赋值给 SubType 的原型,然后又在该新原型
上定义了方法 sayAge()。这样一来,就可以让两个不同的 SubType 实例既分别拥有自己属性——包
括 colors 属性,又可以使用相同的方法了。

第三种 原型式继承

function object(o){function F(){}F.prototype = o;return new F();}var person = {name: "Nicholas",friends: ["Shelby", "Court", "Van"]};var anotherPerson = object(person);anotherPerson.name = "Greg";anotherPerson.friends.push("Rob");var yetAnotherPerson = object(person);yetAnotherPerson.name = "Linda";yetAnotherPerson.friends.push("Barbie");alert(person.friends); //"Shelby,Court,Van,Rob,Barbie"

如果有这么一个对象的话,可以把它传递给 object()函数,然后再根据具体需求对得到的对象加以修改即可。
在这个例子中,可以作为另一个对象基础的是 person 对象,于是我们把它传入到 object()函数中,然后该
函数就会返回一个新对象。这个新对象将 person 作为原型,所以它的原型中就包含一个基本类型值属性
和一个引用类型值属性。这意味着 person.friends 不仅属于 person 所有,而且也会被 anotherPerson
以及 yetAnotherPerson 共享。实际上,这就相当于又创建了 person 对象的两个副本。

function object(o){function F(){}F.prototype = o;return new F();}

上面的这个函数在ES5中 已经变成 object.create();

第四种 寄生式继承

创建一个仅用于封装继承过程的函数,该函数在内部以某种方式来增强对象,最后再像真地是它做了所有工作一样返回对象。

function object(o){function F(){}F.prototype = o;return new F();}function createAnother(original){var clone = object(original); //通过调用函数创建一个新对象clone.sayHi = function(){ //以某种方式来增强这个对象alert("hi");};return clone; //返回这个对象}

createAnother()函数接收了一个参数,也就是将要作为新对象基础的对象。然后,把这个对象(original)传递给 object()函数,将返回的结果赋值给 clone。再为 clone 对象添加一个新方法 sayHi(),最后返回 clone 对象。

然后我们可以这么用

var person = {name: "Nicholas",friends: ["Shelby", "Court", "Van"]};var anotherPerson = createAnother(person);anotherPerson.sayHi(); //"hi"
0 0