一、闭包

1 . 概念:闭包就是能够读取其他函数内部变量的函数。在JS中,只有函数内部的子函数才能读取局部变量,因此可以把闭包简单理解为”定义在一个函数内部的函数”。

2 . 闭包的特点

1)可以读取函数内部的变量。

2)让这些变量的值始终保存在内存中。

3 . 闭包的原理

理解闭包,首先必须理解JS变量的作用域。变量的作用域无非就是两种(es5):全局变量和局部变量。

JS语言的特殊之处,就在于函数内部可以直接读取全局变量。另一方面,函数外部自然无法读取函数内的局部变量。

注意:

1)函数内部声明变量的时候,一定要使用var声明。如果不用的话,你实际上声明了一个全局变量。

2)局部变量的作用域,在函数定义的时候就已经确定下来了。

出于各种原因,我们有时候需要得到函数内部的局部变量。但是正常情况下这是办不到的。只有变通一下才能实现,那就是在函数内部再定义一个函数。外部变量不能访问内部变量,内部变量却能访问外部变量,这正是因为JS特有的”链式作用域”结构(chain scope),子对象会一级一级地向上寻找所有父对象的变量。所以父对象的所有变量,对子对象都是可见的,反之则不成立。我们只需要把子函数返回出来,我们就可以在外部读取内部变量了。

4 . 闭包的应用场景

1)函数作为返回值。

  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8">
  5. <title>闭包</title>
  6. </head>
  7. <body>
  8. <script>
  9. function f1() {
  10. var n = ;
  11. nAdd = function () {
  12. n += ;
  13. }
  14. function f2() {
  15. console.log(n)
  16. }
  17. return f2;
  18. }
  19. var result = f1();
  20. console.log("result的第一次执行")
  21. result();//
  22. console.log("nAdd的执行")
  23. nAdd();//无输出
  24. console.log("result的第二次执行")
  25. result();//
  26. </script>
  27. </body>
  28. </html>

  2)函数作为参数被传递。

  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8">
  5. <title>闭包</title>
  6. </head>
  7. <body>
  8. <script>
  9. function fun(n, o) {
  10. console.log(o);
  11. return {
  12. fun: function (m) {
  13. return fun(m, n);
  14. }
  15. };
  16. }
  17. var a = fun(); //undefined
  18. // 执行完并未销毁保存在内存中
  19. a.fun(); //
  20. a.fun(); //
  21. a.fun(); //
  22.  
  23. fun().fun().fun().fun();
  24. //undefined、0、1、2
  25. var a = fun().fun();
  26. //undefined、0
  27. a.fun();
  28. //undefined、1
  29. a.fun();
  30. //undefined、1
  31. </script>
  32. </body>
  33. </html>

5 . 使用闭包注意点

1)由于闭包会使得函数中的变量都被保存在内存中,内存消耗很大,所以不能滥用闭包。否则会造成网页性能问题,在IE中可能导致内存泄漏。解决方法就是在函数退出之前,将不使用的局部变量删除(值置为null,垃圾回收机制就会处理)。

2)闭包会在父函数外部,改变父函数内部变量的值。所以不要随便改变父函数内部变量的值。

6 . demo通过js闭包实现鼠标滑过隔行换色的效果

  1. <!doctype html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8">
  5. <title>闭包实现各行换色</title>
  6. <style type="text/css">
  7. *{
  8. margin: ;
  9. padding: ;
  10. }
  11. h3{
  12. text-align: center;
  13. font-size: 24px;
  14. line-height: 60px;
  15. }
  16. .newList{
  17. width: %;
  18. margin: auto;
  19. list-style: none;
  20. }
  21. .newList li{
  22. text-indent: 24px;
  23. line-height: 50px;
  24. font-size: 16px;
  25. border-top: 1px dashed #eeeeee;
  26. }
  27. </style>
  28. </head>
  29. <body>
  30. <h3>新闻列表</h3>
  31. <ul id="newList" class="newList">
  32. <li>这是第1条新闻</li>
  33. <li>这是第2条新闻</li>
  34. <li>这是第3条新闻</li>
  35. <li>这是第4条新闻</li>
  36. <li>这是第5条新闻</li>
  37. <li>这是第6条新闻</li>
  38. <li>这是第7条新闻</li>
  39. <li>这是第8条新闻</li>
  40. <li>这是第9条新闻</li>
  41. </ul>
  42. </body>
  43. <script type="text/javascript">
  44. var oNewList=document.getElementById('newList');
  45. var oNewListArr=Array.from(oNewList.children);
  46. oNewListArr.forEach(function (v,i) {
  47. // 隔行换色
  48. if(i % === ) {
  49. oNewListArr[i].style.background = '#f3f3f3';
  50. };
  51. //鼠标滑过改变背景色
  52. v.onmouseover=function () {
  53. this.style.background="#87ceeb";
  54. };
  55. //鼠标滑过恢复原背景色
  56. (function (m){
  57. oNewListArr[m].onmouseout=function () {
  58. if(m % === ) {
  59. oNewListArr[i].style.background = '#f3f3f3';
  60. }
  61. else{
  62. oNewListArr[i].style.background = '#ffffff';
  63. }
  64. }
  65. })(i);
  66. })
  67. </script>
  68. </html>

