资讯专栏INFORMATION COLUMN

JavaScript面向对象~ 作用域和闭包

WilsonLiu95 / 955人阅读

摘要:大名鼎鼎的作用域和闭包,面试经常会问到。声明理解闭包,先理解函数的执行过程。闭包的基本结构因为闭包不允许外界直接访问,所以只能间接访问函数内部的数据,获得函数内部数据的使用权。

大名鼎鼎的作用域和闭包,面试经常会问到。闭包(closure)是Javascript语言的一个难点,也是它的特色。

声明

理解闭包,先理解函数的执行过程。

代码在执行的过程中会有一个预解析的过程,也就是在代码的执行过程中,会先将代码读取到内存中,检查其是否有错误,然后将所有声明在此进行标记,让js解析器知道有这样的一个名字,后面使用时便不会出现未定义的错误,这个标记的过程就是提升。

变量的声明
var num;没有与之对应的数据,仅仅是让js解析器知道,你定义了一个num的变量。

函数的声明
function foo(){};一个独立的结构,没有任何语句。首先是将函数名进行提升,让js解析器知道有一个foo函数,接着是将函数名与函数体连接起来,注意这里并不执行函数体。

代码演示:

var num = 10;
function foo(){
  console.log(num);
}
foo();

预解析的过程(变量提升,函数提升):

var num;
function foo(){
  console.log(num)
}
num = 10;
foo();

代码执行时,首先会执行 num = 10; 然后执行foo(),进行函数体,打印出num的值。此时的num访问到的是全局中定义的num,所以num的值为10.

作用域

以上代码涉及到作用域的问题,所谓的域,表示的是范围,所以作用域表示的是作用范围,也就是一个名字在什么地方可以使用,在什么地方不可使用。

1、词法作用域

在js中,采用的是词法作用域,词法作用域是指在编写代码的过程中体现出来的作用范围,一旦代码写好了,不用执行,作用范围就确定好了。

Javascript的作用域无非就是两种:全局变量和局部变量。

2、词法作用域的规则

函数允许访问函数外的数据

整个代码结构中只有函数可限定作用域

作用域规则首先使用提升规则分析

若当前作用域中有名字了,就不考虑外面的名字

3、作用域链

只有函数可以构成作用域结构。只要存在代码,就至少有一个作用域,即全局作用域。凡是代码有函数,那么这个函数就构成一个作用域,如果函数中还有函数,那么在这个作用域中就又诞生一个作用域,那么将这样的所有作用域列出来,就可以有一个:函数内指向函数外的链式结构。

作用域链变量访问规则:看变量在当前作用域中,是否有变量的定义与赋值,如果有,则直接使用;如果没有,则到外面的作用域中查看,如果有,则停止查找,使用外面一层作用域中定义的变量或值,如果没有,则继续往外查找,直到最外层的全局,如果全局也没有定义,则会报错: xx is not defined。

闭包 什么是闭包

闭包,是一个具有封闭功能与包裹功能的一个结构或空间。在js中,函数可以构成闭包。因为函数在当前的作用域中是一个封闭的结构,具有封闭性;同时根据作用域规则,只允许函数内部访问外部的数据,而外部无法访问函数内部的数据,即函数具有封闭的对外不公开的特性,就像把一个东西包裹起来一样,因此函数可以构成闭包。

有点难理解,简单来说,就是能够读取其他函数内部变量的函数,再简洁一点就是:定义在一个函数内部的函数。

闭包的基本结构

因为闭包不允许外界直接访问,所以只能间接访问函数内部的数据,获得函数内部数据的使用权。

1、写一个函数,函数内定义一个新函数,返回新函数,用新函数获得函数内部的数据
function foo(){
  var num = 123;
  function func(){
    return num;
  }
  return func;
}
var f = foo();
var res1 = f();
var res2 = f(); 
// 此时,foo只调用了一次,不会再内存中重新创建一个函数,而通过f,可以访问并获取num的值,那么调用f,即可获得一样的num值

改良:
function foo(){
  var num = 123;
  return function(){
    return num;
  }
}
var f = foo();
var res1 = f();
var res2 = f();

