这是上一篇的后续。

Javascript是一种基于对象的语言,遇到的所有东西几乎都是对象。如果我们想要把属性和方法封装成一个对象,应该怎么做呢:

假设我们把猫看成一个对象:

var Cat = {

    name : ‘’,

    color : ‘’
}

现在,我们需要根据这个原型对象来生成两个具体的实例对象。

var cat1 = {};//创建一个空对象

cat1.name = “大毛”;

cat1.color = “yellow”;

var cat2 = {};//创建一个空对象

cat2.name = “二毛”;

cat2.color = “white”;

这样也算是一种封装吧。但这样的写法显然是有些缺点。一个是,如果需要多生成实例,会很麻烦。第二就是,实例和原型之间,看不出有什么联系。

原始模式的改进

我们可以写一个代码,来改变代码重复的问题。

function Cat(name,color){
  return {
name : name,
color : color
}
}

然后生成实例对象,就等于在调用函数。

var cat1 = Cat(“大毛”,’yellow’);

var cat2 = Cat(“二毛”,”white”);

这种方法减少了代码量,但依然看不出原型和实例的关系。

构造函数模式

为了解决原型对象生成实例的问题。javascript提供了一个构造函数。

所谓构造函数,其实是一个普通函数。但是内部使用了this变量。对构造函数使用new运算符,就能生成实例。并且this会绑定到实例对象上。

function Cat(name,color){

  this.name = name;

  this.color = color;

}

var cat1 = new Cat(“大毛”,’yellow’);

var cat2 = Cat(“二毛”,”white”);

构造函数的实例和原型之间如何联系呢,实例会含有一个constructor属性,该属性指向实例的构造函数。

alert(cat1.constructor == Cat); //true

alert(cat2.constructor == Cat); //true

构造函数的问题:

资源浪费,前面已经说过,这里就不叙述了。

引入prototype属性

前面已经介绍

构造函数的继承

比如,现在有一个 动物 对象的构造函数。

function Animal(){

    this.species = “animals”;

}

还有一个 猫 对象的构造函数

function Cat(name,color){

  this.name = name;

  this.color = color;

}

那怎样使“猫”继承“动物”呢?

1. 构造函数绑定:

将父对象的构造函数绑定在子对象上。

function Cat(name,color){

  Animal.apply(this,arguments);

  this.name = name;

  this.color = color;

}

var cat1 = new Cat(“kitty”,”white”);

console.log(cat1.species); //animals

原型继承

这种也是比较常用的方法,采用prototype属性。

如果“猫”的prototype对象,指向一个Animal的实例。那么所有“猫”的实例,就能继承Animal了。

//将Cat的prototype对象指向一个Animal的实例。

Cat.prototype = new Animal(); 

Cat.prototype.constructor = Cat;

var cat1 = new Cat(“大毛”,”white”);

console.log(cat1.species);

将Cat的prototype对象指向一个Animal的实例,将完全删除prototype对象原先的值,重新赋予了一个新值。

Cat1的constructor本来是应该指向Cat这个构造函数的。但是因为:

Cat.prototype = new Animal();

Cat的constructor被指向了Animal这个构造函数。这会导致继承链的错乱。因此我们需要手动的进行纠正。

Cat.prototype.constructor = Cat;

直接继承prototype

这种方法是对前面方法的改进。由于在Animal对象中,不变的属性都直接写入了Animal的prototype中。因此,也可以让Cat跳过Animal,直接继承Animal.prototype。

Cat.prototype = Animal.Prototype;

Cat.prototype.constructor = Cat;

与前一种相比,这样可以不用建立Animal实例,相对来说可以节约资源。缺点也很明显:Cat.prototype现在和Animal的prototype都指向了同一个对象。那么任何对Cat.prototype的操作,都会影响到Animal.prototype。所以这个时候,Animal.prototype的constructor也被指向了Cat,这显然不是我们想要的。

利用空对象作为中介

var F = function(){}

F.prototype = Animal.prototype;

Cat.prototype = new F();

Cat.prototype.constructor = Cat;

F是空对象,几乎不占内存。这时,修改Cat.prototype.constructor,也不会影响到Animal的prototype对象。可以将上面的方法,封装成一个函数。

function extend(child,parent){

  var F = function(){};

  F.prototype = parent.prototype;

  child.prototype = new F();

  child.prototype.constructor = child;

}

extend(Cat,Animal);

var cat1 = new Cat(“大毛”,”white”);

拷贝继承

这种逻辑是比较容易理解的,就是将父类的属性一一的拷贝到子类的属性中.

function Animal(){};

Animal.prototype.species = “animal”;

function extend2(child,parent){

  var p = parent.prototype;

  var c = child.prototype;

    for(var k in p){

    c[k] = p[k];

   }
}

然而这种方法的缺点也是很明显的,将父类和子类的prototype指向了同一个存储单元。对于那些引用值类型的属性来说。修改其中的任意一方,都会对另一方的属性造成影响。

非构造函数的继承

