当你在使用手机的时候,你会发现,你并不懂得其中的原理就会操作了,其实这就是面向对象的思想。面向对象还有很多地方都会运用到。JavaScript也不例外,现在跟随我的脚步,来学习一下吧。

面向过程和面向对象编程概述 面向过程编程就是分析出解决问题的步骤,然后使用函数把这些步骤一步步实现,重心放在完成的每个过程上。 面向对象则是以封装的思想,将问题分析得到的数据封装成一个个的对象,然后通过对对象的操作来完成相应的功能。 举个栗子:厨师炒菜 以面向过程的思想来分析应该分为下面几个步骤: ​ 1.检查食材是否齐全 2.如果不不够,去菜市场买菜 3.洗菜 4.开火 5.按炒菜(按顺序放入相应的食材,调料等) 6.出锅装盘 以面向对象的思想分析则是这样的: ​ 1.厨师,检查食材,炒菜 2.采购员,去菜市场买菜 3.墩子,洗菜,切菜,备菜 ​ 通过调用上面对象中的行为方法即可完成炒菜的整个过程 从上面的例子可以看出,面向对象和面向过程最大的不同在于,面向对象关心的是由哪些对象,每个对象应该有哪些功能,而面向过程关心的是实现过程中的每个步骤。 那么这两种思想到底孰优孰劣呢?从表面上看,貌似面向对象更好,为什么呢?因为它完全符合我们的正常思维方式,所以在接受度方面,面向对象的思想肯定是更好。但是面向过程也有他的优势,就是灵活便捷,而面向对象相对来说会更耗资源,更慢一点。 所以,至于以后使用哪一种,这就需要看我们的具体需求,根据不同的需求做不同的选择。 面向对象编程的相关概念 通过上面的分析,我们知道面向对象的重点在于功能分析和对象的封装上,那么最终我们得到的对象的结构是怎样的,我们继续往下学习。 比如,我通过对人的分析得到,每个人都有姓名,年龄,性别等属性,同时也有吃饭睡觉等行为,那么用JS可以做如下的封装: var p = { name : "xiao song", age : 10, sex : 1, eat : function () { console.log("吃饭"); }, sleep : function () { console.log("睡觉"); } }console.log(p.name);//访问对象的属性 p.eat();//访问对象的方法 上面的p则表示一个对象,其中的name / age / sex称之为对象的属性,eat / sleep 称之为对象的方法,我们通过访问该对象的属性或者方法达到相应的目的即可。 DOM操作相关知识点复习 在学习了html之后我们发现,html文档中的内容其实就是由一堆的标签组成,由于在后面的课程中需要使用到html,所以我们先大致的回顾一下它的结构。

H5-JS面向对象

