JavaScript作为一个面向对象语言(JS是基于对象的),可以实现继承是必不可少的,但是由于本身并没有类的概念,所以不会像真正的面向对象编程语言通过类实现继承,但可以通过其他方法实现继承。(javascript中的继承是通过原型链来体现的http://www.cnblogs.com/amumustyle/p/5435653.html)实现继承的方法很多,下面就只是其中的几种。

一.原型链继承

         function Person() {   //被继承的函数叫做超类型(父类,基类)
this.name='mumu';
this.age='18';
} Person.prototype.name='susu';//当属性名相同时需就近原则,先在实例里面查找,没找到再到原型里找 function Worker(){ //继承的函数叫做子类型(子类,派生类)
this.job='student';
} Worker.prototype=new Person();//通过原型链继承,超类型实例化后的对象实例,赋值给子类的原型属性
var p2=new Worker(); console.log(p2.name);
console.log(p2 instanceof Object);//ture 所有的构造函数都继承自Object

以上实现继承关键在于:Worker.prototype=new Person();  将Worker的原型成为Person的一个实例,通过原型链继承。

注意:在使用原型链实现继承时,不能使用对象字面量创建原型方法,因为这样会中断关系而重写原型链。

原型链继承问题:

1.出现引用共享问题,他们还是共用一个空间,子类会影响父类

         function Person() {
this.bodys=['eye','foot'];
} function Worker(){
} Worker.prototype=new Person();
var p1=new Worker();
p1.bodys.push('hand');
var p2=new Worker();
console.log(p1.bodys);
console.log(p2.bodys);

2.在创建子类型的实例时,不能像超类型的构造函数中传递参数。

那么如何解决原型链的两个问题呢?那就继续看下面的继承方式吧~

二.借用构造函数继承(也叫对象冒充,伪造对象或经典继承)

 function Person(name,age){
this.name=name;
this.age=age;
this.bodys=['eye','foot'];
} Person.prototype.showName=function(){
console.log(this.name);
} function Worker(name,age,job){
Person.call(this,name,age);
this.job=job;//子类添加属性
} var p1=new Worker('mumu','18','学生');
p1.bodys.push('hand') ;
var p2=new Worker(); console.log(p1.name);
console.log(p2.bodys);
console.log(p1.showName());

简单分析下以上使用借用构造函数的原理:Person.call(this,name,age);这句代码调用父级构造函数,继承父级属性,使用call方法调用Person构造函数改变函数执行时候的this,  这里的this-> new出来的一个Worker对象  构造函数伪装方法:把Worker传给上面的Person。

当引用类型放在构造函数里面的时候就不会被共享,所以p2不受影响。

这里借用构造函数继承方式就解决了原型链不能传递参数以及引用类型共享的问题。

小知识:call()和apply()方法可以改变函数执行的作用域, 简言之就是改变函数中this指向的内容。

call()和apply()都接受两个参数:第一个是在其中运行函数的作用域,另一个是传递的参数。

    call和apply的区别就是参数的不同.
    call中的参数必须是一个个枚举出来的.
    apply中的参数必须是数组或者是arguments对象

那么问题来了:为什么p1.showName()结果是错误的呢?----因为借用构造函数继承方式只能继承构造函数里的属性和方法。这里也就发现了借用构造函数的一个问题。

注意:由于把方法都放在构造函数里,每次我们实例化就会分配内存空间给它造成资源的浪费,所以一般我们都是把方法放在原型里,属性放在构造函数里。

借用构造函数继承问题:

因为借用构造函数只能继承构造函数里的属性和方法,在超类型的原型中定义的方法对子类而言是不可见的,所以就相当于没有了原型。结果所有的方法都只能在构造函数里定义,因此就没有函数复用了。

那么如何解决借用构造函数所产生的问题呢?那就要看下面这种继承方式了

三.组合继承(伪经典继承)

 function Person(name,age){
this.name=name;
this.age=age;
} Person.prototype.showName=function(){
console.log(this.name);
} function Worker(name,age,job){
Person.call(this,name,age);//借用构造函数
this.job=job;
} Worker.prototype=new Person();//原型链继承
var p1=new Worker('mumu','18','学生'); console.log(p1.age);
p1.showName();

组合继承:将原型链与借用构造函数结合。

思路:通过使用原型链实现原型上的属性和方法继承,借用构造函数实现实例属性的继承

以上的例子Person.call(this,name,age);借用构造函数继承了属性

Worker.prototype=new Person();原型链继承了方法 , 避免了两者的缺点,融合了它们的优点,成为最常用的继承模式。

组合继承的问题:

调用两次超类型构造函数,一次是在创建子类型原型时,另一次是在子类型的构造函数内部。

要解决这个问题就要用到寄生组合式继承方式了。

四.原型式继承

 function object(proto) {
function F() {}
F.prototype = proto;
return new F();
} var person = {
name: 'mumu',
friends: ['xiaxia', 'susu']
}; var anotherPerson = object(person);
anotherPerson.friends.push('wen');
var yetAnotherPerson = object(person);
anotherPerson.friends.push('tian');
console.log(person.friends);//["xiaxia", "susu", "wen", "tian"]
console.log(anotherPerson.__proto__)//Object {name: "mumu", friends: Array[4]}

简单分析下:function object(proto)是一个临时中转函数,里面的参数proto表示将要传递进入的一个对象,F()构造函数是临时新建的对象,用来存储传递过来的对象,F.prototype = proto;将对象实例赋值给F构造函数的原型对象,最后返回传递过来的对象的对象实例。原型式继承还是会共享引用类型的属性。

五.寄生式继承

 //临时中转函数