二、构造函数的继承

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

详解new的执行过程:

  1. 在内存生成一个实例对象obj。
  2. 指定实例对象的__proto__到构造函数的prototype。
  3. 运行构造函数,相当于运行fn.call(obj)。
  4. 检查返回值,如果返回值为基本数据类型,则无视该返回值,而将生成的对象返回。如果为引用类型,则将该返回值返回。

构造函数很好用,但是存在浪费内存的问题。

JS规定,每一个构造函数都有一个prototype属性,指向另一个对象。此对象的所有属性和方法,都会被构造函数的实例继承。

  1. <!doctype html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8">
  5. <title>构造函数</title>
  6. </head>
  7. <body>
  8. </body>
  9. <script type="text/javascript">
  10. //构造函数的命名首字母一般大写
  11. function Car(carlogo) {
  12. this.carLogo = carlogo;
  13. this.whistle = function () {
  14. console.log("正在鸣笛......")
  15. }
  16. }
  17. Car.prototype.run = function() {
  18. console.log("正在行走......")
  19. };
  20. var bmw=new Car("BMW");
  21. var audi=new Car("Audi");
  22. console.log("构造函数创建的实例:")
  23. console.log(bmw === audi)
  24. console.log(bmw,audi)
  25. console.log("构造函数whisle属性:")
  26. console.log(bmw.whisle === audi.whisle)
  27. console.log("原型run方法:");
  28. console.log(bmw.run === audi.run);
  29.  
  30. </script>
  31. </html>

  • instanceof运算符:判断对象是不是构造函数的实例,是则true,否则false。
  1. console.log(bmw instanceof Car)//true
  2. console.log(bmw instanceof Array)//false
  • isPrototypeOf:判断prototype对象和某个实例之间的关系。
  1. console.log(Car.prototype.isPrototypeOf(bmw));//true
  2. console.log(Array.prototype.isPrototypeOf(bmw));//false
  • hasOwnProperty:每个实例对象都有一个hasOwnProperty方法,用来判断某一个属性到底是本地属性,还是继承自prototype对象的属性。
  1. bmw.hasOwnProperty('carlogo');//true
  2. bmw.hasOwnProperty('run');//false
  • in运算符:in运算符可以用来判断,某个实例是否含有某个属性,不管是不是本地属性。
  1. console.log('run' in bmw);//true

注:

详解instanceof 运算符。         // 会沿着原型链查找。

详解hasOwnProperty方法。 // 不会沿着原型链查找。

详解isPrototypeOf方法。   // 会沿着原型链查找。

详解in运算符。                        // 会沿着原型链查找。


三、call/apply继承

call和apply都是为了改变某个函数运行时的context即上下文而存在的,即改变函数内部this的指向。

Fn.call(obj, arg1, arg2 [, argN]);

fn,.apply(obj, [arg1, arg2,…, argN]);

作用相同,apply以数组的形式传参,call是以列表的形式。

  1. <!doctype html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8">
  5. <title>构造函数</title>
  6. </head>
  7. <body>
  8. </body>
  9. <script type="text/javascript">
  10. //构造函数
  11. function Person(name) {
  12. this.name = name;
  13. }
  14.  
  15. var xiaoJun = {
  16. name: '小军'
  17. };
  18.  
  19. var xiaoHua = {
  20. name: '小花',
  21. sing: function (where, music) {
  22. console.log(this.name + '正在' + where + '唱' + music);
  23. }
  24. };
  25.  
  26. xiaoHua.sing('马路上', '葫芦娃');
  27. //列表形式传参
  28. xiaoHua.sing.call(xiaoJun, '音乐厅', '屋顶');
  29. //数组方式传参
  30. xiaoHua.sing.apply(xiaoJun, ['KTV', '我们不一样']);
  31. //列表形式传参,且与call、apply的执行方式不同,需要调用
  32. var func = xiaoHua.sing.bind(xiaoJun);
  33. func('教室', '荡起双桨');
  34.  
  35. </script>
  36. </html>

apply和call实现继承:

将父对象的构造函数绑定在子对象上,即在子对象构造函数中加一行:

  1. <!doctype html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8">
  5. <title>继承</title>
  6. </head>
  7. <body>
  8. </body>
  9. <script type="text/javascript">
  10. function Animal () {
  11. this.eyes = ;
  12. }
  13. function Dog(name) {
  14. Animal.call(this);
  15. this.name = name;
  16. }
  17. var oWangCai = new Dog('旺财');
  18. console.log(oWangCai);
  19.  
  20. </script>
  21. </html>

