JavaScript面向对象-基于函数伪造的方式实现继承
来源:互联网 发布:java做计算器界面 编辑:程序博客网 时间:2024/05/21 08:01
由于基于原型链实现继承的方式存在一些缺点,所以人们采用了另外一种方式来实现继承——基于函数伪造的方式实现继承。这个技术的思想是在子类构造函数的内部调用父类的构造函数。
基于函数伪造的方式实现继承的实现方式
因为在JavaScript中,函数是在特定环境中执行代码的对象,所以我们可以使用call()
或apply()
方法来在子类对象上执行父类对象的构造函数。来看下面的例子:
/* 创建父类 */
function
Parent(){
this
.color = [
"red"
,
"blue"
];
}
/* 创建子类 */
function
Child(){
// 继承父类的属性
Parent.call(
this
);
}
在上面的代码中,我们首先创建了一个父类Parent
,然后创建一个子类Child
,并在子类的内部使用Parent.call(this);
来完成继承。
在函数的属性一文中,我们已经介绍了call()
和apply()
方法,这两个方法的作用是在特定的作用域中调用函数,也就是说这两个方法可以通过函数名称来调用函数。在这里我们在Child的内部使用Parent.call(this);
来完成继承,这句话的意思是在子类中调用父类的构造函数,此时的this
指的是Child对象(在Child中的this
应该是执行Child的对象),所以就等于在Child中有了一句this.color = ["red","blue"];
,也就是等于在Child中有了this.color
属性,这样也就变相的完成了继承。
我们可以通过下面的方法来进行验证:
var
c1 =
new
Child();
//创建子类对象c1
c1.color.push(
"Green"
);
//为c1添加新的颜色
console.info(c1.color);
//控制台输出:red,blue,Green
var
c2 =
new
Child();
//创建子类对象c2
console.info(c2.color);
//控制台输出:red,blue
在上面的代码中,我们创建了子类对象c1,并为它添加新的颜色”Green“,所以会在控制台中输出:"red,blue,Green"。然后我们又创建了对象c2,因为没有为它添加新的颜色,所以它只会在控制台中输出继承自父类的颜色:"red,blue"。
每调用一次new Child
就等于执行了一次对象属性的设定,此时,每个对象的空间中都有color
属性,而不会在原型中存在,所以color
不会被共享。这样就解决了原型链继承中引用类型变量存在的问题。
子类构造函数
原型链继承的另外一个缺点是无法从子类中调用父类的构造函数,这样就没有办法把子类中的属性赋值到父类中。通过函数伪造的方式可以很好的解决这个问题。来看下面的例子:
// 创建父类
function
Parent(name){
this
.name = name;
}
//创建子类
function
Student(name,age){
//使用伪造的方式就可以把子类的构造函数参数传递到父类中
Parent.call(
this
,name);
//调用父类的属性
this
.age = age;
}
var
s1 =
new
Student(
"Leon"
,22);
var
s2 =
new
Student(
"Ada"
,25);
console.info(s1.name +
","
+ s1.age);
// 控制台输出:Leon,22
console.info(s2.name +
","
+ s2.age);
// 控制台输出:Ada,25
在上面的代码中,子类Student通过函数伪造的方式调用父类的name
属性,实际上是为子类添加一个name
属性。在这里,call()
方法将Student类的参数name
传递到父类中,完成的操作相当于this.name = name;
。而这个name
属性是子类的name
属性,而不是父类的name
属性。
基于函数伪造实现继承存在的问题
在上面的讨论中,我们讲的只是子类继承父类的属性,那么子类如何继承父类的方法呢?在前面我们说过,通常我们将方法放到原型中设置,例如父类中有一个say()
方法,代码如下:
// 创建父类
function
Parent(name){
this
.name = name;
}
// 父类的say()方法
Parent.prototype.say =
function
(){
console.info(
this
.name);
}
//创建子类
function
Student(name,age){
Parent.call(
this
,name);
this
.age = age;
}
由于使用函数伪造的方式不会完成子类Student的原型指向父类Parent,所以在子类继承父类之后,say()
方法是不存在的。解决这个问题的方法是,将say()
方法放置到Parent中使用this
关键字来创建。
// 创建父类
function
Parent(name){
this
.name = name;
// 父类的say()方法
this
.say =
function
(){
console.info(
this
.name);
}
}
//创建子类
function
Student(name,age){
Parent.call(
this
,name);
this
.age = age;
}
这样做虽然可以使子类继承父类的say()
方法,但是又产生了另外一个问题:每次创建子类对象的时候都会生成一个say()
方法,会占用大量的内存空间。
由于基于函数伪造的方式实现继承也存在缺陷,所以我们也不会单独使用这种方式来完成继承,而是会使用基于组合的方式实现继承,我们将在下一篇文章中介绍这种继承方式。
- JavaScript面向对象-基于函数伪造的方式实现继承
- JavaScript面向对象-基于原型链和函数伪装组合的方式实现继承
- JavaScript的继承--伪造对象
- JavaScript面向对象编程(继承实现方式)
- JavaScript使用伪造方式实现继承
- JavaScript面向对象的继承机制实现方式
- 面向对象---基于组合的继承:属性的继承基于伪装的方式实现,而方法的继承基于原型链的方式继承。
- javascript 面向对象的继承的实现
- javascript实现面向对象的继承
- 面向对象的JavaScript 四 ----- Javascript实现继承的方式(1)
- 面向对象的JavaScript 五 ----- Javascript实现继承的方式(2)
- 面向对象的JavaScript 六 ---- javascript 继承方式总结
- JavaScript对象之面向对象的三种继承方式
- javascript的面向对象 函数 闭包 构造函数 继承
- 函数伪造,组合实现继承
- JavaScript基于面向对象之继承机制
- Javascript面向对象编程(二):构造函数的继承
- Javascript面向对象编程(二):构造函数的继承
- Android中如何实现播放音频设置不同的播放速率(MediaPlayer SoundPool AudioTrack OpenSL ES)
- LeetCode 101. Symmetric Tree
- 怎样用通俗的语言解释什么叫 REST,以及什么是 RESTful?
- 前端面试准备(一)
- 再谈pmt中的streamtype
- JavaScript面向对象-基于函数伪造的方式实现继承
- Java集合题
- Git 撤销 merge
- 经典书单 —— 语言/算法/机器学习/深度学习/AI/CV/PGM
- android 实现FlowLayout 流线布局(自定义ViewGroup)
- MySql函数 FIND_IN_SET 在Hibernate HQL语句中的使用
- Effective Objective-C 2.0 总结
- 赋值运算和赋值表达式
- 六个藉藉无名但迅速崛起的Apache大数据项目