再改良:
var f = (function foo(){
  var num = 123;
  return function (){
    return num;
  }
})();
var res1 = f();
var res2 = f();
2、写一个函数,函数内定义一个对象,对象绑定一个或多个函数(方法),返回对象,利用对象的方法访问函数内部的数据
function func(){
  var num1 = Math.random();
  var num2 = Math.random();
  return {
    num1: function(){
      return num1;
    },
    num2: function(){
      return num2;
    }
  }
}
var p = func();
console.log(p.num1());
console.log(p.num1());// 这两个访问到的是同一个随机数
闭包的基本用法

如上面代码演示的那样,闭包可以通过返回函数来间接访问到函数内的数据,这样,闭包可以实现具有私有访问空间的函数,保护私有的数据。另一方面,可以帮助其他对象读取到函数内部的变量

闭包的性能问题

函数定义的变量会在函数执行结束后自动回收,但是因为闭包结构引出的数据经常会被外界所引用,这些数据将不会被回收,因此过多的闭包会消耗内存资源,影响性能。所以要谨慎使用闭包,可以在使用闭包时,如果不再使用某些变量了,一定要赋值一个null。

在ES6中,提出来对象代理概念,在代理层操作数据而不是直接操作原数据。

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/100263.html

相关文章

  • 这一次,我们换种姿势学习 javascript

    摘要:操作符或调用函数时传入参数的操作都会导致关联作用域的赋值操作。此外可以使用和来设置对象及其属性的不可变性级别。忽视这一点会导致许多问题。使用调用函数时会把新对象的属性关联到其他对象。 前言 《你不知道的 javascript》是一个前端学习必读的系列,让不求甚解的JavaScript开发者迎难而上,深入语言内部,弄清楚JavaScript每一个零部件的用途。本书介绍了该系列的两个主题:...

    zone 评论0 收藏0
  • 20170917 前端开发周报:JavaScript函数式编程、作用域和闭包

    摘要:用函数式编程对进行断舍离当从业的老司机学会函数式编程时,他扔掉了的特性,也不用面向对象了,最后发现了真爱啊作用域和闭包作用域和闭包在里非常重要。旨在帮助非函数式编程的同学,能快速切入到函数式编程的理念。 1、用函数式编程对JavaScript进行断舍离 当从业20的JavaScript老司机学会函数式编程时,他扔掉了90%的特性,也不用面向对象了,最后发现了真爱啊!!! https:/...

    tomener 评论0 收藏0
  • 20170917 前端开发周报:JavaScript函数式编程、作用域和闭包

    摘要:用函数式编程对进行断舍离当从业的老司机学会函数式编程时,他扔掉了的特性,也不用面向对象了,最后发现了真爱啊作用域和闭包作用域和闭包在里非常重要。旨在帮助非函数式编程的同学,能快速切入到函数式编程的理念。 1、用函数式编程对JavaScript进行断舍离 当从业20的JavaScript老司机学会函数式编程时,他扔掉了90%的特性,也不用面向对象了,最后发现了真爱啊!!! https:/...

    cyixlq 评论0 收藏0
  • 20170917 前端开发周报:JavaScript函数式编程、作用域和闭包

    摘要:用函数式编程对进行断舍离当从业的老司机学会函数式编程时,他扔掉了的特性,也不用面向对象了,最后发现了真爱啊作用域和闭包作用域和闭包在里非常重要。旨在帮助非函数式编程的同学,能快速切入到函数式编程的理念。 1、用函数式编程对JavaScript进行断舍离 当从业20的JavaScript老司机学会函数式编程时,他扔掉了90%的特性,也不用面向对象了,最后发现了真爱啊!!! https:/...

    lentoo 评论0 收藏0
  • 深入javascript——作用域和闭包

    摘要:注意由于闭包会额外的附带函数的作用域内部匿名函数携带外部函数的作用域,因此,闭包会比其它函数多占用些内存空间,过度的使用可能会导致内存占用的增加。 作用域和作用域链是javascript中非常重要的特性,对于他们的理解直接关系到对于整个javascript体系的理解,而闭包又是对作用域的延伸,也是在实际开发中经常使用的一个特性,实际上,不仅仅是javascript,在很多语言中都...

    oogh 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<