文档章节

JavaScript 面向对象学习——2

learn_more
 learn_more
发布于 2014/12/01 00:34
字数 1646
阅读 150
收藏 13

    继承是面向对象的特性(封装、抽象、继承、多态)之一,JavaScript作为面向对象语言自然拥有继承的特性。如果想要真正理解JavaScript的继承机制,那么应该从JavaScript对象的原型说起。

    1 prototype

    每一个对象都有一个原型属性,当然,不同的浏览器对这个属性包装不一样。比如我们使用 Firefox 或者 Google浏览器就能通过 __proto__ 获取属性指向的实例引用(原型对象)。IE浏览器不能通过以上方法获取,并不能说明这个对象不存在!我们知道JavaScript中函数也是一个对象,一个Function对象,既然是对象他也有原型对象的引用,他的属性名称就是prototype,换句话:我们能够通过函数调用prototype的方式获取原型引用。函数又可以称作为类,那么类的实例所拥有的原型引用与函数本身所拥有的原型引用是完全相同的,这就保证了原型共享,为继承打好了基础。

    总结:

         1)每个函数都有一个prototype(原型)属性,这个属性是一个对象,它的用途是包含所有实例共享的属性和方法。逻辑上可以这么理解:使用原型的好处可以让所有对象实例共享它所包含的属性和方法,而且函数本身与该函数所有的实例共享一个原型。

        2)函数调用原型采用 Class.prototype,实例调用原型属性 obj.__proto__,判断(Class.prototype ==obj.__proto__)

        3)原型是一个对象,一个实例化的对象,这个对象的实例化过程比较特殊,特殊之处在于他不是通过类本身去实例化的,但是他又是该类的实例。比如一个类 function Person(name,age){ this.name=name; ....}; var p = new Person('learn',23);如果p的原型是通过类本身去实例化的话,那么原型一定会有一个name属性,然而实际上原型是一个 Person{ };却不是一个Person的实例,又不是通过Person的构造方法new出来的。可以用 instanceof 测试这个原型不属于Person实例。

function Person(name ,age){
  this.name = name;
  this.age = age;
  this.info = function(){
    return this.name + this.age;
  };
}
var p = new Person('learn',23);
console.info(Person.prototype); // Person{}
console.info(p.__proto__); // Person{}
console.info(Person.prototype == p.__proto__ );//true
console.info(p.__proto__ instanceof Person);//false

    2 constructor

    与原型一样,每一个函数都有一个constructor属性,每一个函数的原型也有一个constructor属性,既然原型中有constructor属性,自然每一个对象实例就能共享这个constructor属性。那么这里要注意了:函数其实有两个constructor属性,一个是自身的属性,可以通过 Class.constructor 获取(js属性调用就近原则),一个是原型中的constructor属性,可以通过 Class.prototype.constructor 或者 obj.__proto__.construcotr 获取。这两个是有本质差异的,前者是一个匿名函数的引用,后者是该类本身的引用。而且前者是类专有私有的属性,是不被实例共享的。实际开发中,我们不会去触碰前者,我们往往是在继承的时候对后者进行改变。

    总结:

        1)每个函数都有一个类私有的constructor属性和一个原型当中共享的constructor属性

        2)只有类本身才能调用这个私有属性:Class.constructor ;原型constructor属性调用:obj.consturctor 或 obj.__proto__.construcotr 或 Class.prototype.constructor

        3)类私有的constructor属性指向一个匿名函数的引用,注意是函数引用,不是函数的实例引用;原型的constructor属性则是指向类本身的引用,这里也是函数引用,不是实例引用。

        4)原型的constructor属性是一个类的重要标志,他一定要指向类本身,因为面向对象规定构造函数指向本身。然而类的私有constructor属性是由系统决定,我们不最好不要触碰。

console.info(Person.constructor);//Function()
console.info(Person.prototype.constructor);// Person(name, age)
console.info(p.constructor);// Person(name, age)
console.info(p.__proto__.constructor);// Person(name, age)

    3 extend

    JavaScript是通过原型进行继承的,原型的作用就是共享,所以通过原型可以很好的达到继承机制。采用原型继承时要注意必不可少的两点:子类的原型必须指向父类的实例,子类原型的constructor属性必须指向子类本身。通过原型指向父类实例,从而所有子类实例共享父类的属性与方法,达到继承效果。通过子类原型的constructor属性指向子类本身,达到面向对象中要求的构造函数指向之间。

        总结:

        1)子类的原型指向父类的实例,SubClass.prototype = new SuperClass( );

        2)子类的原型构造函数指向子类本身,SubClass.prototype.constructor = SubClass ;

        3 ) 由于js使用原型继承,导致构造函数也被继承,然而面向对象来说这是错误的,所以才有第二步重新指向构造函数。

        4 ) 个人理解 Person 与 Person.prototype 的差异是:前者是指构造函数或类本身,后者其实是一个所有实例都共享的实例对象。

        5)如果单纯只是调用某一个函数那么可以使用 call 函数进行处理,而无需继承。 Class.method.call(Self , param) ; 

