老生常谈javascript的5中继承
<!DOCTYPE html>
<html> <head>
<meta charset="UTF-8">
<title></title>
<script type="text/javascript">
function MAN(name, sex, age) {
this.name = name;
this.sex = sex;
this.age = age;
this.say = function(school, zhuanye) {
console.log(this.name + "," + this.sex + ",今年" + this.age + "岁!在" + school + "学习" + zhuanye);
}
}
MAN.prototype.cao = function() {
console.log(this.name + "," + this.sex + ",都已经" + this.age + "了,再不疯狂我们就老了!")
} function WOMAN(name, sex, age) {
//方法1:对象冒充
//this.man = MAN;
//this.man(name, sex, age);
//方法2:call
//MAN.call(this,name, sex, age);
//方法3:apply
//MAN.apply(this,[name, sex, age]);
//方法4:bind
//MAN.bind(this)(name, sex, age);
MAN.bind(this)(name, sex, age);
}
//方法5:prototype
WOMAN.prototype = new MAN(); //注意:方法1,2,3,4只能继承this.XXX=XXX的属性,不能继承XXX.prototype.xxx==function(){},注释掉方法5可以看到
//方法5只能继承XXX.prototype.xxx==function(){}的属性,不能继承this.XXX=XXX的属性,注释掉方法1,2,3,4可以看到 var man = new MAN("张三", "男", 26);
man.say('蓝翔技校', '电气焊');
man.cao();
var woman = new WOMAN("小红", "女", 18);
woman.say('清华大学', '挖掘机');
woman.cao();
</script>
</head> <body>
</body> </html>
console.log(man instanceof MAN); //true
console.log(man instanceof Function);//false
console.log(man instanceof Object);//true console.log(man.constructor==MAN);//true
console.log(man.constructor==Object);//false
js继承的概念
js
里常用的如下两种继承方式:
原型链继承(对象间的继承)
类式继承(构造函数间的继承)
由于js
不像java
那样是真正面向对象的语言,js
是基于对象的,它没有类的概念。所以,要想实现继承,可以用js
的原型prototype机制或者用apply
和call
方法去实现
在面向对象的语言中,我们使用类
来创建一个自定义对象。然而js
中所有事物都是对象,那么用什么办法来创建自定义对象呢?这就需要用到js
的原型:
我们可以简单的把prototype
看做是一个模版,新创建的自定义对象都是这个模版(prototype
)的一个拷贝 (实际上不是拷贝而是链接,只不过这种链接是不可见,新实例化的对象内部有一个看不见的__Proto__
指针,指向原型对象)。
js
可以通过构造函数和原型的方式模拟实现类的功能。 另外,js
类式继承的实现也是依靠原型链来实现的。
原型式继承与类式继承
类式继承
是在子类型构造函数的内部调用超类型的构造函数。
严格的类式继承并不是很常见,一般都是组合着用:
function Super(){
this.colors=["red","blue"];
}
function Sub(){
Super.call(this);
}
原型式继承
是借助已有的对象创建新的对象,将子类的原型指向父类,就相当于加入了父类这条原型链
原型链继承
为了让子类继承父类的属性(也包括方法),首先需要定义一个构造函数。然后,将父类的新实例赋值给构造函数的原型。代码如下:
<script>
function Parent(){
this.name = 'mike';
}
function Child(){
this.age = 12;
}
Child.prototype = new Parent();//Child继承Parent,通过原型,形成链条
var test = new Child();
alert(test.age);
alert(test.name);//得到被继承的属性
//继续原型链继承
function Brother(){ //brother构造
this.weight = 60;
}
Brother.prototype = new Child();//继续原型链继承
var brother = new Brother();
alert(brother.name);//继承了Parent和Child,弹出mike
alert(brother.age);//弹出12
</script>
以上原型链继承还缺少一环,那就是Object
,所有的构造函数都继承自Object
。而继承Object
是自动完成的,并不需要我们自己手动继承,那么他们的从属关系是怎样的呢?
确定原型和实例的关系
可以通过两种方式来确定原型和实例之间的关系。操作符instanceof
和isPrototypeof()
方法:
alert(brother instanceof Object)//true
alert(test instanceof Brother);//false,test 是brother的超类
alert(brother instanceof Child);//true
alert(brother instanceof Parent);//true
只要是原型链中出现过的原型,都可以说是该原型链派生的实例的原型,因此,isPrototypeof()
方法也会返回true
在js
中,被继承的函数称为超类型(父类,基类也行),继承的函数称为子类型(子类,派生类)。使用原型继承主要由两个问题:
一是字面量重写原型会中断关系,使用引用类型的原型,并且子类型还无法给超类型传递参数。
伪类解决引用共享和超类型无法传参的问题,我们可以采用“借用构造函数”技术
借用构造函数(类式继承)
<script>
function Parent(age){
this.name = ['mike','jack','smith'];
this.age = age;
}
function Child(age){
Parent.call(this,age);
}
var test = new Child(21);
alert(test.age);//21
alert(test.name);//mike,jack,smith
test.name.push('bill');
alert(test.name);//mike,jack,smith,bill
</script>
借用构造函数虽然解决了刚才两种问题,但没有原型,则复用无从谈起,所以我们需要原型链+借用构造函数
的模式,这种模式称为组合继承
组合继承
<script>
function Parent(age){
this.name = ['mike','jack','smith'];
this.age = age;
}
Parent.prototype.run = function () {
return this.name + ' are both' + this.age;
};
function Child(age){
Parent.call(this,age);//对象冒充,给超类型传参
}
Child.prototype = new Parent();//原型链继承
var test = new Child(21);//写new Parent(21)也行
alert(test.run());//mike,jack,smith are both21
</script>
组合式继承是比较常用的一种继承方法,其背后的思路是 使用原型链实现对原型属性和方法的继承,而通过借用构造函数来实现对实例属性的继承。这样,既通过在原型上定义方法实现了函数复用,又保证每个实例都有它自己的属性。
call()
的用法:调用一个对象的一个方法,以另一个对象替换当前对象。
call([thisObj[,arg1[, arg2[, [,.argN]]]]])
原型式继承
这种继承借助原型并基于已有的对象创建新对象,同时还不用创建自定义类型的方式称为原型式继承
<script>
function obj(o){
function F(){}
F.prototype = o;
return new F();
}
var box = {
name : 'trigkit4',
arr : ['brother','sister','baba']
};
var b1 = obj(box);
alert(b1.name);//trigkit4
b1.name = 'mike';
alert(b1.name);//mike
alert(b1.arr);//brother,sister,baba
b1.arr.push('parents');
alert(b1.arr);//brother,sister,baba,parents
var b2 = obj(box);
alert(b2.name);//trigkit4
alert(b2.arr);//brother,sister,baba,parents
</script>
原型式继承首先在obj()
函数内部创建一个临时性的构造函数 ,然后将传入的对象作为这个构造函数的原型,最后返回这个临时类型的一个新实例。
寄生式继承
这种继承方式是把原型式+工厂模式结合起来,目的是为了封装创建的过程。
<script>
function create(o){
var f= obj(o);
f.run = function () {
return this.arr;//同样,会共享引用
};
return f;
}
</script>
组合式继承的小问题
组合式继承是js
最常用的继承模式,但组合继承的超类型在使用过程中会被调用两次;一次是创建子类型的时候,另一次是在子类型构造函数的内部
<script>
function Parent(name){
this.name = name;
this.arr = ['哥哥','妹妹','父母'];
}
Parent.prototype.run = function () {
return this.name;
};
function Child(name,age){
Parent.call(this,age);//第二次调用
this.age = age;
}
Child.prototype = new Parent();//第一次调用
</script>
以上代码是之前的组合继承,那么寄生组合继承,解决了两次调用的问题。
寄生组合式继承
<script>
function obj(o){
function F(){}
F.prototype = o;
return new F();
}
function create(parent,test){
var f = obj(parent.prototype);//创建对象
f.constructor = test;//增强对象
}
function Parent(name){
this.name = name;
this.arr = ['brother','sister','parents'];
}
Parent.prototype.run = function () {
return this.name;
};
function Child(name,age){
Parent.call(this,name);
this.age =age;
}
inheritPrototype(Parent,Child);//通过这里实现继承
var test = new Child('trigkit4',21);
test.arr.push('nephew');
alert(test.arr);//
alert(test.run());//只共享了方法
var test2 = new Child('jack',22);
alert(test2.arr);//引用问题解决
</script>
call和apply
全局函数apply
和call
可以用来改变函数中this
的指向,如下:
// 定义一个全局函数
function foo() {
console.log(this.fruit);
}
// 定义一个全局变量
var fruit = "apple";
// 自定义一个对象
var pack = {
fruit: "orange"
};
// 等价于window.foo();
foo.apply(window); // "apple",此时this等于window
// 此时foo中的this === pack
foo.apply(pack); // "orange"
博主近来穷的吃土了,如果看完本文的内容后觉得对你有所帮助,想博主更新的勤一点,你不扫一下吗(留言你想学的前端技术,博主有空了就更新呦)
老生常谈javascript的5中继承的更多相关文章
- JavaScript中继承的那些事
引言 JS是一门面向对象的语言,但是在JS中没有引入类的概念,之前特别疑惑在JS中继承的机制到底是怎样的,一直学了JS的继承这块后才恍然大悟,遂记之. 假如现在有一个“人类”的构造函数: functi ...
- Javascript中继承
Javascript中继承 构造函数继承 原型继承 call和apply继承 组合继承
- JavaScript中继承的实现方法--详解
最近看<JavaScript王者归来>中关于实现继承的方法,做了一些小总结: JavaScript中要实现继承,其实就是实现三层含义:1.子类的实例可以共享父类的方法:2.子类可以覆盖父类 ...
- javascript中继承方式及优缺点(三)
文以<JavaScript高级程序设计>上的内容为骨架,补充了ES6 Class的相关内容,从我认为更容易理解的角度将继承这件事叙述出来,希望大家能有所收获. 1. 继承分类 先来个整体印 ...
- 【面试必备】javascript的原型和继承
原型.闭包.作用域等知识可以说是js中面试必考的东西,通过你理解的深度也就能衡量出你基本功是否扎实.今天来复习一下javascript的原型和继承,虽说是老生常谈的话题,但对于这些知识,自己亲手写一遍 ...
- JavaScript对寄生组合式继承的理解
有关JavaScript的几种继承方式请移步JavaScript的几种继承方式 原型链的缺陷 SubType.prototype = new SuperType(); 这样做的话,SuperType构 ...
- web前端学习(二) javascript对象和原型继承
目录 1. JavaScrpt对象 2. 原型对象和继承 3. 对象的克隆 (1)javascript对象 在JS中,对象是属性的容器.对于单个对象来说,都由属性名和属性值构成:其中属性名需要是标识符 ...
- Javascript的实例化与继承:请停止使用new关键字
本文同时也发表在我另一篇独立博客 <Javascript的实例化与继承:请停止使用new关键字>(管理员请注意!这两个都是我自己的原创博客!不要踢出首页!不是转载!已经误会三次了!) 标题 ...
- Javascript之对象的继承
继承是面向对象语言一个非常重要的部分.许多OOP语言都支持接口继承和实现继承两种方式.接口继承:继承方法签名:实现继承:继承实际的方法.在ECMAScript中函数是没有签名的,所以也就无法实现接口继 ...
随机推荐
- charles抓包误点deny处理办法及日常抓包
误点deny方法在最底下~~ (博文为转载) 我们在开发网站项目的时候,我们可以通过浏览器的debug模式来看request以及response的数据,那么如果我们开发移动端项目没有网页呢?如何抓取数 ...
- strcpy、memcpy和memset之间的区别
今天刷题时遇到了这个问题,记录一下. strcpy比较简单,就是拷贝字符串,遇到'\0'时结束拷贝. memcpy用来做内存拷贝,可以拷贝任何数据类型的对象并指定拷贝数据的长度:char a[100] ...
- effective c++读书笔记(一)
很早之前就听过这本书,找工作之前读一读.看了几页,个人感觉实在是生涩难懂,非常不符合中国人的思维方式.之前也有博主做过笔记,我来补充一些自己的理解. 我看有人记了笔记,还不错:http://www.3 ...
- hdu 1907(Nim博弈)
John Time Limit: 5000/1000 MS (Java/Others) Memory Limit: 65535/32768 K (Java/Others)Total Submis ...
- Git分支管理小结
分支管理命令 每次提交,Git都把它们串成一条时间线,这条时间线就是一个分支.截止到目前,只有一条时间线,在Git里,这个分支叫主分支,即master分支.HEAD严格来说不是指向提交,而是指向mas ...
- python中list的底层实现
这里不讨论具体的实现细节,主要是转载这篇文章: 顺序表的原理与python中的list类型. 原文就不贴过来了,总结一下: 确定数据类型的意义在于确定一个数据在内存中占据的空间大小以及如何解释一段内存 ...
- MP3 Music Library in Tornado
Web2.0的lab3,使用tornado实现,自己改了改UI 效果 选中播放列表后的效果 原来的图标长得太丑了,有空找些好看点的加进去……以后继续完成extra feature,当复习python了 ...
- 小甲鱼Python笔记(上)
基于Python 3.4.3 一 二 三 四 基础 print 三版必须加括号,二版不用加 alt + n :上一条语句 alt + p :下一条语句 打印三条hello 没有大括号,用缩进来表示 ...
- 洛谷P3203 [HNOI2010] 弹飞绵羊 [LCT]
题目传送门 弹飞绵羊 题目描述 某天,Lostmonkey发明了一种超级弹力装置,为了在他的绵羊朋友面前显摆,他邀请小绵羊一起玩个游戏.游戏一开始,Lostmonkey在地上沿着一条直线摆上n个装置, ...
- 隐马尔可夫模型(Hidden Markov Model)
隐马尔可夫模型(Hidden Markov Model) 隐马尔可夫模型(Hidden Markov Model, HMM)是一个重要的机器学习模型.直观地说,它可以解决一类这样的问题:有某样事物存在 ...