文档章节

JavaScript继承(二)——借用构造函数

Bob2100
 Bob2100
发布于 01/20 22:50
字数 1098
阅读 11
收藏 0

JavaScript继承(一)——原型链中提出原型链继承的两个问题:一是原型的数据共享问题,二是创建子类型的实例时,不能向父类型的构造函数中传递参数。这两个问题的根源还是在于使用原型模式创建对象,可以参考JavaScript创建对象(三)——原型模式。本篇文章来讨论一下这两个问题的解决方案——借用构造函数继承。

借用构造函数也被称为伪造对象或经典继承。这种技术的基本思想相当简单,即在子类型构造函数的内部调用父类型构造函数。在Javascript中,从本质上来讲,我们声明的函数不过是Function类型在特定执行环境中执行代码的实例,因此可以通过使用apply方法在创建子类型的对象时,把子类型的执行环境传递给父类型。

首先我们来看下apply的用法,如下代码所示:

var nums = {
  n1: 10,
  n2: 8
}

function sum(a, b) {
  console.log(this);
  console.log(arguments);
}
sum(2, 4);//this: window 。 arguments:[2, 4]
sum.apply(nums, [2, 4]);//this: nums 。 argument:[2, 4]

直接调用sum时,函数sum中的this指代的是调用sum的执行环境的变量对象,即全局变量对象window,使用sum.apply的形式调用,第一个参数传的nums,第二个参数传的数组,那么sum在执行时,this指的就是numsarguments指的就是传入的参数数组。

明白了apply的用法,下面我们来看借用构造函数继承,如代码所示:

function Human(){
  this.colors = ['yellow', 'white', 'black'];
}
function Person(){
  Human.apply(this);
}
var p1 = new Person();
p1.colors.push('brone');
console.log(p1.colors);//["yellow", "white", "black", "brone"]

var p2 = new Person();
console.log(p2.colors);//["yellow", "white", "black"]

Human中声明了一个数组colorsPerson中使用apply的方式调用Human,并把this传递给Human,以实现Person继承Human,当执行new Person()时,函数Person中的this指的就是新创建出的对象,接着就会传递到Human,于是这个新对象上就有了colors属性,实现了继承的效果,通过这种方式,每次创建对象时,子类型中都生成了父类型中定义的属性的一个副本,没有共享属性,也就不存在数据共享的问题了。

另外,对于在子类型构造函数中向超类型构造函数传递参数的问题来看以下示例:

function Human(){
  this.name = arguments[0];
}
function Person(name){
  Human.apply(this, arguments);
  //重新定义子类型的属性,防止被父类型覆盖
  this.age = 18;
}
var p1 = new Person('Bob');
console.log(p1.name);//Bob
console.log(p1.age);//18

创建Person的实例时传递了一个参数Bob,在构造函数中通过apply的方式又将参数传递给了Human,在Human中进行赋值操作实际上就是给新创建的实例设置name属性。为了防止子类型的属性被重写,可以在调用超类型的构造函数之后再添加应该在子类型中定义的特有的属性。

如果仅仅是借用构造函数,那么也将无法避免构造函数模式存在的问题——方法都在构造函数中定义,因此函数复用就无从谈起了。而且,在超类型的原型中定义的方法,对子类型而言也是不可见的,因为整个过程中并没有创建超类型的对象,根据原型链的特征,自然也就无法使用超类型的原型,结果继承链上的所有类型都只能使用构造函数模式创建对象。考虑到这些问题,借用构造函数继承的技术也是很少使用的。

读者也许已经想到可以组合使用构造函数和原型链继承,就像组合使用构造函数模式和原型模式创建对象一样,那么下一篇文章就来谈谈组合继承。

© 著作权归作者所有

共有 人打赏支持
Bob2100
粉丝 21
博文 78
码字总数 39165
作品 0
浦东
高级程序员
私信 提问
JavaScript 中的继承:ES3、ES5 和 ES6

选择一种继承方式 JavaScript 是一门动态语言,动态意味着高灵活性,而这尤其可以体现在继承上面。JavaScript 中的继承有很多种实现方式,可以分成下面四类: Mixin 模式,即属性混入,从一个...

天方夜
2018/10/30
0
0
JavaScript中的函数继承

面向对象和基于对象 几乎每个开发人员都有面向对象语言(比如C++、C#、Java)的开发经验。在传统面向对象的语言中,有两个非常重要的概念——类和实例。类定义了一些事物公共的行为和方法;而...

倔强的石头
2018/12/04
0
0
JavaScript继承(五)——寄生式继承

首先回顾一下原型式继承: 寄生式继承是与原型式继承紧密相关的一种思路,并且同样也是由克罗克福德推而广之的。 说到寄生式继承不得不说工厂模式和寄生构造函数模式创建对象。下面来回顾一下...

Bob2100
02/13
0
0
JavaScript继承(三)——组合继承

借用构造函数继承解决了原型链数据共享和无法向超类型传递参数的问题,但自身的缺陷是不能使用超类型原型中定义的方法。组合继承是将原型链继承和借用构造函数继承组合到一起,从而发挥二者之...

Bob2100
01/26
0
0
每个JavaScript工程师都应懂的33个概念

摘要: 基础很重要啊! 原文:33 concepts every JavaScript developer should know 译文:每个 JavaScript 工程师都应懂的33个概念 作者:stephentian Fundebug经授权转载,版权归原作者所有...

Fundebug
2018/10/30
0
0

没有更多内容

加载失败,请刷新页面

加载更多

springboot快速搭建

1.https://start.spring.io/ 2.点击 Switch to the full version ,可以进行详细设置,然后生成项目即可。

ninjaFrog
9分钟前
0
0
redis

1、redis简介(sina) 是什么 1)Redis:REmote DIctionary Server(远程字典服务器) 2)是完全开源免费的,用C语言编写的,遵守BSD开源协议, 是一个高性能的(key/value)分布式内存数据库,基...

丁典
14分钟前
0
0
Typora快捷键

无序列表:输入-之后输入空格 有序列表:输入数字+“.”之后输入空格 任务列表:-[空格]空格 文字 标题:ctrl+数字 表格:ctrl+t 生成目录:[TOC]按回车 选中一整行:ctrl+l 选中单词:ctrl+...

AzureMonkey
今天
2
0
SpringBoot2.x配置Cors跨域

1 跨域的理解 跨域是指:浏览器A从服务器B获取的静态资源,包括Html、Css、Js,然后在Js中通过Ajax访问C服务器的静态资源或请求。即:浏览器A从B服务器拿的资源,资源中想访问服务器C的资源。...

hengbao5
今天
5
0
mybatis(7) - 分页

一般程序在处理sql分页的场景,要么选择在程序中对所有的结果集sublist,要么在写sql时指定limit。那如何利用mybatis的特性在处理分页呢? 分页插件 适用于数据量大的情况下。 在真正执行sql...

noob_fly
今天
10
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部