一、OOP的概念和继承

1、OOP概念

面向对象程序设计(Object-oriented programming,OOP)是一种程序设计范型,同时也是一种程序开发的方法。对象指的是类的实例。它将对象作为程序的基本单元,将程序和数据封装其中,以提高软件的重用性、灵活性和扩展性。

OOP特点:继承、封装、多态和抽象。

2、基于原型的继承

  1. function Foo(){
  2. this.y=2;
  3. }
  4.  
  5. /*每个函数对象有一个对象属性prototype,这个prototype是个对象,Fooj就是Foo.prototype*/
  6.  
  7. Foo.prototype.x=1;
  8. var obj3=new Foo();
  9. /*创建一个Foo的实例obj3,
  10. 使用new调用的时候,Foo作为构造器来使用,并且this指向一个对象,而这个对象的原型会指向构造器的prototype属性,也就是Foo.prototype*/
  11.  
  12. console.log(obj3.y); //2 对象上的
  13. console.log(obj3.x); //1 原型上的

3、prototype属性与原型

用函数声明创建一个空函数function Foo(){}的时候,函数就会有一个prototype对象属性。

prototype对象属性默认会有2个属性,一个是constructor,会指向它本身Foo;另外一个是_proto_,一般的对象都会指向Object.prototype。

x:1是通过赋值语句Foo.prototype.x=1;增加的。

Foo.prototype的作用:

当使用new Foo去构造Foo的实例的时候,这个prototype属性会用作new出来的对象(obj1,obj2,obj3...)的原型(_proto_)。

prototype:是函数对象上面预设的对象属性。

_proto_:对象上的原型,通常都是它的构造器的prototype属性。

4、更复杂的实例:

Student继承Person

  1. <script>
  2. function Person(name,age){//new方法调用,this作为 return值
  3. this.name=name;
  4. this.age=age;
  5. }
  6. /*Person.prototype添加实例共享的属性和方法*/
  7. Person.prototype.hi=function(){
  8. console.log('Hi,my name is'+this.name+"I'm"+this.age+"years old now.");
  9. }
  10.  
  11. Person.prototype.LEGS_NUM=2;
  12. Person.prototype.ARMS_NUM=2;
  13. Person.prototype.walk=function(){
  14. console.log(this.name+" is wlking...");
  15. }
  16. /*初始化Student类*/
  17. function Student(name,age,className) {
  18. Person.call(this,name,age);//先调用父类初始化
  19. this.className=className;
  20. }
  21.  
  22. /*继承*/
  23. Student.prototype=Object.create(Person.prototype);
  24. Student.prototype.constructor=Student;
  25. /*覆盖基类的hi方法*/
  26. Student.prototype.hi=function(){
  27. console.log('Hi,my name is '+this.name+",I'm "+this.age+" years old now,and from "+this.className+'.');
  28. }
  29.  
  30. Student.prototype.learn=function(subject){
  31. console.log(this.name+' is learning '+subject+' at '+this.className+'.');
  32. }
  33. //test
  34. var bosn=new Student('Bosn',27,'Class 3,Grade 2');
  35. console.log(bosn.hi());//Hi,my name is Bosn,I'm 27 years old now,and from Class 3,Grade 2.
  36. console.log(bosn.LEGS_NUM);//
  37. bosn.walk();
  38. //Bosn is wlking...
  39. bosn.learn('math');
  40. //Bosn is learning math at Class 3,Grade 2.
  41. </script>

二、原型链

如下:

从后往前:

bosn构造:通过 new Student()创建了bosn实例,bosn实例的原型_proto_指向构造器的prototype属性,也就是Student.prototyep。Studnet.prototype上面有hi()方法和learn()方法。

Studnet.prototype构造:通过Object.create(Person.prototype)来构造。Student.prototype是个空对象,这个空对象随后添加了hi()方法和learn()方法,它的原型_proto_指向了Person.prototype。

Person.prototype:直接定义了一个Person函数,在Person.ptototype上添加了共享的属性和方法,这个Person.prototype就是一个内置的普通对象。它本身也会有原型就是Object.prototype。

坑1:

并不是所有的对象,最终原型链上都有Object.prototype。

通过Object.create(null)创建的对象原型链上没有Object.prototype,也就没有Object.prototype上的方法。

坑2:

并不是所有的函数对象都会有prototype属性。

ES5的bind()函数用来修改函数在运行时的this。