function extends( SubClass , SuperClass){
/*第一步 : 构建桥梁类Bridge,他的作用就是完全替代父类本身,包括构造方法*/
var Bridge = function( ){ } ;
Bridge.prototype = new SuperClass( ); // Bridge.prototype.constructor = SuperClass ;这一步原型链默认完成 
/*第二步 : 使用子类的原型链继承桥梁父类*/
SubClass.prototype = new Bridge( );  
SubClass.prototype.constructor = SubClass;  
/*第三步 : 扩展子类属性,把父类的引用作为子类的共享属性,为子类中所调用 */
SubClass.prototype.superClass = SuperClass.prototype;       //  这里必须是prototype,而不能是函数本身
/*第四步 : 为保证程序正常运行机制,做个小判断*/
if( SuperClass.prototype.constructor == Object.prototype.constructor  ){
SuperClass.prototype.constructor = SuperClass;
} 
}
6)javascript是单继承的,但如果想在一个类中拥有多个类的方法,那么就要使用聚合(掺元类,把其他类的方法为自己所用)。
具体如下:
function mixin(ReceivingClass,GivingClass){
    for(var method in GivingClass.prototype ){
        if(ReceivingClass.prototype[method] == undefined){
  /* 这里特别注意使用prototype而不使用原因就是 静态属性 与 原型属性的差异 */
            ReceivingClass.prototype[method]= GivingClass.prototype[method];
        }
    }
}


© 著作权归作者所有

learn_more
粉丝 93
博文 240
码字总数 210196
作品 0
深圳
程序员
私信 提问
分享51本关于JavaScript方面的学习书籍(免费下载)

分享51本关于JavaScript方面的学习书籍(免费下载) 1、JavaScript面向对象15分钟教程 2、原型、作用域、闭包的完整解释 3、Javascript面向对象特性实现(封装、继承、接口) 4、JavaScript面向...

邓剑彬
2012/12/02
1K
12
每个JavaScript工程师都应懂的33个概念

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

Fundebug
2018/10/30
0
0
是时候谈谈JavaScript面向对象了!(我们什么时候更需要它)

前端技术尤其是JavaScript,经常被后端觉得不是正经编程语言,大多数是因为JavaScript是基于函数的语言,因此潜在上使得它在使用和发展上有所局限。 我记得在90年代末和21世纪初,JavaScrip...

Little heaven
05/14
0
0
如何用不到200行代码写一款属于自己的js框架

前言 JavaScript 的核心是支持面向对象的,同时它也提供了强大灵活的 OOP 语言能力。本文将使用面向对象的方式,来教大家用原生js写出一个类似jQuery这样的框架。我们将会学到如下知识点: ...

徐小夕
07/05
0
0
JavaScript开发者应懂的33个概念

简介 这个项目是为了帮助开发者掌握 JavaScript 概念而创立的。它不是必备,但在未来学习(JavaScript)中,可以作为一篇指南。 本篇文章是参照 @leonardomso 创立,英文版项目地址在这里。 ...

大灰狼的小绵羊哥哥
2018/10/22
0
0

没有更多内容

加载失败,请刷新页面

加载更多

阿里maven仓库设置,不设置mirror防止覆盖项目pom指定repo

<?xml version="1.0" encoding="UTF-8"?> <!-- Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file distributed wi......

dead_pools
35分钟前
2
0
在Springboot中编写Mock单元测试

1.概要 软件测试是一个应用软件质量的保证。java开发者开发接口往往忽视接口单元测试。作为java开发如果会Mock单元测试,那么你的bug量将会大大降低。spring提供test测试模块,所以现在小胖哥...

码农小胖哥
48分钟前
14
0
Qt编写自定义控件36-图片浏览器

一、前言 本控件主要用来作为一个简单的图片浏览器使用,可以上下翻页显示图片,图片还可以开启过度效果比如透明度渐变,应用场景有查看报警图片运行图片等。此控件非本人原创,来源于网络,...

飞扬青云
50分钟前
1
0
Java并发编程笔记——J.U.C之collections框架:ConcurrentLinkedQueue

一:ConcurrentLinkedQueue简介 ConcurrentLinkedQueue是线程安全的无界非阻塞队列,其底层数据结构使用单向链表实现,对于入队和出队操作使用CAS来实现线程安全。 Doug Lea在实现Concurren...

须臾之余
今天
2
0
cisco交换机配置ssh远程登陆

前言: 最近整理一些以前的学习笔记(有部分缺失,会有些乱,日后再补)。 过去都是存储在本地,此次传到网络留待备用。 cisco SSH远程登陆配置 0.配置ip,启动端口 Switch>enable ...

迷失De挣扎
今天
1
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部