javaScript设计模式之面向对象编程(object-oriented programming,OOP)(二)
接上一篇
面向对象编程的理解?
答:面向对象编程,就是将你的需求抽象成一个对象,然后针对这个对象分析其特征(属性)与动作(方法)。这个对象我们称之为类。面向对象编程思想其中一个特点就是封装,就是把你需要的功能放在一个对象里。
一、封装
1.1创建一个类
在javascript中创建一个类,很容易,
方法一:首先,声明一个函数保存在变量里,然后,在这个函数内部通过this(函数内部自带的一个变量,用于指向当前这个对象)变量添加属性或者方法,来实现对类的添加属性或方法。
举个例子:
var Book = function(id,bookname,price){this.id = id;this.bookname = bookname;this.price = price; }
方法二:可以通过类的原型添加属性或方法,有两种方法,不要混用
(1)为原型对象属性赋值的方法
Book.prototype.display = function(){//展示这本书 };
(2)将对象赋值给类的原型对象
Book.prototype = {display:function(){} };
我们需要的方法和属性都封装在我们抽象的Book类里,当使用功能方法时,我们不能直接使用这个Book类,需要用关键字new来实例化新的对象。使用实例化对象的属性或者方法时,可以通过点语法来访问
var book = new Book(10,'javascript课本',50); console.log(book.bookname);
由于JavaScript的函数级作用域,声明在函数内部的变量以及方法在外界是访问不到的,通过此特性即可创建类的私有变量以及私有方法。然而在函数内部通过this创建的属性和方法,在类创建对象时时,每一个对象自身都拥有一份并且可以外部访问的。因此通过this创建,不但可以访问这些对象的共有属性与共有方法,而且还可以访问到类或者对象自身的私有属性和私有方法。
//私有属性,私有方法;特权方法,对象公有属性,对象公有方法;构造器var Book = function(id,name,price){//私有属性var num = 1;//私有方法function checkId(){};//特权方法this.getName = function(){};this.getPrice = function(){};this.setName = function(){};this.setPrice = function(){};//对象公有属性this.id = id;//对象公有方法this.copy = function(){};//构造器this.setName(name);this.setPrice(price); };
使用原生的prototype对象。
//静态类公有属性(对象不能访问) Book.isChinese = true;//类静态公有方法(对象不能访问) Book.resetTime = function(){console.log('new time'); };Book.prototype = {//公有属性isJSBook:false,//公有方法display:function(){} }
通过new关键字创建的对象时对新对象this的不断赋值,并将prototype指向类的prototype所指向的对象,而类的构造函数外面通过点语法定义的属性方法是不会添加到新创建的对象上去的。
var b = new Book(11,'JavaScript设计',50); console.log(b.num); //undefined console.log(b.isJSBook); //false console.log(b.id); //11 console.log(b.isChinese); //undefined
类的私有属性num,以及静态公有属性isChinese在新创建的b对象里访问不到。而类的公有属性isJSBook在b对象中却可以通过点语法访问到。
但是类的静态公有属性isChinese可以通过类的自身访问。
console.log(Book.isChinese); //true Book.resetTime(); //new time
1.2闭包实现
你对闭包的理解?
答:闭包是有权访问另外一个函数作用域中变量的函数,即在一个函数内部创建另外一个函数。我们将这个闭包作为创建对象的构造函数,这样它既是闭包又是可实例化对象的函数,即可访问到类函数作用域的变量,这个变量叫静态私有变量,静态私有方法。
二、继承
总结类: 发现每一个类都有3个部分:
1、第一部分是构造函数内的,供实例化对象复制用的;
2、第二部分是构造函数外的,直接通过点语法添加的,这是供类使用的,实例化对象时访问不到的;
3、第三部分是类的原型中的,实例化对象可以通过其原型链间接的访问到,也是为供所有的实例化对象所共有的。
JavaScript中没有继承这一个现有的机制,该如何实现呢?
(一)子类的原型对象--类式继承
比如:常见的类式继承
//类式继承 //声明父类 function SuperClass(){this.superValue = true; } //为父类添加共有方法 SuperClass.prototype.getSuperValue = function(){return this.superValue; };//声明子类 function SubClass(){this.subValue = false; }//继承父类 SubClass.prototype = new SuperClass();//为子类添加共有方法 SubClass.prototype.getSubValue = function(){return this.subValue; }
刚才封装,对比,继承里面声明了2个类,而且第二个类的原型prototype被赋予第一个类的实例。
类式继承需要将第一个类的实例赋值给第二个类的原型。
继承原理:新创建的对象不仅仅可以访问父类原型上的属性和方法,同样可以访问从父类构造函数中复制的属性和方法。将这个对象赋值给子类的原型,那么这个子类的原型同样可以访问父类原型上的属性和方法与从父类构造函数中复制的属性和方法。
var instance = new SubClass(); console.log(instance.getSuperValue()); //true console.log(instance.getSubValue()); //false
在js中,有一个关键字instanceof 来判断某一个对象是否为某一个类的实例,或者说某一个对象是否继承了某个类,这样可以判断对象和类之间的关系
instanceof如何知道对象和类之间的继承关系呢?
答;instanceof是通过判断对象的prototype链来确定这个对象是否是某一个类的实例,而不关心对象与类的自身结构。
console.log(instance instanceof SuperClass); //true console.log(instance instanceof SubClass); //true console.log(SubClass instanceof SuperClass); //false
为啥最后是false,SubClass继承SuperClass,为啥还是false;记住:instanceof是判断前面的对象是否是后边类(对象)的实例,它并不是表示两者的继承。
console.log(SubClass.prototype instanceof SuperClass); //true
类式继承的一个特点:你所创建的所有的对象都是谁的实例?
Object,正式JavaScript为我们提供的原生对象Object。创建的所有的对象都是Object的实例。
console.log(instance instanceof Object); //true
类式继承有两个缺点:
1、由于子类是通过其原型prototype对父类实例化,继承了父类。所以说父类中共有属性要是引用类型,就会在子类中被所有实例共用,因此一个子类的实例更改子类原型从父类构造函数中继承来的共有属性就会直接影响到其他子类。
2、由于子类实现的继承是靠原型的prototype对父类的实例化实现的,因此在创建父类的时候,是无法向父类传递参数的,因而在实例化父类的时候也无法对父类构造函数内的属性进行初始化。
(二)创造即继承--构造函数继承
除了类式继承以外还有构造函数继承
//构造函数式继承 //声明父类 function SuperClass(id){//引用类型共有属性this.books = ['JavaScript','html','css'];//值类型共有属性this.id = id; }//父类声明原型的方法 SuperClass.prototype.showBooks = function(){console.log(this.books); }//声明子类 function SubClass(id){//继承父类 SuperClass.call(this,id); }//创建第一个子类的实例 var instance1 = new SubClass(10); //创建第二个子类的实例 var instance2 = new SubClass(11);instance1.books.push('设计模式'); console.log(instance1.books); //["JavaScript", "html", "css", "设计模式"] console.log(instance1.id); //10 console.log(instance2.books); //["JavaScript", "html", "css"] console.log(instance2.id); //11
注意:SuperClass.call(this.id);这个语句是构造函数式继承的精华,由于call这个方法可以更改函数的作用域,
由于这种类型的继承没有涉及到原型prototype,所以父类的原型方法自然就不会被子类继承,而如果想被子类继承就必须放在构造函数中,这样创造出来的每一个实例都会拥有一份而不能共用,这样就违背了代码复用的原则。
综上这两种模式优点,后来就有了组合式的继承
(三)集合优点--组合继承
总结一下:
(1)类式继承,通过子类的原型prototype对父类实例化来实现的
(2)构造函数继承,通过子类的构造函数作用环境执行一下父类的构造函数来实现的
//组合式的继承 //声明父类 function SuperClass(name){//值类型共有属性this.name = name;//引用类型共有属性this.books = ['html','css','JavaScript']; };//父类原型共有方法 SuperClass.prototype.getName = function(){console.log(this.name); };//声明子类 function SubClass(name,time){//构造函数式继承父类name属性SuperClass.call(this,name);//子类中新增共有属性this.time = time; }//类式继承 子类原型继承父类 SubClass.prototype = new SuperClass(); //子类原型方法 SubClass.prototype.getTime = function(){console.log(this.time); }
组合模式:在子类构造函数中执行父类构造函数,在子类原型上实例化父类。
这样就融合了类式继承和构造函数继承的优点。
var instance1 = new SubClass('js book',2014); instance1.books.push('设计模式'); console.log(instance1.books); //["html", "css", "JavaScript", "设计模式"] instance1.getName(); //js book instance1.getTime(); //2014var instance2 = new SubClass('css book',2013); console.log(instance2.books); //["html", "css", "JavaScript"] instance2.getName(); //css book instance2.getTime(); //2013
子类的实例中更改父类继承下来的引用类型属性如books,根本就不会影响到其他实例。
但是我们在使用构造函数继承时执行了一遍父类的构造函数,而在实现子类原型的类式继承时又调用了一遍父类的构造器。因此父类构造函数调用了两遍,还不是最完美的方式。
(四)洁净的继承者--原型式继承
借助原型的prototype可以根据已有的对象创建一个新对象,同时不必创建新的自定义对象类型。
var inheritObject(item){//声明一个过渡函数对象function F(){};//过渡对象的原型继承父对象F.prototype = item;//返回过渡对象的一个实例,该实例的原型继承了父对象return new F(); }
他是对类式继承的一个封装,其实其中的过渡对象就相当于类式继承中的子类,只不过在原型式中作为一个过渡对象出现,目的是为了创建要返回新的实例化对象。
当然如果你感觉有必要可以将F过渡缓存起来,不必每次都创建一个新过渡类F,随后就出现了Object.create()的方法。
var book = {name: 'js book',alikeBook: ['css book','html book'], };var newBook = inheritObject(book); newBook.name = 'ajax book'; newBook.alikeBook.push('xml book');var otherBook = inheritObject(book); otherBook.name = 'flash book'; otherBook.alikeBook.push('as book');console.log(newBook.name); //ajax book console.log(newBook.alikeBook); //['css book','html book','xml book','as book'] console.log(otherBook.name); //flash book console.log(otherBook.alikeBook); //['css book','html book','xml book','as book'] console.log(book.name); //js book console.log(book.alikebook); //['css book','html book','xml book','as book']
跟类式继承一样,父类对象book中的值类型的属性被复制,引用类型的属性被共用。
转载于:https://www.cnblogs.com/chengxs/p/9311331.html
javaScript设计模式之面向对象编程(object-oriented programming,OOP)(二)相关推荐
- SystemVerilog HVL:面向对象编程(Object Oriented Programming, OOP)
目录 1. 封装 1.1. 构造函数 new 与句柄 1.2. 调用句柄 1.3. 静态属性 与 静态方法 1.4. 权限(local和protected) 2. 继承 2.1. 子类的构造函数 3. ...
- Python编程基础:第三十九节 面向对象编程Object Oriented Programming
第三十九节 面向对象编程Object Oriented Programming 前言 实践 前言 到目前为止我们都是函数式编程,也即将每一个功能块写为一个函数.其实还有一种更常用的编程方式被称为面向对 ...
- 面向对象编程 object oriented programming(OOP)
面向对象编程,是一种编程方式,这种编程方式需要使用"对象"来实现 对象的特征 世间万物皆对象 每个对象都是唯一的 对象具有属性和行为(对象的行为包括具有的功能及具体的实现) 对象具 ...
- BioPython ② | 面向对象编程Object Oriented Programming
BioPython ② | Python面向对象编程 题目要求 定义分子类(Molecule)作为基类,包含集合elements和weight作为其属性,用初始化函数,将elements初始化为空集, ...
- python, 面向对象编程Object Oriented Programming(OOP)
把对象作为程序的基本单元,一个对象包含了数据和操作数据的函数. 面向过程的程序设计把计算机程序视为一系列的命令集合,即一组函数的顺序执行.为了简化程序设计,面向过程把函数继续切分为子函数,即把大块函数 ...
- 面向对象编程 object oriented programming(OOP)(第二篇)
函数装饰器 对于某个函数,如果我们希望在不改变该函数代码的前提下,为该函数增加额外的功能,那么就可以使用装饰器来装饰该函数. 装饰器是一个函数,装饰器接收一个函数作为参数(传入的实参是被装饰的函数) ...
- Java SE 008 理解面向对象程序设计 (Inside Object Oriented Programming)
Java SE 008 理解面向对象程序设计 (Inside Object Oriented Programming) 前言:此笔记为圣思园张龙老师讲述的java视频课程笔记,自己看视频学习时记录的, ...
- 【前端系列教程之JavaScript】15_JavaScript面向对象编程
JavaScript面向对象编程 面向对象概述 什么是对象 Everything is object (万物皆对象) 对象到底是什么,我们可以从两次层次来理解. (1) 对象是单个事物的抽象. 一本书 ...
- Object Oriented Programming面向对象编程
OOP 面向对象编程( Object Oriented Programming)是一种 计算机编程 架构.OOP 的一条基本原则是 计算机程序是由单个能够起到子 程序作用的单元或 对象组合而成.OOP ...
最新文章
- ChromeDriver和PhantomJS配置到$PATH
- 抖音短视频怎么加文字 怎么在视频画面批量添加一行滚动字幕?
- 基于Android的太阳方位角计算工具
- 针对QQ邮箱发邮件限制的解决方案
- 金融分析与风险管理——期权BSM模型
- 百度地图标注公司那家好
- 外地人在成都买房被限购怎么办?看完就知道
- 练习 用C语言编写一个程序,解释高等数学中的映射、单射和一一映射,并表示为函数。
- 手游公司运维之初识MongoDB
- ★戏子入画、一生天涯
- 【网络】什么是HTTPS证书?
- 集合类 Java中的集合类解析和一些有深入的面试题
- 1.OpenCV介绍
- form表单如何不直接提交?
- 世间百态诉说~福莫福于少事,祸莫祸于多心。
- 图表生成pdf,出坑经历
- 关于股市里的那些事,学会选股;赢在起跑线
- android studio官网
- OPPO R9m线刷包_OPPO R9m刷机包_线刷救砖
- Python 实现动态人流量计数, 百度AI接口
热门文章
- 神经网络代码解读_强化学习、联邦学习、图神经网络,飞桨全新工具组件详解...
- 【机器学习】机器学习从零到掌握之四 -- 教你使用可视化分析数据
- 论文审稿意见太奇葩?NeurIPS 2021
- AI前沿 | Gartner曲线5大趋势:传感和移动、超能人类、自动机器人、高级人工智能…...
- java 火星坐标转wgs84_js中火星坐标、百度坐标、WGS84坐标转换实现方法示例
- 揭秘自动驾驶纯视觉算法,探索自动驾驶的未来
- C语言指针变量--图示易懂
- 等式与不等式约束的序列二次规划(SQP)
- Arcgis遇到的各种问题的解决方法暨处理数据分析的一些好习惯
- 华为鸿蒙3799跟4799有啥区别,华为鸿蒙智慧屏出世!3799元高价,是增智慧还是智商税?...