bind方法返回的也是一个函数,可以通过typeof判断一下,但是bind()方法返回的函数就没有prototype属性。

三、prototype属性

1、prototype相关的修改

  1. /*给prototype添加属性和方法会影响到已创建或新创建的实例*/
  2. Student.prototype.x=101;
  3. console.log(bosn.x); //
  4.  
  5. /*修改prototype并不会影响已经创建的实例,会影响后续创建的实例*/
  6. Student.prototype={y:2};
  7. console.log(bosn.y); //undefined
  8. console.log(bosn.x); //
  9.  
  10. var nunnly=new Student('Nunnly',3,'Class LOL KengB');
  11. console.log(nunnly.x); //undefined
  12. console.log(nunnly.y); //

2、内置的构造器的prototype

内置的函数构造器也有prototype属性,比如Object,Number,Boolean,Function,等等。

bind,apply,call等等都是从Function的prototype上取到的。

边际效应:

修改这些构造器的prototype有时候会带来一些边际效应。

  1. Object.prototype.x=1;
  2. var obj={};
  3. console.log(obj.x); //
  4. for(var key in obj){
  5. console.log('result: '+key);
  6. }
  7. //result: x

边际效应:在prototype上添加属性x,在for in遍历的时候会把x遍历出来。

解决办法:

ES5里面有defineProperty来控制对象属性。默认标签都是false,下面只设置writable:true。简洁表示不可枚举,也不可配置。

  1. Object.defineProperty(Object.prototype,'x',
  2. {writable:true,value:1});
  3. var obj={};
  4. console.log(obj.x); //
  5. for(var key in obj){
  6. console.log('result: '+key);
  7. }
  8. //nothing output here

这样for in的时候就不会有边际效应。所以如果写nodejs,判断一下如果有defineProperty,可以通过这种方式来改写Object.property这样一些内置构造器上的prototype的时候,可以跨过这样一个边际效应。

很少会用到修改Object.prototype,因为影响范围太广了。 但是有时候为了兼容性可能会通过Object.defineProperty做一些ES5才支持的方法模拟。

四、实现继承的方式

见代码。

  1. <script>
  2. function Person(){
  3. }
  4. function Student(){
  5. }
  6.  
  7. Student.prototype=Person.prototype;//1 禁止用,改变Student也会修改Person
  8.  
  9. Student.prototype=new Person();//2
  10. /*可以实现,问题:比如构造函数有一个name和age,new Person()的时候name和age传什么呢?传任何东西都是很奇怪的。因为Student只是一个类,还没有实例化。
  11.  
  12. 所以这里只是为了继承调用了Person的构造函数,创建了一个实例,在很多情况下也是比较奇怪的。
  13. */
  14. Student.prototype=Object.create(Person.prototype);//
  15. Student.prototype.constructor=Person;
  16.  
  17. /*第三种是相对理想的办法*/
  18. /*
  19. 创建了一个空的对象,并且对象的原型指向了Person.prototype。既保证了继承Person.prototype删的方法,并且Student.prototype又有自己的一个空的对象,Student.prototype的修改又不会影响Person.prototype。
  20. */
  21.  
  22. /*Object.create是ES5才支持的方法,在ES5之前可以模拟实现*/
  23. if(!Object.create){
  24. Object.create=function(proto){
  25. function F(){};
  26. F.prototype=proto;
  27. return new F; /*new调用时创建一个对象,并且原型指向F.prototype,即proto*/
  28. }
  29. }
  30. </script>

本文作者starof,因知识本身在变化,作者也在不断学习成长,文章内容也不定时更新,为避免误导读者,方便追根溯源,请诸位转载注明出处:http://www.cnblogs.com/starof/p/4904929.html有问题欢迎与我讨论,共同进步。