div h3:元素节点 id class:属性节点 H5-JS面向对象:文本节点 一个html文档主要由这三部分组成,DOM(文档对象模型)是对操作这些元素的属性或者方法进行了封装,从而达到方便快捷的操作html的目的。 获取元素对象:document.getElementById("div1") 访问元素的属性:div1.className 访问元素的文本内容:div1.innerText 增删改元素:div1.appendChild(newNode) 下面,我们就通过这些API来讲解说明面向对象相关的内容。 创建并设置标签(面向过程) 需求1:创建三个div元素,并设置边框,背景色,文本及字体颜色 for (var i = 0; i < 3; i++) { var div = document.createElement("div"); div.innerText="div"+i; div.style.backgroundColor="green"; div.style.border="1px solid #000"; div.style.color="white"; document.body.appendChild(div); } ![在这里插入图片描述](https://img-blog.csdnimg.cn/20191220094107944.jpeg) 需求2:为页面中存在的三个P元素设置边框,背景色,文本及字体颜色

我是P1

我是P2

我是P3

需求3:获取页面上三个class=“test”的元素,设置边框,背景色,文本及字体颜色

我是标题1

我是标题2

我是标题3

上面的代码是以面向过程的思想完成的,可以看到,两个需求中的每个步骤都是我们一步一步完成的,问题很明显,代码大量的冗余,这种代码后期不好维护。 创建并设置标签(函数封装) 对于上面重复的代码,我们可以使用函数对其进行封装

封装了三个函数:

  1. setStype(eles,bgcolor):为元素设置样式
  2. eles:哪些元素
  3. bgcolor:背景色
  4. getElementsByTagName(tagName):根据元素名称获取指定的元素
  5. tagName:元素名
  6. getElementsByClassName(className):根据class属性名获取指定的元素
  7. className:class属性名
  8. 接下来就是调用三个方法完成了上面的需求,解决了第一种方式中大量的重复代码的问题。 但是,这种方式仍然存在问题。在前面JS基础中说过,我们应该尽量避免大量使用全局变量,这会降低程序的执行效率,在上面的程序中,我们就出现了5个(包括函数)。所以需要继续优化。 创建并设置标签(面向对象) 使用面向对象的思想来解决上面的问题,我们可以将上面的三个函数都装到一个对象中 var .getElementsByTagName("p").getElementsByClassName("test");这个对象中添加即可 如,根据元素的id属性获取元素,并未其设置样式 getElementById:function (eleId) { return [document.getElementById(eleId)]; } 需要注意的是,在设置样式方法中,我们默认是将传递进来的元素当做数组进行处理的,所以,在这里,我们在getElementById方法中,手动将获取到的元素添加到数组中返回。 通过观察,在= { getElements:{ byTagName: function (tagName) { return document.getElementsByTagName(tagName); }, byClassName:function (className) { return document.getElementsByClassName(className); }, byId:function (eleId) { return [document.getElementById(eleId)]; } }, setStype:function (eles,bgcolor) { for (var i = 0; i < eles.length; i++) { eles[i].style.backgroundColor=bgcolor; eles[i].style.border="1px solid #000"; eles[i].style.color="white"; } } } 将获取元素的方法封装到$对象的getElements属性中,今后如果还有其他获取元素的方法,都应该是添加到getElements属性中,其他类型的方法也应该按照这种思想进行封装。 面向对象编程的三大特性 面向对象的特性: 封装 作用:复用和信息隐藏 封装,也就是把客观事物封装成抽象的类,并且类可以把自己的数据和方法只让可信的类或者对象操作,对不可信的进行信息隐藏。 继承 它可以使用现有类的所有功能,并在无需重新编写原来的类的情况下对这些功能进行扩展。 通过继承创建的新类称为“子类”或“派生类”。 被继承的类称为“基类”、“父类”或“超类”。 继承的过程,就是从一般到特殊的过程。 多态 当存在继承关系时,允许将父类对象看成为和它的一个或多个子类对象等同. 这样,可以根据当前赋给父类对象的子对象的具体特性以不同的方式进行运行. 用字面量方式创建对象 直接使用字面量方式创建对象比较方面,以键值对的格式来定义数据 var book1 = { name:"JavaScript权威指南", price:100, author:"tim", showInfo:function () { console.log(this.name,this.price,this.author); } }console.log(book1); 上面定义了一个书对象,并为其添加了属性和方法,我们也可以直接访问其中的属性和方法。 这种方式的弊端是,如果需要创建多个类似的对象,就显得不太方便了,会出现大量的重复代码。 也就是说,这种方式不适合创建大量的相同或相似的对象。 内置构造函数和简单工厂创建对象 使用new关键字+内置的构造函数创建对象 var book2 = new Object(); book2.name="JS"; book2.price=10; book2.author="作者"; book2.showInfo=function () { console.log(this.name,this.price,this.author); } book2.showInfo(); 这种方式和字面量方式创建对象存在的问题差不多,在大量创建对象的时候都会存在大量重复的代码。 那么,利用前面的封装的思想,我们应该可以想到,当有重复代码的时候,我们可以将这些重复代码抽取到函数中来解决。 function createBook(name, price, author) { var book = new Object(); book.name=name; book.price=price; book.author=author; book.showInfo=function () { console.log(this.name,this.price,this.author); } return book; }var book3 = createBook("bookName1",10,"author1");var book4 = createBook("bookName2",10,"author2");console.log(book3);console.log(book4); 我们将创建book对象的代码封装到createBook函数中,当需要创建一个book对象的时候,直接调用该函数,将函数需要的参数传递过去即可。 那么,相同的思想,如果我们需要创建其他的对象,一样可以使用封装函数的方法来解决,这是没问题的。 function createPerson(name, age) { var p = new Object(); p.name = name; p.age = age; return p; }console.log(createPerson("Neld", 10)) 利用上面的函数,我们可以创建一个Person对象出来,但是通过打印对比,我们无法通过创建出来的对象判断该对象的类型,而在实际开发中,判断对象的类型是我们经常需要执行的,所以我们继续看下面的自定义构造函数创建对象。 自定义构造函数创建对象 构造函数和普通的函数的定义方式完全一样,如下,我们定义一个创建Person的构造函数 function createPerson(name, age, sex) { this.name=name; this.age=age; this.sex=sex; }var p = new createPerson("Neld", 10, 1);var p2 = new createPerson("Song", 12, 0);console.log(p);console.log(p2); 自定义函数和工厂函数非常相似,但是还是存在很大的区别
  9. 构造函数名的首字母要求大写
  10. 需要使用new关键字和构造函数一起创建对象
  11. 在函数中,不需要手动创建对象进行数据封装,会自动创建并封装数据
  12. 在函数最后,不需要手动返回创建好的对象,会自动返回 到这里,大家肯定会有疑问,自定义构造函数到底是如何创建并封装对象呢?
  13. 在函数内部默认会创建一个空对象 var obj = new Object();
  14. 默认把创建好的对象赋值给this this = obj;
  15. 默认设置this的原型对象为当前构造函数的原型对象
  16. 通过this添加属性和方法
  17. 默认会把内部创建的对象返回 return this; 通过上面的分析,相信大家已经能够理解自定义构造函数的基本使用以及基本的原理了。 构造函数创建对象的返回值 默认情况下,构造函数内部会返回新创建好的对象(this) 主动返回:
  18. 如果返回值类型的数据,仍然返回创建好的对象(this),不做任何修改
  19. 如果返回引用类型的数据,则返回指定的数据,不再返回this。 函数作为构造函数参数使用 在JS世界里,函数属于一等公民,拥有最高特权,在使用过程中可以作为变量赋值,可以作为参数传递,也可以作为函数的返回值,下面我们具体来看看他的使用。 函数作为参数使用 function f1(name,age,fn) { console.log("name:",name,"age:",age); fn(); }function fn(){ console.log("Hello H5"); } f1("Neld", 10, fn); 输出结果: ​ name: Neld age: 10 ​ Hello H5 在上面的代码中,我们将函数fn作为参数传递给了函数f1,并且在函数f1中调用,得到的相应的打印输出。 函数作为返回值使用 function f1(name,age,fn) { console.log("name:",name,"age:",age); return fn; }function fn(){ console.log("Hello H5"); }var retFun = f1("Neld", 10, fn); retFun(); 在函数f1中将传递进来的fn作为返回值返回,接收到调用f1之后的返回值得到的是返回的函数,然后在调用retFun得到打印结果。 此时的f1为高阶函数,即参数中有一个或多个函数,并且把函数作为返回值。 此时的fn为回调函数,fn作为参数传递给函数f1,在f1内部调用。 函数作为构造函数的参数使用 function createPerson(name, age, sex, say) { this.name=name; this.age=age; this.sex=sex; this.say=say; }var p = new createPerson("Neld", 10, 1, function () { console.log("say hello"); });var p2 = new createPerson("Song", 12, 0,function () { console.log("say bye"); }); p.say(); p2.say(); 在构造函数中也可以对方法进行封装,如果方法的实现是由调用者决定的,那么可以在构造函数中接收一个函数对象,然后在构造函数中进行封装。 如上面的函数say,在创建p和p2对象的时候传递并赋值给形参say,然后在构造函数中赋值给当前对象。 构造器属性 前面说到工厂函数创建对象是比较方便的,但是存在一个问题就是无法得知创建出来的对象的类型,所以我们选择使用自定义的构造函数来创建,构造函数创建对象我们已经会使用了,那么如何通过他得知创建对象的类型呢?这里我们提供两种方式。
  20. constructor属性

function Person(name) { this.name = name; }function Dog(name) { this.name = name; }var p = new Person("p");var d = new Dog("d");console.log(p.constructor);//打印得到Person函数对象console.log(d.constructor);//打印得到Dog函数对象if(p.constructor == Person){ console.log("是Person对象"); }if(d.constructor == Dog){ console.log("是Dog对象"); } 3. 使用constructor属性可以获取到创建对象使用的构造器函数对象,所以我们可以通过判断构造器的类型来得知创建的对象的类型 4.

  1. instanceof关键字

function Person(name) { this.name = name; }function Dog(name) { this.name = name; }var p = new Person("p");var d = new Dog("d");console.log(p instanceof Person);//trueconsole.log(d instanceof Person);//false

  1. instanceof关键字可以直接用来判断对象的类型,如果是指定的类型,返回true,反之返回false。

构造函数的调用和命名 在学习了构造函数之后,有的同学对于它和普通函数的区别还是不太清楚,这里我们就再对构造函数做一个说明。 1. 构造函数和普通函数在定义语法上没有任何区别 2. function 函数名(参数列表){代码块;} 3. 4. 为了和普通函数区分开,我们约定将构造函数的名称首字母大写 5. 6. 构造函数一样可以直接调用,此时内部的this执行window,这种方式不太安全,有可能会在函数内部修改当前的全局变量,不建议使用,而且这样做也不能创建对象 7. 8. 想要创建对象,必须使用new和构造函数一起使用 9. 函数上下文和this指针 在JS编程的过程中发现,我们大量使用到this关键字,用好了this,能让我们的代码更加优雅。 this总是执行一个对象(引用类型),但是具体执行谁,需要根据我们在哪里使用this有关。这里主要分为下面几种情况:

  1. 函数外部
  2. 函数外部的作用域是全局作用域(window),所以,在全局作用域中使用的this指向window
  3. 普通函数内部
  4. 函数内部的作用域是局部的,属于调用当前函数的对象,所以this执向调用当前函数的对象
  5. 构造函数内部
  6. 在构造函数中,this直接执行当前创建出来的新对象
  7. 在开发中,我们也可以使用call或者apply函数修改this的执行,这一点我们在后面继续说明。 自定义构造函数存在的问题 自定义构造函数可以解决工厂函数带来的对象类型不确定的问题,在开发中用得非常多,那么目前我们的自定义构造函数又是否存在问题呢?先来看看下面的对象内存结构分析。 function Person(name, age, say) { this.name = name; this.age = age; this.say = function(){ console.log("say hello"); } }var p = new Person("zs", 10, say);console.log(p); 上面创建的p对象的内存结构图:

  1. 可以看出,我们没创建一个Person对象,都会在内存中分配如0x22和0x33这样的内存来存储数据,但是通过观察发现,0x33中存储的是一个函数,而这个函数在每个对象中都是相同

所以从内存资源分配考虑,我们无需为每个对象创建并分配一份新的函数对象(完全相同),这种函数大家最好共享同一份。 如何实现多个对象共享同一份数据呢,这就需要使用到原型相关的知识点了。

关于JavaScript面向对象的内容就到此为止了,如果你还想了解关于JavaScript的其他内容,不妨关注我们,接下来我还会发布其他内容供大家学习。

关于JavaScript面向对象那些事的更多相关文章

  1. javascript面向对象系列第一篇——构造函数和原型对象

    × 目录 [1]构造函数 [2]原型对象 [3]总结 前面的话 一般地,javascript使用构造函数和原型对象来进行面向对象编程,它们的表现与其他面向对象编程语言中的类相似又不同.本文将详细介绍如 ...

  2. Javascript面向对象(封装、继承)

    Javascript 面向对象编程(一):封装 作者:阮一峰 Javascript是一种基于对象(object-based)的语言,你遇到的所有东西几乎都是对象.但是,它又不是一种真正的面向对象编程( ...

  3. Javascript 面向对象编程

    Javascript是一个类C的语言,他的面向对象的东西相对于C++/Java比较奇怪,但是其的确相当的强大,在 Todd 同学的“对象的消息模型”一文中我们已经可以看到一些端倪了.这两天有个前同事总 ...

  4. 转:javascript面向对象编程

    作者: 阮一峰 日期: 2010年5月17日 学习Javascript,最难的地方是什么? 我觉得,Object(对象)最难.因为Javascript的Object模型很独特,和其他语言都不一样,初学 ...

  5. javascript面向对象系列第四篇——OOP中的常见概念

    前面的话 面向对象描述了一种代码的组织结构形式——一种在软件中对真实世界中问题领域的建模方法.本文将从理论层面,介绍javascript面向对象程序程序(OOP)中一些常见的概念 对象 所谓对象,本质 ...

  6. (三)Javascript面向对象编程:非构造函数的继承

    Javascript面向对象编程:非构造函数的继承   这个系列的第一部分介绍了"封装",第二部分介绍了使用构造函数实现"继承". 今天是最后一个部分,介绍不使 ...

  7. Javascript面向对象编程(三):非构造函数的继承(对象的深拷贝与浅拷贝)

    Javascript面向对象编程(三):非构造函数的继承   作者: 阮一峰 日期: 2010年5月24日 这个系列的第一部分介绍了"封装",第二部分介绍了使用构造函数实现&quo ...

  8. JavaScript 面向对象编程(三):非构造函数对象的继承

    JavaScript 面向对象编程(三):非构造函数对象的继承 一.什么是"非构造函数"的继承? 比如,现在有一个对象,叫做"中国人". var Chinese ...

  9. javascript面向对象之Javascript 继承

    转自原文javascript面向对象之Javascript 继承 在JavaScript中实现继承可以有多种方法,下面说两种常见的. 一,call 继承 先定义一个“人”类 //人类 Person=f ...

随机推荐

  1. UNICODE和UCS

    Unicode是国际组织制定的可以容纳世界上所有文字和符号的字符编码方案.目前的Unicode字符分为17组编排,0x0000 至 0xFFFF,每组称为平面(Plane),而每平面拥有65536个码 ...

  2. 实现:python3_解析shodan_json数据

    前言:今天,一美元可以开通shodan,急忙去买了一个哈哈!! 下载json格式的数据,可以通过该脚本进行解析,得到相应的ip:port的格式 示例代码: # coding=utf-8 import ...

  3. File upload - MIME type

    Your goal is to hack this photo galery by uploading PHP code.Retrieve the validation password in the ...

  4. haproxy 2.0 dataplaneapi rest api 转为graphql

    haproxy 2.0 dataplaneapi rest api 是比较全的,以下是一个简单的集成graphql,通过swagger-to-graphql 转换为graphql api 方便使用 环 ...

  5. SDU暑假排位第一场 (Gym - 100889)

    啊今天有点挂机啊 D题和队友暴力后发现一组数据跑得飞快 然后遇上1e5组数据就没了..... 然后我疯狂优化暴力 然后去世了 最后半小时F也没写出来 主要还是最后有点慌并且没有考虑清楚 导致情况越写越 ...

  6. CCF 201803-3 URL映射

    CCF 201803-3  URL映射 试题编号: 201803-3 试题名称: URL映射 时间限制: 1.0s 内存限制: 256.0MB 问题描述: 问题描述 URL 映射是诸如 Django. ...

  7. planning algorithms chapter 2

    planning algorithms chapter 2 :Discrete Planning 离散可行规划导论 问题定义 在离散规划中,状态是"可数"的,有限的. 离散可行规划 ...

  8. 利用python爬虫爬取图片并且制作马赛克拼图

    想在妹子生日送妹子一张用零食(或者食物类好看的图片)拼成的马赛克拼图,因此探索了一番= =. 首先需要一个软件来制作马赛克拼图,这里使用Foto-Mosaik-Edda(网上也有在线制作的网站,但是我 ...

  9. (转) 中断处理程序&中断服务例程

             关于中断处理程序和中断服务例程ISR的区别及联系,之前一直搞混,今天抽时间将两者关系弄弄清楚.ok,下面进入主题.       首先中断处理程序(Interrupt Handler) ...

  10. 如何新建WebAPI,生成注释,TestAPI的项目

    一.新建WebAPI的项目 1. 在Web下,ASP.NET Web 应用程序,点击确定 2. 点击确定 3. 如图所示, 新建Controller 4 . 运行项目 二.注释 1. 在生成中,勾选x ...