javascript 小白学习指南 继承

首先我们要明白,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(){
//继承了 SuperType
SuperType.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(); //29
var 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"
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值