😄
前端学习
  • 👋Welcome
  • 📖前端基础
    • HTML
      • 基础知识
      • 进阶知识
      • HTML5
    • CSS
      • 基础知识
      • 进阶知识
      • CSS 专题
        • CSS 选择器
        • CSS 布局
        • CSS 动画
        • CSS 画图
        • 响应式方案
        • CSS BEM 规范
        • CSS 案例
    • JavaScript
      • 基础知识
      • 进阶知识
      • 常用内置对象
        • Array 对象
        • String 对象
        • Number 对象
        • Boolean 对象
        • Math 对象
        • Date 对象
        • RegExp 对象
        • Object 对象
      • JS 专题
        • 数据类型
        • 原型链/继承
        • 对象赋值与拷贝
        • this 的指向
        • 异步操作
        • 模块化
        • 设计模式
    • 浏览器
      • 浏览器模型
      • 事件
      • 位置属性
      • Web 缓存
      • 本地存储
    • 综合内容
      • 前端跨域
      • 登录鉴权
      • 文件上传与下载
  • 🏗️前端框架
    • Vue.js
      • 基础知识
      • Vue 组件通信
      • Vuex 使用指南
      • Vue 动画
      • 静态网站框架 VuePress
    • React.js
      • 基础知识
      • 组件通信
  • 📦计算机基础/后端
    • 图解计算机网络
    • HTTP/HTTPS
    • TCP/UDP
    • Node.js
    • MongoDB
  • 🛠️开发工具
    • 版本控制工具-Git
      • git submodule
    • 构建工具-Webpack
    • 错误监控工具-Sentry
    • 单元测试工具-Jest
    • 包管理工具-NPM
    • 代码编辑器-VSCode
  • 🤔专题内容
    • 前端工程化
    • 代码规范
      • JavaScript 代码规范
      • CSS 代码规范
      • Vue 代码规范
      • Git Commit 规范
      • 代码规范配置
    • 网络安全与防御
    • 性能优化
    • 算法编程
    • 数据可视化
  • 🧑‍💻 面试相关
    • 面试知识总结
    • 面试问题总结
    • 面试常见编程
    • 面试资源汇总
  • 🍭其他
    • 项目经验❗️
    • 踩坑指南❗️
      • JavaScript 踩坑指南
      • CSS 踩坑指南
      • Vue 踩坑指南
    • 学习资源
    • 综合收藏夹
由 GitBook 提供支持
在本页
  • 1. 闭包 losure
  • 1.1 定义
  • 1.2 作用
  • 2. 事件循环机制
  • 2.1 宏任务
  • 2.2 微任务
  • 3. 垃圾回收机制
  • 4. 节流与防抖
  • 5. 模版字符串
  • 6. 函数柯里化

这有帮助吗?

  1. 前端基础
  2. JavaScript

进阶知识

1. 闭包 losure

1.1 定义

闭包为定义在一个函数内部的函数,其本质是将函数内部和函数外部连接起来的一座桥梁,通过闭包使外部能够访问函数内的局部变量,延伸了变量的作用范围。

// f2能够访问f1内的局部变量,因此返回f2就能在外部访问f1内的局部变量 - f2就是闭包
function f1() {
    var n = 999;
    function f2() {
        console.log(n);
    }
    return f2;
}
var result = f1();
result(); // 999

// 注意闭包返回f2与f2()的区别 - 带上括号返回的是函数调用,不带括号仅函数名返回的是函数
function f1() {
    var n = 999;
    function f2() {
        console.log(n);
    }
    return f2();
}
var result = f1(); // 999

1.2 作用

  1. 读取函数内部的变量

  2. 变量的值始终保持在内存中 - 保存变量现场

  3. 封装 - 信息隐藏

// Example1 
function f1() {
    var n = 999;
    nAdd = function () {
        n += 1
    }
    function f2() {
        alert(n);
    }
    return f2;
}

var result = f1();
result(); // 999
// nAdd前面没有使用var关键字,因此nAdd是一个全局变量,而不是局部变量,但是需要先调用一次f1()才会生成全局变量nAdd。
nAdd();
// f1是f2的父函数,而f2被赋给了一个全局变量,这导致f2始终在内存中,而f2的存在依赖于f1,因此f1也始终在内存中,不会在调用结束后,被垃圾回收机制(garbage collection)回收,因此f1的局部变量n也一直保存在内存中。
result(); // 1000
// Example2
// 未使用闭包,在实际中点击节点并不会显示对应的标号,而每个节点点击显示的都是nodes的长度值,因为i均来自for循环中i
var addHandlers = function(nodes){
  for(var i=0;i<nodes.length;i++){
    nodes[i].onclick() = function(){
      alert(i);
    }
  }
} 