javascript OOP(上)(八)的更多相关文章

  1. Javascript多线程引擎(八)

    Javascript多线程引擎(八)    Javascript 多线程项目, 做到现在已经快3个月了(加上前期准备编译原理和必要的文档), 该项目(js-engine)已经快进入尾声了, 现在该引擎 ...

  2. 使用JavaScript OOP特性搭建Web应用

    最近,我面试了一个有五年 Web 应用程序开发经验的软件开发人员.四年半来她一直在从事 JavaScript 相关的工作,她自认为 JavaScript 技能非常好,但在不久之后我就发现实际上她对 J ...

  3. 几款极好的 JavaScript 文件上传插件

    文件上传功能作为网页重要的组成部分,几乎无处不在,从简单的单个文件上传到复杂的批量上传.拖放上传,需要开发者花费大量的时间和精力去处理,以期实现好用的上传功能.这篇文章向大家推荐几款很棒的 JavaS ...

  4. JavaScript返回上一页代码区别

    JavaScript返回上一页代码区别: window.history.go(-1); //返回上一页 window.history.back(); //返回上一页 //如果要强行刷新的话就是:win ...

  5. 【精心推荐】几款极好的 JavaScript 文件上传插件

    文件上传功能作为网页重要的组成部分,几乎无处不在,从简单的单个文件上传到复杂的批量上传.拖放上传,需要开发者花费大量的时间和精力去处理,以期实现好用的上传功能.这篇文章向大家推荐几款很棒的 JavaS ...

  6. AGS API for JavaScript 图表上地图

    原文:AGS API for JavaScript 图表上地图 图1 图2 图3 -------------------------------------华丽丽的分割线--------------- ...

  7. JavaScript: 世界上最被误解的语言|Douglas Crockford

    JavaScript: 世界上最被误解的语言 JavaScript: The Wrrrld's Most Misunderstood Programming Language Douglas Croc ...

  8. jQuery UI 是建立在 jQuery JavaScript 库上的一组用户界面交互、特效、小部件及主题

    jQuery UI 是建立在 jQuery JavaScript 库上的一组用户界面交互.特效.小部件及主题.无论您是创建高度交互的 Web 应用程序还是仅仅向窗体控件添加一个日期选择器,jQuery ...

  9. JavaScript OOP 之 this指向

    今天给大家分享一个JavaScript OOP中关于分辨this指向对象的小技巧,很实用呦! 我们先来看一段代码: 大家能判断出func();和obj.func();这两句的this指向吗? 首先,我 ...

  10. JavaScript返回上一页和返回上一级页面并刷新

    JavaScript返回上一页和刷新当前页 window.history.go(-1); //返回上一页 window.history.back(); //返回上一页 //如果要强行刷新的话就是:wi ...

随机推荐

  1. 【转】JVM内存结构 VS Java内存模型 VS Java对象模型

    JVM内存结构 我们都知道,Java代码是要运行在虚拟机上的,而虚拟机在执行Java程序的过程中会把所管理的内存划分为若干个不同的数据区域,这些区域都有各自的用途. 其中有些区域随着虚拟机进程的启动而 ...

  2. hibernate框架学习之多表查询helloworld

    package cn.itcast.h3.hql; import java.util.List; import org.hibernate.Query; import org.hibernate.Se ...

  3. gPRC学习笔记

    gPRC学习笔记 gPRC基础教程. gPRC官方文档. protobuf 3.0的简易教程. 什么是RPC RPC(remote procedure call) -- 远程过程调用(相对于本地调用的 ...

  4. PHP随机红包算法

    2017年1月14日 14:19:14 星期六 一, 整体设计 算法有很多种, 可以自行选择, 主要的"架构" 是这样的, 用redis decr()命令去限流, 用mysql去记 ...

  5. python学习第40天

    # 多表查询 # 索引的基础理论 + 数据准备

  6. appium+java(五)微信小程序自动化测试实践

    前言: 上一篇<appium+java(四)微信公众号自动化测试实践>中,尝试使用appium实现微信公众号自动化测试,接着尝试小程序自动化,以学院小程序为例 准备工作 1.java-cl ...

  7. [C]*和&

    一 .& c的&被称为“寻址运算符”,作用是指向某变量的指针: 请看以下代码: int main(void){ int int_1 = 16;        printf(" ...

  8. 洛谷P4705 玩游戏 [生成函数,NTT]

    传送门 这是两个月之前写的题,但没写博客.现在回过头来看一下发现又不会了-- 还是要写博客加深记忆. 思路 显然期望可以算出总数再乘上\((nm)^{-1}\). 那么有 \[ \begin{alig ...

  9. EasyUI Layout 布局

    1.在整个页面上创建布局(Layout) <!DOCTYPE html> <html> <head> <title>吹泡泡的魚-主页</title ...

  10. 三.linux磁盘与文件系统

    第一层 机械硬盘 和 固态硬盘 结构 接口 机械硬盘stat.sas 固态pci-e .nvme也叫m2 硬盘的选择 磁盘内部组成 计算硬盘的大小 命令 fdisk  -l 显示下面信息 大小=扇区大 ...