JavaScript继承(一)——原型链中提出原型链继承的两个问题:一是原型的数据共享问题,二是建立子类型的实例时,不能向父类型的构造函数中传递参数。这两个问题的根源仍是在于使用原型模式建立对象,能够参考JavaScript建立对象(三)——原型模式。本篇文章来讨论一下这两个问题的解决方案——借用构造函数继承。javascript
借用构造函数也被称为伪造对象或经典继承。这种技术的基本思想至关简单,即在子类型构造函数的内部调用父类型构造函数。在Javascript中,从本质上来说,咱们声明的函数不过是Function
类型在特定执行环境中执行代码的实例,所以能够经过使用apply
方法在建立子类型的对象时,把子类型的执行环境传递给父类型。java
首先咱们来看下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
指的就是nums
,arguments
指的就是传入的参数数组。app
明白了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
中声明了一个数组colors
,Person
中使用apply
的方式调用Human
,并把this
传递给Human
,以实现Person
继承Human
,当执行new Person()
时,函数Person
中的this
指的就是新建立出的对象,接着就会传递到Human
,因而这个新对象上就有了colors
属性,实现了继承的效果,经过这种方式,每次建立对象时,子类型中都生成了父类型中定义的属性的一个副本,没有共享属性,也就不存在数据共享的问题了。this
另外,对于在子类型构造函数中向超类型构造函数传递参数的问题来看如下示例:.net
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
属性。为了防止子类型的属性被重写,能够在调用超类型的构造函数以后再添加应该在子类型中定义的特有的属性。code
若是仅仅是借用构造函数,那么也将没法避免构造函数模式存在的问题——方法都在构造函数中定义,所以函数复用就无从谈起了。并且,在超类型的原型中定义的方法,对子类型而言也是不可见的,由于整个过程当中并无建立超类型的对象,根据原型链的特征,天然也就没法使用超类型的原型,结果继承链上的全部类型都只能使用构造函数模式建立对象。考虑到这些问题,借用构造函数继承的技术也是不多使用的。对象
读者也许已经想到能够组合使用构造函数和原型链继承,就像组合使用构造函数模式和原型模式建立对象同样,那么下一篇文章就来谈谈组合继承。blog