function object(proto) {
function F() {}
F.prototype = proto;
return new F();
} //寄生函数
function create(proto){
var f=object(proto);
f.love=function(){
return this.name;
}
return f;
} var person = {
name: 'mumu',
friends: ['xiaxia', 'susu']
}; var anotherPerson = create(person);
23 console.log(anotherPerson.love());寄生组合式继承

六.寄生组合式继承

 function object(proto) {
function F() {}
F.prototype = proto;
return new F();
} //寄生函数
function create(Person,Worker){
var f=object(Person.prototype);//创建对象
f.constructor=Worker;//调整原型构造指针,增强对象
Worker.prototype=f;//指定对象
} function Person(name,age){
this.name=name;
this.age=age;
}
Person.prototype.showName=function(){
console.log(this.name);
}
function Worker(name,age,job){
Person.call(this,name,age);
this.job=job;
} create(Person,Worker);//寄生组合式继承
var p1=new Person('mumu','18','学生');
p1.showName();

这种方法也是现在实现继承方法中最完美的,也是最理想的。

JavaScript继承学习笔记的更多相关文章

  1. 【09-23】js原型继承学习笔记

    js原型继承学习笔记 function funcA(){ this.a="prototype a"; } var b=new funcA(); b.a="object a ...

  2. JavaScript正则表达式学习笔记(二) - 打怪升级

    本文接上篇,基础部分相对薄弱的同学请移步<JavaScript正则表达式学习笔记(一) - 理论基础>.上文介绍了8种JavaScript正则表达式的属性,本文还会追加介绍几种JavaSc ...

  3. javascript正则表达式 - 学习笔记

    JavaScript 正则表达式 学习笔记 标签(空格分隔): 基础 JavaScript 正则表达式是用于匹配字符串中字符组合的模式.在javascript中,正则表达式也是对象.这些模式被用于Re ...

  4. JavaScript简易学习笔记

    学习地址:http://www.w3school.com.cn/js/index.asp 文字版: https://github.com/songzhenhua/github/blob/master/ ...

  5. javaScript 对象学习笔记

    javaScript 对象学习笔记 关于对象,这对我们软件工程到学生来说是不陌生的. 因为这个内容是在过年学到,事儿多,断断续续,总感觉有一丝不顺畅,但总结还是要写一下的 JavaScript 对象 ...

  6. 【转载】Javascript原型继承-学习笔记

    阮一峰这篇文章写的很好 http://www.ruanyifeng.com/blog/2011/06/designing_ideas_of_inheritance_mechanism_in_javas ...

  7. 【MarkMark学习笔记学习笔记】javascript/js 学习笔记

    1.0, 概述.JavaScript是ECMAScript的实现之一 2.0,在HTML中使用JavaScript. 2.1 3.0,基本概念 3.1,ECMAScript中的一切(变量,函数名,操作 ...

  8. Javascript MVC 学习笔记(一) 模型和数据

    写在前面 近期在看<MVC的Javascript富应用开发>一书.本来是抱着一口气读完的想法去看的.结果才看了一点就傻眼了:太多不懂的地方了. 仅仅好看一点查一点,一点一点往下看吧,进度虽 ...

  9. Javascript作用域学习笔记(三)

    看完<你不知道的javascript>上,对作用域的新的理解(2018-9-25更) 一.学习笔记:   1.javascript中的作用域和作用域链 +  每个函数在被调用时都会创建一个 ...

随机推荐

  1. Android异常一、异步任务导致的窗口句柄泄漏问题(转)

    05-05 10:36:41.009: E/WindowManager(4243): Activity com.tao.MyActivity has leaked window com.android ...

  2. c/c++基本问题

    1. 使用g++将文件编译成库文件 g++ -c -O2 -fPIC test.cpp -o test.o && g++ -shared -Wall -o test.so test.o ...

  3. 第一部分 CLR基础:第1章 CLR的执行模型

    1.1将源代码编译成托管模块

  4. 记一次动态调用WebService

    这次的使用参考博客园中的ID是  生命不息,折腾不止 http://www.cnblogs.com/leolion/p/4757320.html ,感谢分享 博客园让自己慢慢的成长,少不了这些无私奉献 ...

  5. Silverlight读取Zip文件中的图片与视频

    首先看看Demo的截图: 下面我将一步步展示实现这个Demo的过程,这个需求就是读出Zip文件中的图片与视频. Demo整体架构: 首先我们准备几张图片和视频,然后将其压缩至resource.zip文 ...

  6. js执行过程

    正如我们了解的一样,当我们书写了JS程序之后,打开浏览器,我们的代码就可以开始运行了(当然保证你的代码没有问题,才能按照你的预期进行执行).刚才说的是JS执行的一个大的环境,今天我们学习一下,JS在解 ...

  7. Java transient volatile关键字(转)

    Volatile修饰的成员变量在每次被线程访问时,都强迫从主内存中重读该成员变量的值.而且,当成员变量发生变化时,强迫线程将变化值回写到主内存.这样在任何时刻,两个不同的线程总是看到某个成员变量的同一 ...

  8. CSS 设置TABLE 表格 边框

    /*table列表 合并边框设置*/ .tablelist { border-collapse:collapse; } /*table列表 设置边框宽度及颜色*/ .tablelist td { bo ...

  9. "大账户"时代

    当要下载某文件时,哪怕是免积分,也需要登陆账户才能下载.  当要浏览某论坛时,只有注册账户,才可以浏览帖子.  当要网购商品时,必须注册账户,还要有众多宝宝平台,才可以实现交易.  当要团购时,必须先 ...

  10. Redis 五:配置主从复制功能

    redis的主从复制事实上是非常简单的一件事情,甚至比mysql的配置还简单,因为基本不需要在主服务器上做任何操作 我们在同一台服务器上开不同的端口进行测试操作(安装部分就不说啦,前面的文章有::) ...