当前位置: 首页 > news >正文

Javascript 面向对象编程—继承和封装

  前  言

 Javascript是一种基于对象(object-based)的语言,你遇到的所有东西几乎都是对象。但是,它又不是一种真正的面向对象编程(OOP)语言,因为它的语法中没有class(类)。面向对象主要专注于有哪一个对象来解决这个问题,编程特点时出现一个个的类,从类中拿到对象,有这个对象去解决具体问题。 对于调用者来说,面向过程需要调用者去实现各种函数。而面向对象,只需要告诉调用者对象中的具体方法的功能, 而不需要调用者了解方法中的实现细节。

 而面向过程主要专注于如何去解决一个问题的步骤。编程特点是由一个个的函数去实现每一步的过程步骤,没有类和对象的概念。

 

一、 继承

我们首先解释一下继承的概念,所谓继承就是使用一个子类,继承另一个父类,那么子类可以自动拥有父类中的所有属性和方法,这个过程叫继承,继承的两方,发生在两个类间。

然后我们阐述一下实现继承的原理, 通过循环将父类对象的所有属性,全部赋给子类对象。关键点在于for-in循环, 即使不扩展循环Object,也能通过简单的循环实现操作
  

1.1扩展Object实现继承。

 

 1 function Person(name,age){
 2                 this.name=name;
 3                 this.age=age;
 4                 this.say=function(){
 5                     alert("我叫"+this.name);
 6                 }
 7             }
 8             
 9             function Student(no){
10                 this.no=no;
11                 this.study=function(){
12                     alert("我在学习");
13                 }
14             }
15             
16             var p=new Person("张三",12);
17             var s=new Student("12345");
18             for(var i in p){
19                 s[i]=p[i];
20             }
21             
22             Object.prototype.extend1=function(){
23                 for(var i in parent){
24                     this[i]=parent[i];
25                 }
26             }
27             s.extend1(p);
28             
29             console.log(s);

但是呢,扩展Object继承也有如下缺点:
① 无法通过一次实例化,拿到完整的子类对象,而需要先拿到父类对象和子类对象两个对象,手动合并
② 扩展Object继承方法,也会保留在子类对象上

 

1.2使用原型实现继承

我们先说说使用原型继承的原理, 将父类对象,赋值给子类的prototype,那么父类对象的属性和方法就会出现在子类的prototype中。  那么,实例化子类时,子类的prototype又不会到子类对象的__proto__中,  最终,父类对象的属性和方法,会出现在子类对象的__proto__


这种继承的特点主要是,子类自身的所有属性,都是成员属性,父类继承过来的属性,都是原型属性,但是依然无法通过一次实例化拿到所有的子类对象。

 1 function Person(name,age){
 2                 this.name=name;
 3                 this.age=age;
 4                 this.say=function(){
 5                     alert("我叫"+this.name);
 6                 }
 7             }
 8             
 9             function Student(no){
10                 this.no=no;
11                 this.study=function(){
12                     alert("我在学习");
13                 }
14             }
15             
16             Student.prototype=new Person("张三",12);
17             var s=new Student(15);
18             console.log(s);

 

1.3使用call和apply以及bind实现继承

我们先解释一下call/bind/apply三个函数的作用,这三个函数通过函数名调用这三个函数,可以强行将函数中的this指定为某个对象。

 

 1 var name="window"
 2             function func(a,b){
 3                 console.log(this.name+a+b);
 4             }
 5             var obj={
 6                 name:"zhangsan"
 7             }
 8             var obj1={
 9                 name:"lisi"
10             }
11             func(1,2);//window12
12             func.call(obj,1,2);//zhangsan12
13             func.apply(obj1,[1,2]);//lisi12
14             func.bind(obj)(1,2);//zhangsan12
15             
16             
17             function Person(name,age){
18                 this.name=name;
19                 this.age=age;
20                 this.say=function(){
21                     alert("我叫"+this.name);
22                 }
23             }
24             
25             function Student(no,name,age){
26                 this.no=no;
27                 this.study=function(){
28                     alert("我在学习");
29                 }
30                 Person.call(this,name,age);
31             }
32             var s=new Student(12345,"张三",15);
33             console.log(s);