四、prototype的概念

  1. 一切引用类型都是对象。
  2. 对象是属性的集合。
  3. 对象都是通过构造函数创建的。
  4. 每个函数都有一个prototype属性,即原型。对象都有__proto__属性,可以成为隐式原型。这个__proto__属性是一个隐藏的属性,JS并不希望开发者能够用到这个属性,有的低版本浏览器甚至不支持这个属性值。
  5. 每个对象的__proto__属性指向创建该对象的函数的prototype。
  6. Object.prototype.__proto__指向null。

原型链:

访问一个对象的属性时,先在本地属性中查找,如果没有,再沿着__proto__这条链向上找,这就是原型链。

constructor属性:函数的prototype有一个constructor属性,该属性指向了函数本身。对象没有constructor属性,它沿着原型链使用的是对象的构造函数的constructor属性。

五、this的使用情况

1:构造函数(在new的情况下)

this指向的是新构建出来的对象。

2:函数作为对象的一个属性

函数中的this指向的是该对象。

3:函数call或者apply

当函数被call或者apply调用时,this的值就取传入对象的值。

4:全局函数 & 普通函数

全局函数或者普通函数中,this指向的是window。

5:在prototype原型对象中,this指向的是调用构造函数实例出来的对象。

注:this关键字的值在函数运行的时候才会被指定。

六、原型链的继承:

将一个构造函数的原型指向另一个构造函数的实例对象来实现继承。

  1. <!doctype html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8">
  5. <title>原型链继承</title>
  6. </head>
  7. <body>
  8. </body>
  9. <script type="text/javascript">
  10. function Person() {
  11. this.age = ;
  12. }
  13.  
  14. function Man() {
  15. this.beard = '胡子';
  16. }
  17.  
  18. var person = new Person();
  19. //改变man的原型指向
  20. Man.prototype = person;
  21. var man1 = new Man();
  22. console.log(man1.beard);
  23. console.log(man1.age);
  24.  
  25. </script>
  26. </html>

原型链的继承必须将Man的prototype.constructor指向更改过来,否则它将会指向People,发生原型混乱。也就是下一点讲述的混合继承


七、混合继承:

原型链与构造函数的优点,组合而成的一个模式,即原型链继承方法,而在构造函数继承属性

  1. <!doctype html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8">
  5. <title>混合继承</title>
  6. </head>
  7. <body>
  8. </body>
  9. <script type="text/javascript">
  10. function Person() {
  11. this.age = ;
  12. }
  13.  
  14. Person.prototype.introduce = function () {
  15. console.log('我有' + this.beard + ';今年' + this.age + '岁');
  16. }
  17.  
  18. function Man() {
  19. Person.call(this);
  20. this.beard = '胡子';
  21. }
  22.  
  23. var person = new Person();
  24. console.log("prototype.constructor指向未改:")
  25. Man.prototype = person;//改变函数原型指向
  26. person.age = ;
  27. var man1 = new Man();
  28. var man2 = new Man();
  29. console.log(man1.age);
  30. console.log(man2.age);
  31.  
  32. console.log("prototype.constructor指向改变:")
  33. Man.prototype.constructor = Man;//改变构造函数指向
  34. var man3 = new Man();
  35. var man4 = new Man();
  36. man3.age = ;
  37. console.log(man3);
  38. console.log(man4);
  39. man3.introduce();
  40. man4.introduce();
  41.  
  42. </script>
  43. </html>