道爷曾经提出过一个object()函数,可以做到这一点。

function object(o){

  function F(){}

  F.prototype = o;

  return new F();

}

这种方法 其实和空对象中介方法,是一个道理的。

javascript的原型与继承(2)的更多相关文章

  1. 【面试必备】javascript的原型和继承

    原型.闭包.作用域等知识可以说是js中面试必考的东西,通过你理解的深度也就能衡量出你基本功是否扎实.今天来复习一下javascript的原型和继承,虽说是老生常谈的话题,但对于这些知识,自己亲手写一遍 ...

  2. 深入浅出JavaScript之原型链&继承

    Javascript语言的继承机制,它没有"子类"和"父类"的概念,也没有"类"(class)和"实例"(instanc ...

  3. javascript的原型和继承(1)

    原型与继承是javascript中基础,重要而相对比较晦涩难解的内容.在图灵的网上看到一篇翻译过的文章,有参考了一些知名博客.我自己总结了几篇.通过这次的总结,感觉自己对原型和继承的认识又增加了很多, ...

  4. JavaScript的原型链继承__propt__、prototype、constructor的理解、以及他们之间相互的关系。

    回想自己已经工作了有一段时间了,但是自己对JavaScript的原型链.和继承的理解能力没有到位,最近他们彻底的整理并且复习了一遍. 本案例中部分文案来自网络和书籍,如有侵权请联系我,我只是把我的理解 ...

  5. JavaScript 面向对象 原型(prototype) 继承

    1.对象的概念:无需属性的集合,属性可以为数值,对象或函数,ECMAscript中没有类的概念,这点是javascript与其他面向对象(OO)语言不同的地方. //创建一个自定义对象 var per ...

  6. JavaScript基于原型的继承

    在一个纯粹的原型模式中,我们会摒弃类,转而专注于对象,基于原型的继承相比基于类的继承的概念上更为简单 if( typeof Object.beget !== 'function') { Object. ...

  7. javascript高级:原型与继承

    原型继承的本质就是一条原型链,对象会沿着这条链,访问链里的方法属性. 对象的__proto__属性就是用于访问它的原型链的上一层: 考虑以下对象: 1. 所有对象的原型: Object.prototy ...

  8. 🍓JavaScript 对象原型链继承的弊端 🍓

  9. javascript中继承(一)-----原型链继承的个人理解

    [寒暄]好久没有更新博客了,说来话长,因为我下定决心要从一个后台程序员转为Front End,其间走过了一段漫长而艰辛的时光,今天跟大家分享下自己对javascript中原型链继承的理解. 总的说来, ...

随机推荐

  1. MyBatis源码分析(3)—— Cache接口以及实现

    @(MyBatis)[Cache] MyBatis源码分析--Cache接口以及实现 Cache接口 MyBatis中的Cache以SPI实现,给需要集成其它Cache或者自定义Cache提供了接口. ...

  2. WebService异常时,查看请求状态码方法

    /// <summary> /// Test 的摘要说明 /// </summary> [WebService(Namespace = "http://tempuri ...

  3. 在sql脚本中获取变量中的查询结果

    )--变量 ) set @itemValue='select @a=getdate()'--赋值 exec sp_executesql @itemValue,N'@a nvarchar(max) ou ...

  4. VclZip压缩文件夹

    压缩指定路径MyZipDir下的文件夹b及b目录下的所有文件和文件b.txt function ZipDir(zipMode:Integer;zipControl:TVCLZip;MyZipName, ...

  5. centos下 redis安装配置及简单测试

    1:安装redis(使用的的环境是centos6.7 redis-2.6.14) 将redis-2.6.14.tar.gz文件拷贝到/usr/local/src 目录下 解压文件  tar zxvf ...

  6. Jenkins进阶系列之——03parameterized-trigger插件

    说明:这个插件可以根据已经完成构建的结果,触发新Job或者传递参数. 官方说明:Parameterized Trigger Plugin 安装步骤: 系统管理→管理插件→可选插件→Build Trig ...

  7. [shell基础]——split命令

    测试文本 # cat name1.txt name1 alvin1 name2 alvin2 name3 alvin3 name4 alvin4 此时目录下就只有这个文件 # ls name1.txt ...

  8. js中几个正则表达式相关函数使用时g标志的作用

    首先,javascript中涉及到正则表达式的函数总共有6个,可分为两种: 1.第一种是作为字符串对象的方法,即以 String.fun(); 形式调用,这里包括 split.search.match ...

  9. 第二十二章 CLR寄宿和AppDomain

    1. 概念解析 CLR Hosting(CLR 宿主):初始启动.Net Application时,Windows进程的执行和初始化跟传统的Win32程序是一样的,执行的还是非托管代码,只不过由于PE ...

  10. hadoop配置文件详解系列(一)-core-site.xml篇

    接上一个属性,这个属性就是设置阈值的. hadoop.security.groups.cache.secs 300 配置用户组映射缓存时间的,当过期时重新获取并缓存. hadoop.security. ...