这三个函数的唯一区别,在于接受func参数列表的方式不同,除此之外,功能上无区别。

 

二、 封装

什么叫封装呢?封装分为方法的封装和属性的封装。
所谓 方法的封装就是将类内部的函数进行私有化处理,不对外提供调用接口,无法在类外部使用的方法,称为私有方法,即方法的封装。

而属性的封装: 将类中的属性进行私有化处理,对外不能直接使用对象名访问(私有属性)。 同时,需要提供专门用于设置和读取私有属性的set/get方法,让外部使用我们提供的方  法,对属性进行操作。 这就叫属性的封装。

封装也有需要 注意的地方, 封装不是拒绝访问,而是限制访问。  要求调用者,必须使用我们提供的set/get方法进行属性的操作,而不是直接拒绝操作。 

因此,单纯的属性私有化,不能称为封装!必须要私有化之后,提供对应的set/get方法。

 

1、 生成实例对象的原始模式

 

1.1我们把人看做一个对象,人有"姓名"和"年龄"两个属性。

 

1 var Person={
2 
3       name : "张三",
4 
5       age : "12"    
6   
7 }

 

1.1我们根据这个原型对象的模式,生成两个实例对象。

 

1  var Person1= {}; // 创建一个空对象
2         Person1.name = "张三"; // 按照原型对象的属性赋值
3         Person1.age= "12";
4  var Person2= {};
5         Person2.name = "李四";
6         Person2.age= "15"; 
7 
8 //这就是最简单的封装了,把两个属性封装在一个对象里面。       

 

2、 原始对象模式的改进

 

1  function Person(name,age) {
2     return {
3       name:name,
4       age:age    
5            }
6  }
7 
8  var Person1= Person("张三","12");
9  var Person2= Person("李四","15");

 

3、 构造函数

构造函数:其实就是一个普通函数,但是内部使用了this变量。对构造函数使用new运算符,就能生成实例,并且this变量会绑定在实例对象上。

我们来说说创建一个类和对象的大概步骤,

首先,创建一个类(构造函数):类名必须使用大驼峰法则。即每个单词首字母大写。

function 类名(属性1){
    this.属性1=属性1;
    this.方法=function(){
     //方法中要调用自身属性,必须使用this.方法
    }
   }
   通过类,实例化(new)出一个对象。
   var obj=new 类名(属性1的具体值);
   obj.属性; //调用属性
   obj.方法(); //调用方法

 

 1 //人的原型对象
 2  function Person(name,age){
 3     this.name=name;
 4     this.age=age;
 5  }
 6 
 7 //生成实例对象
 8  var Person1= new Person("张三","12");
 9  var Person2= new Person("李四","15");
10  console.log(Person1.name); // 张三
11  console.log(Person2.age); // 15
12 
13 //Person1 和 Person2都会有一个constructor属性,返回当前对象的构造函数
14  console.log(Person1 .constructor == Person); //true
15  console.log(Person2 .constructor == Person); //true
16 
17 //instanceof检测一个对象是不是一个类的实例
18  console.log(Person1 instanceof Person); //true
19  console.log(Person2 instanceof Person); //true

构造函数需要注意以下几点,
1、通过一个类名,new出一个对象的过程,叫做"类的实例化"
2、类中的this,会在实例化的时候指向新的new出的对象
所以,this.方法this.属性,实际上是将属性和方法绑定在即将new出的对象上,在类中调用自身属性,必须使用this.属性名。如果直接使用变量名,则无法访问对应的属性。 类名必须使用大驼峰法则,注意区分与普通函数的区别。
   

4、 Prototype模式

 

