JavaScript原型继承和原型链原理详解

所属分类: 网络编程 / JavaScript 阅读数: 1946
收藏 0 赞 0 分享

这篇文章主要介绍了JavaScript原型继承和原型链原理详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下

在讨论原型继承之前,先回顾一下关于创建自定义类型的方式,这里推荐将构造函数和原型模式组合使用,通过构造函数来定义实例自己的属性,再通过原型来定义公共的方法和属性。

这样一来,每个实例都有自己的实例属性副本,又能共享同一个方法,这样的好处就是可以极大的节省内存空间。同时还可以向构造函数传递参数,十分的方便。

这里还要再讲一下两种特色的构造函数模式:

1.寄生构造函数

从形式上来看,这种模式和工厂模式并无区别:

function Person(name, age, job) {
  var o = new Object();
  o.name = name;
  o.age = age;
  o.job = job;
  o.sayName = function() {
    alert(this.name);
  };
  return o;
}
var friend = new Person("Nicholas", 29, "Software Engineer");
friend.sayName(); //"Nicholas"

都是在内部创建一个Object对象实例,再赋予属性和方法,最后返回,这种构造模式的好处是,对于原生的引用类型创建的实例,例如Array,想为实例创建新的方法或者属性时,因为不建议直接修改原生的Array引用类型的构造函数,所以可以利用寄生构造函数:

function SpecialArray() {
  //创建数组
  var values = new Array();
  //添加值
  values.push.apply(values, arguments);
  //添加方法
  values.toPipedString = function() {
    return this.join("|");
  };
  //返回数组
  return values;
}
var colors = new SpecialArray("red", "blue", "green");
alert(colors.toPipedString()); //"red|blue|green"

通过在内部创建一个Array实例,并添加新的方法,最后将这个实例返回,既没有修改原生的Array构造函数,又成功添加了自定义的方法和属性。

缺点:使用寄生构造函数有一个缺点,那就是返回的实例与构造函数或构造函数原型属性之间没有关系,与在构造函数外创建实例没有区别,也无法通过instanceof来确定对象类型,因此有其他更好选择的时候,不推荐使用该方法。

2.稳妥构造函数

稳妥构造函数与寄生构造函数类似,但是并不使用new和this(某些环境下禁止使用),前面的函数可以改写成这样:

function Person(name, age, job) {
  //创建要返回的对象
  var o = new Object();

  //可以在这里定义私有变量和函数
  //添加方法
  o.sayName = function() {
    alert(name);
  };
  //返回对象
  return o;
}

说完这些,现在来谈谈原型继承和原型链,所谓继承,基本思想是利用原型让一个引用类型继承另一个引用类型的方法和属性。每个构造函数都有一个原型对象,原型对象都包含一个指向构造函数的指针,而实例都包含一个指向原型对象的内部指针。所有引用类型默认都继承了Object,而这个继承也是通过原型链实现的。大家要记住,所有函数的默认原型都是Object 的实例,因此默认原型都会包含一个内部指针,指向Object.prototype。

借用构造函数(即在子类型构造函数的内部调用超类型构造函数)

如果仅仅是借用构造函数,那么也将无法避免构造函数模式存在的问题——方法都在构造函数中定
义,因此函数复用就无从谈起了。而且,在超类型的原型中定义的方法,对子类型而言也是不可见的,结
果所有类型都只能使用构造函数模式。考虑到这些问题,借用构造函数的技术也是很少单独使用的。

组合继承(思路是使用原型链实现对原型属性和方法的继承,而通过借用构造函数来实现对实例属性的继承)

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 属性,又可以使用相同的方法了。

原型式继承(借助原型可以基于已有的对象创建新对象,同时还不必因此创建自定义类型)

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"

在没有必要兴师动众地创建构造函数,而只想让一个对象与另一个对象保持类似的情况下,原型式
继承是完全可以胜任的。不过别忘了,包含引用类型值的属性始终都会共享相应的值,就像使用原型模
式一样。

寄生式继承(寄生式继承的思路与寄生构造函数和工厂模式类似,即创建一个仅用于封装继承过程的函数,该函数在内部以某种方式来增强对象,最后再像真地是它做了所有工作一样返回对象)

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

寄生组合式继承

通过借用构造函数来继承属性,通过原型链的混成形式来继承方法。其背后的基本思路是:不必为了指定子类型的原型而调用超类型的构造函数,我们所需要的无非就是超类型原型的一个副本而已。本质上,就是使用寄生式继承来继承超类型的原型,然后再将结果指定给子类型的原型。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持脚本之家。

更多精彩内容其他人还在看

js单独获取一个checkbox看其是否被选中

这篇文章主要与大家分享js获取一个checkbox看其是否被选中的具体实现,很简单,但很实用,需要的朋友可以参考下
收藏 0 赞 0 分享

js变量、作用域及内存详解

本文主要详细分析了JS变量,作用域以及内存问题,同时附上非常多的实例,方便大家理解这3个概念,是篇不可多得的文章,希望对大家有所帮助
收藏 0 赞 0 分享

深入理解javascript作用域和闭包

作用域和作用域链是javascript中非常重要的特性,对于他们的理解直接关系到对于整个javascript体系的理解,而闭包又是对作用域的延伸,也是在实际开发中经常使用的一个特性,实际上,不仅仅是javascript,在很多语言中都提供了闭包的特性。
收藏 0 赞 0 分享

IE6 hack for js 集锦

本文主要讲诉了使用js实现网站功能兼容IE6,非常的实用的小技巧,有需要的朋友可以参考下
收藏 0 赞 0 分享

Javascript的setTimeout()使用闭包特性时需要注意的问题

这篇文章主要介绍了Javascript的setTimeout(0)使用闭包特性时需要注意的问题,需要的朋友可以参考下
收藏 0 赞 0 分享

常用的jquery模板插件——jQuery Boilerplate介绍

Query Boilerplate是一个不错的jQuery插件开发工具,使用这个工具可以帮助你快速的构建一个jQuery框架。这个工具提供你很多评论用以帮助你使得开发变得简单和直接,它是个真正的面对对象的工具,你可以实现公开或者私有的方法或者公开或者私有的属性。
收藏 0 赞 0 分享

深入理解javascript构造函数和原型对象

对象,是javascript中非常重要的一个梗,是否能透彻的理解它直接关系到你对整个javascript体系的基础理解,说白了,javascript就是一群对象在搅。。(哔!)。
收藏 0 赞 0 分享

深入理解javascript原型链和继承

这篇文章主要介绍了javascript原型链和继承的概念,以及使用原型链实现继承、经典继承、组合式继承、寄生组合式继承。非常实用,是篇非常不错的文章,这里推荐给大家。
收藏 0 赞 0 分享

再探JavaScript作用域

这篇文章主要介绍了再探JavaScript作用域,本文用简洁的语言和直观的测试结果图片给大家讲解JavaScript的作用域,需要的朋友可以参考下
收藏 0 赞 0 分享

JavaScript获取图片真实大小代码实例

这篇文章主要介绍了JavaScript获取图片真实大小代码实例,本文使用onload事件来获取图片的真实大小,需要的朋友可以参考下
收藏 0 赞 0 分享
查看更多