// 使用闭包,每个节点生成点击事件都生成一个闭包,每个闭包都存储了当前的i值,因此在这个情况下能满足要求,在实际中点击节点会显示对应的标号。
var addHandlers = function(nodes){
  var helper = function(i){
    return function(){
      alert(i);
    }
  }
  for(var i=0;i<nodes.length;i++){
    nodes[i].onclick() = helper(i);
  }
}
// Example3 - 封装
// 外部不能访问内部的observerList,而通过返回的闭包则能够访问observerList进行操作
var observer = (function(){
  var observerList = [];
  return {
    add: function(obj){
      observerList.push(obj);
    },
    empty: function(){
      observerList = [];
    },
    get: function(){
      return observerList;
    }
  }
})();

2. 事件循环机制

JavaScript 是一门单线程语言,异步操作都是放到事件循环队列里面,每次宏任务执行完毕,先去微任务队列查找是否有微任务,如果有就先完成所有的微任务,如果没有微任务或完成所有微任务则从宏任务队列中继续执行宏任务。

2.1 宏任务

分类:script 整体代码, setTimeout, setInterval, requestAnimationFrame, I/O, UI rendering

  • 宏任务所处的队列就是宏任务队列

  • 第一个宏任务队列中只有一个任务,也就是script的代码

  • 宏任务队列可以有多个

  • 当宏任务队列中的任务全部执行完毕后可以查看是否有微任务队列,如果有就先执行微任务队列中的所有任务

2.2 微任务

分类:Promise.then(), await之后的代码, process.nextTick, Object.observe, MutationObserver

  • 微任务所处的队列就是微任务队列

  • 只有一个微任务队列

  • 在上一个宏任务队列执行完毕后,如果微任务队列中有任务就会去执行微任务队列中的所有任务

// 例题

console.log('----- start -----')
setTimeout(() => {
  console.log('setTimeout')
},0)
new Promise((resolve) => {
  for(let i = 0; i < 5; i++) {
    console.log(i)
  }
  resolve()
}).then(() => {
  console.log('promise实例成功回调执行')
})
console.log('----- end -----')

// ----- start -----
// 0
// 1
// 2
// 3
// 4
// ----- end -----
// promise实例成功回调执行
// setTimeout

3. 垃圾回收机制

4. 节流与防抖

5. 模版字符串

模版字符串的引入可以使字符串中直接嵌入变量,而不用使用'+'连接。注意模版字符串不是引号"",而是反引号````````。

// ES5
let a = 'hello <b>' + basket.count + '</b>';

// ES6 - 多行字符串所有的空格和缩进都会被保留在输出之中
let a = `hello <b> ${basket.count} </b>`;
let a = `
<ul>
  <li>first</li>
  <li>second</li>
</ul>
`;

模板字符串紧跟在一个函数名后面,该函数将被调用来处理这个模板字符串。

let message = SaferHTML`<p>${sender} has sent you a message.</p>`;

function SaferHTML(templateData) {
  let s = templateData[0];
  for (let i = 1; i < arguments.length; i++) {
    let arg = String(arguments[i]);

    // Escape special characters in the substitution.
    s += arg.replace(/&/g, "&amp;")
            .replace(/</g, "&lt;")
            .replace(/>/g, "&gt;");

    // Don't escape special characters in the template.
    s += templateData[i];
  }
  return s;
}

6. 函数柯里化

接受多个参数的函数变换成接受一个单一参数(最初函数的第一个参数)的函数,并且返回接受余下的参数而且返回结果的新函数。

// 普通的add函数
function add(x, y) {
    return x + y
}
​
// Currying后
function curryingAdd(x) {
    return function (y) {
        return x + y
    }
}
​
add(1, 2)           // 3
curryingAdd(1)(2)   // 3
上一页基础知识下一页常用内置对象

最后更新于3年前

这有帮助吗?

参考资料:

参考资料:

参考资料:

如果你对内容有任何疑问,欢迎提交 或

📖
谈谈 JS 垃圾回收机制
十分钟学会防抖和节流
《JavaScript 专题之函数柯里化》
js如何用一句代码实现函数的柯里化
❕issues
✉️ email