prototype 属性允许您向对象添加属性和方法,每一个构造函数都有一个prototype属性,指向另一个对象。这个对象的所有属性和方法,都会被构造函数的实例继承。

1  function Person(name,age){
2         this.name=name;        
3         this.age=15;
4  }
5  Person.prototype.age=12;            
6  var zhangsan=new Person("张三");
7  console.log(zhangsan.age);        

 

编者按

  Javascript面向对象是最难的,初学者不容易掌握,可以多多参考参考专门Javascript面向对象的资料,最后,希望各位和小编一起努力,在前端的路上越走越远!

转载于:https://www.cnblogs.com/lgc-17862800193/p/7671064.html

相关文章:

  • 沃土前端社区教程 - es6(7)常用技能点
  • MATH
  • EXTJS学习系列基础篇:第二篇(转载)作者殷良胜
  • 一卡通vip充值消费线上oracle库服务器故障排查过程
  • 通过UseAfterFree实现命令执行
  • javaScript滚动新闻之上下左右平滑滚动
  • putty和xshell的应用
  • 图表控件amCharts
  • 在 Linux 中使用 Azure Premium 存储的基本优化指南
  • 闰年算法
  • CSS实例:图片导航块
  • 翻译 A Gentler Introduction to Programming
  • 一致性哈希算法(Consistent Hashing)
  • linux系统调用的三种方法
  • 在线小工具推荐
  • es6(二):字符串的扩展
  • ESLint简单操作
  • GDB 调试 Mysql 实战(三)优先队列排序算法中的行记录长度统计是怎么来的(上)...
  • JavaScript标准库系列——Math对象和Date对象(二)
  • JavaScript创建对象的四种方式
  • Mac转Windows的拯救指南
  • node-glob通配符
  • 干货 | 以太坊Mist负责人教你建立无服务器应用
  • 那些年我们用过的显示性能指标
  • 如何优雅的使用vue+Dcloud(Hbuild)开发混合app
  • 小程序01:wepy框架整合iview webapp UI
  • 用jQuery怎么做到前后端分离
  • ​软考-高级-系统架构设计师教程(清华第2版)【第1章-绪论-思维导图】​
  • #includecmath
  • #绘制圆心_R语言——绘制一个诚意满满的圆 祝你2021圆圆满满
  • $HTTP_POST_VARS['']和$_POST['']的区别
  • (1)安装hadoop之虚拟机准备(配置IP与主机名)
  • (附源码)ssm基于web技术的医务志愿者管理系统 毕业设计 100910
  • (附源码)计算机毕业设计SSM教师教学质量评价系统
  • (七)理解angular中的module和injector,即依赖注入
  • (亲测)设​置​m​y​e​c​l​i​p​s​e​打​开​默​认​工​作​空​间...
  • (求助)用傲游上csdn博客时标签栏和网址栏一直显示袁萌 的头像
  • (四)TensorRT | 基于 GPU 端的 Python 推理
  • (一)VirtualBox安装增强功能
  • (转)visual stdio 书签功能介绍
  • (转)程序员技术练级攻略
  • (转)平衡树
  • (转)四层和七层负载均衡的区别
  • (转载)PyTorch代码规范最佳实践和样式指南
  • .naturalWidth 和naturalHeight属性,
  • .NET Core 2.1路线图
  • .net framework profiles /.net framework 配置
  • .net FrameWork简介,数组,枚举
  • .net redis定时_一场由fork引发的超时,让我们重新探讨了Redis的抖动问题
  • .net 流——流的类型体系简单介绍
  • .NET 使用 JustAssembly 比较两个不同版本程序集的 API 变化
  • .NET/C# 在代码中测量代码执行耗时的建议(比较系统性能计数器和系统时间)...
  • .net6解除文件上传限制。Multipart body length limit 16384 exceeded
  • .Net中的设计模式——Factory Method模式
  • .net中应用SQL缓存(实例使用)