从零开始学习前端JAVASCRIPT — 12、JavaScript面向对象编程的更多相关文章

  1. 从零开始学习前端开发 — 12、CSS3弹性布局

    一.分栏布局 1.设置栏数column-count:数值; 2.设置每栏的宽度column-width:数值+单位; 注:当设置了column-width,column-count会失效,二者设置其一 ...

  2. 从零开始学习前端JAVASCRIPT — 11、Ajax-前后端异步交互以及Promise-异步编程的改进

    (注:本章讲解涉及部分后端知识,将以php提供数据的方式进行相应的demo实现) 1:ajax的概念 全称:Asynchronous Javascript And Xml AJAX不是一种新的编程语言 ...

  3. 从零开始学习前端JAVASCRIPT — 1、JavaScript基础

    1:定义:javascript是一种弱类型.动态类型.解释型的脚本语言. 弱类型:类型检查不严格,偏向于容忍隐式类型转换. 强类型:类型检查严格,偏向于不容忍隐式类型转换. 动态类型:运行的时候执行类 ...

  4. 从零开始学习前端JAVASCRIPT — 10、JavaScript基础ES6(ECMAScript6.0)

    ECMAScript 6.0(简称ES6)是JavaScript语言的下一代标准,已经在2015年6月正式发布了.它的目标,是使得JavaScript语言可以用来编写复杂的大型应用程序,成为企业级开发 ...

  5. 深入理解javascript中实现面向对象编程方法

    介绍Javascript中面向对象编程思想之前,需要对以下几个概念有了解: 1. 浅拷贝和深拷贝:程序在运行过程中使用的变量有在栈上的变量和在堆上的变量,在对象或者变量的赋值操作过程中,大多数情况先是 ...

  6. javaScript设计模式之面向对象编程(object-oriented programming,OOP)(二)

    接上一篇 面向对象编程的理解? 答:面向对象编程,就是将你的需求抽象成一个对象,然后针对这个对象分析其特征(属性)与动作(方法).这个对象我们称之为类.面向对象编程思想其中一个特点就是封装,就是把你需 ...

  7. javaScript设计模式之面向对象编程(object-oriented programming,OOP)(一)

    面试的时候,总会被问到,你对javascript面向对象的理解? 面向对象编程(object-oriented programming,OOP)是一种程序设计范型.它讲对象作为程序的设计基本单元,讲程 ...

  8. JavaScript中的面向对象编程,详解原型对象及prototype,constructor,proto,内含面向对象编程详细案例(烟花案例)

    面向对象编程:   面向:以什么为主,基于什么模式 对象:由键值对组成,可以用来描述事物,存储数据的一种数据格式 编程:使用代码解决需求   面向过程编程:         按照我们分析好的步骤,按步 ...

  9. C#学习笔记(六)——面向对象编程简介

    一.面向对象编程的含义 *   是一种模块化编程方法,使代码的重用性大大的增加. *   oop技术使得项目的设计阶段需要的精力大大的增加,但是一旦对某种类型的数据表达方式达成一致,这种表达方式就可以 ...

  10. python学习第十四天 -面向对象编程基础

    python也是支持面向对象编程的.这一章节主要讲一些python面向对象编程的一些基础. 什么是面向对象的编程? 1.面向对象编程是一种程序设计范式 2.把程序看做不同对象的相互调用 3.对现实世界 ...

随机推荐

  1. CentOS 通过yum来升级php到php5.6

    在文章中,我们将展示在centOS系统下如果将php升级到5.6,之前通过yum来安装lamp环境,直接升级的话,提示没有更新包,也就是说默认情况下php5.3.3是最新 1.查看已经安装的php版本 ...

  2. mac对比class文件

    下载反编译工具 wget https://varaneckas.com/jad/jad158g.mac.intel.zip 设置Beyond Compare 填写编译工具路径

  3. nagios 数据更新不及时的问题

    配置nagios的时候发现一个问题,就是改变了某个主机或者服务的描述之后,在主页信息总是更新很慢,而且告警信息还是老的信息,重启多次 nagios甚至重启主机都没有解决,其实这些都是由于nagios每 ...

  4. 02-Go语言数据类型与变量

    Go基本类型 布尔型: bool - 长度: 1字节 - 取值范围: true,false - 注意事项: 不可以用数字代表true或false 整型: int/uint - 根据运行平台可能为32或 ...

  5. Macaca拓展自己控件的方法

    https://github.com/macacajs/wd.py/blob/3bc4334bcb68733cb230b59d6164110053fd1c16/tests/macaca/test_ut ...

  6. ABP官方文档翻译 3.5 规约

    规约 介绍 示例 创建规范类 使用仓储规约 组合规约 讨论 什么时候使用? 什么时候不使用? 介绍 规约模式是一种特别的软件设计模式,通过使用布尔逻辑将业务规则链接起来重新调配业务规则.(维基百科). ...

  7. Java 常用List集合使用场景分析

    Java 常用List集合使用场景分析 过年前的最后一篇,本章通过介绍ArrayList,LinkedList,Vector,CopyOnWriteArrayList 底层实现原理和四个集合的区别.让 ...

  8. ext4 关闭延迟分配

    ext4的延迟分配特性(delalloc)保证文件在磁盘中的连续,提高文件的读写性能,但是却增加了丢数据的概率. Hadoop和HBase中建议将延迟分配特性关闭. 可以使用下面的方法关闭延迟分配 1 ...

  9. Java字节码基础[转]

    原文链接:http://it.deepinmind.com/jvm/2014/05/24/mastering-java-bytecode.html Java是一门设计为运行于虚拟机之上的编程语言,因此 ...

  10. BZOJ 2916: [Poi1997]Monochromatic Triangles [计数]

    题意:空间中有n个点,任意3个点不共线.每两个点用红线或者蓝线连接,如果一个三角形的三边颜色相同,那么称为同色三角形.给你一组数据,计算同色三角形的总数. 考虑补集,异色三角形 每个点的边红色和蓝色两 ...