zoukankan      html  css  js  c++  java
  • Javascript闭包简单理解


    提到闭包,想必大家都早有耳闻,下面说下我的简单理解。
    说实话平时工作中实际手动写闭包的场景并不多,但是项目中用到的第三方框架和组件或多或少用到了闭包。
    所以,了解闭包是非常必要的。呵呵...


    一、什么是闭包
    简而言之,就是能够读取其他函数内部变量的函数。
    由于JS变量作用域的特性,外部不能访问内部变量,内部可以外部变量。


    二、使用场景
    1. 实现私有成员。
    2. 保护命名空间,避免污染全局变量。
    3. 缓存变量。
    4. 代码复用

    先看一个封装的例子:

    1. var person = function () {
    2.     // 变量作用域为函数内部,外部无法访问
    3.     var name = "default";
    4.     return {
    5.         getName: function () {
    6.             return name;
    7.         },
    8.         setName: function (newName) {
    9.             name = newName;
    10.         }
    11.     }
    12. }();
    13. console.log(person.name); // 直接访问,结果为:undefined
    14. console.log(person.getName()); // 结果为:default
    15. console.log(person.getName()); // 结果为:langjt
    复制代码



    再看循环中常用闭包解决引用外部变量问题:

    1. var aLi = document.getElementsByTagName('li');
    2. for (var i=0, len=aLi.length; i<len; i++) {
    3.    aLi[i].onclick = function() {
    4.      alert(i); // 无论点击哪个<li>元素,弹出的值都为len,表明这里的i和在for之后打印i的值是一样的。
    5.    };
    6. }
    复制代码



    使用闭包后:

    1. var aLi = document.getElementsByTagName('li');
    2. for (var i=0, len=aLi.length; i<len; i++) {
    3.   aLi[i].onclick = (function(i) {
    4.     return function() {
    5.       alert(i); // 此时点击<li>元素,就会弹出对应的下标了。
    6.     }
    7.   })(i);
    8. }
    复制代码



    三、注意事项
    1. 内存泄漏
    由于闭包会使得函数中的变量都被保存在内存中,内存消耗很大,所以不能滥用闭包,否则会造成网页的性能问题。
    比如:

    1. function foo() {
    2.    var oDiv = document.getElementById(‘J_DIV’);
    3.    var id = oDiv.id;
    4.    oDiv.onclick = function() {
    5.      // alert(oDiv.id); 这里存在循环引用,IE低版本页面关闭后oDiv仍在内存中。所以尽可能缓存基本类型而不是对象。
    6.      alert(id);
    7.    };
    8.    oDiv = null;
    9. }
    复制代码



    2. 变量命名
    如果内部函数的变量和外部函数的变量名相同时,那么内部函数再也无法指向外部函数那个同名的变量。
    比如:

    1. function foo(num) {
    2.   return function(num) {
    3.     console.log(num); 
    4.   }
    5. }
    6. var f = new foo(9);
    7. f(); // undefined
    复制代码



    其实上面的用法,专业术语叫函数柯里化(Currying),就是把接受多个参数的函数变换成接受一个单一参数(最初函数的第一个参数)的函数,并且返回接受余下的参数而且返回结果的新函数的技术。本质上也利用了闭包可以缓存的特性,比如:

    1. var adder = function(num) {
    2.     return function(y) {
    3.         return num+y;
    4.     };
    5. };
    6. var inc = adder(1);
    7. var dec = adder(-1);
    8. //inc, dec现在是两个新的函数,作用是将传入的参数值 (+/‐)1
    9. alert(inc(99));//100
    10. alert(dec(101));//100 
    11. alert(adder(100)(2));//102 
    12. alert(adder(2)(100));//102
    复制代码



    再比如阿里玉伯的seaJS源码中:

    1. /**
    2. * util-lang.js - The minimal language enhancement
    3. */
    4. function isType(type) {
    5.   return function(obj) {
    6.     return {}.toString.call(obj) == "[object " + type + "]"
    7.   }
    8. }
    9. var isObject = isType("Object");
    10. var isString = isType("String");
    复制代码
  • 相关阅读:
    java后端解决请求跨域
    在IDEA中找不到Mapper报错
    ES6拼接数组与小程序本地存储
    小程序云开发实现微信发说说
    SQLServer的操作以及一些概念
    数据依赖(决定),码,范式,规范化与反规范化
    Git的使用上传与下载github
    JS中Map和ForEach的区别
    进入React的世界
    Node的重要性
  • 原文地址:https://www.cnblogs.com/daqianduan/p/4428698.html
Copyright © 2011-2022 走看看