JavaScript忍者秘籍读书笔记

80 阅读9分钟

热身

无处不在的JavaScript

  1. JavaScript和其他语言的差异
  • 函数是一等公民。函数和其他对象共存。可以字面量创建函数、函数可以作为函数参数传递、函数可以赋值给变量、可以作为返回值从函数返回。
  • 函数闭包。在一个函数中用到了外部变量,则这个函数为一个闭包。(描述准确吗?)
  • 作用域,函数级别变量与全局变量:var。块级作用域:let、const。
  • 基于原型的面向对象————区别于基于类的面向对象
  1. JavaScript特性
  • 生成器
  • promise
  • 代理,控制对特定对象的访问
  • 高级数组
  • Map,字典集合。Set,不重复项目的集合
  • 正则表达式
  • 模块————项目管理 3、理解浏览器
  • DOM
  • 事件
  • 浏览器API 4、小结
  • 核心JavaScript机制:函数、函数闭包、原型。特性:生成器、Promise、代理、映射、集合(Map、Set)和模块。

运行时的页面构建过程

image.png

用户输入URL,浏览器将请求发送给服务器,服务器响应请求,浏览器接收请求并处理HTML、CSS和JavaScript并构建页面。页面构建完毕,浏览器进入事件处理直到用户关闭页面。

页面构建阶段

  1. 大致过程
  • 解析HTML
  • 构建DOM和执行JavaScript代码之间交替执行
  1. 执行JavaScript代码
  • 所有包含在脚本元素中的JavaScript代码由浏览器JavaScript引擎执。FireFox的Spidermonkey引擎。Chrome和Opera的V8引擎。
  1. 浏览器JavaScript引擎的全局变量window和window重要属性document,document为当前页面的DOM。
  2. JavaScript脚本可以更改DOM,但是要在更改的DOM构建之后,所以一般Script标签都放在最后。

事件处理

1、检查事件队列,有则事件处理,无则继续检查事件队列。(事件都是异步的) 2、注册事件处理器

  • on:缺点是一个事件只能有一个事件处理器,且可能会被覆盖。
  • addEventListener:一个可以注册多个事件处理器
  • on和addEventListener混用 可以混用

小结

  1. 浏览器接受的HTML代码用作创建DOM的蓝图,他是客户端Web应用结构的内部展示阶段。
  2. 我们使用JavaScript代码来动态地修改DOM以便给Web应用带来动态行为
  3. 客户端Web应用的执行分为两个阶段
  • 页面构建代码用于创建DOM的。而全局JavaScript代码是遇到script节点时执行。在这个执行过程中,JavaScript代码能够以任意程度改变当前的DOM,还能注册事件处理器————事件处理器是一种函数,当某个特定事件发生后被执行。注册分为on与addEventListener
  • 事件处理————同一时刻,只能处理多个事件中的一个,处理顺序是事件生成的顺序。事件处理阶段依赖事件队列,所有事件都以其出现的顺序存储在事件队列中。事件循环会检查事件队列的对头,如果检测到了一个事件,那么相应的事件处理器会被调用

3 初步函数

函数是第一类对象。函数与对象共存,函数也可以被视为其他人一类型的JavaScript对象。

3.1 函数式的不同点到底是什么

3.1.1 函数是第一类对象

  • 函数可以通过字面量创建(表达式右边)
  • 作为函数参数传递(回调函数)
  • 作为函数返回值返回(闭包场景)
  • 可以动态创建和分配属性(函数是第一类对象) 对象能做的任何一件事,函数也可以做。函数也是对象,唯一特殊之处在于它是可以调用的。

3.1.2 回调函数

建立的函数会被其他函数在稍后某个合适时间点再回来调用(回调是异步和同步之争)

3.2 函数作为对象的乐趣

函数能动态创建和添加属性带来的

3.2.1 存储函数:给函数动态添加属性,知道此函数是否被添加过。

image.png

3.2.2 自记忆函数:能够记住已计算的结果

image.png 优点:

  • 函数调用会寻找之前调用所得到的值,有性能收益。 缺点:
  • 任何类型的缓存必然为性能牺牲内存
  • 纯粹主义者认为缓存逻辑不应该和业务逻辑混合
  • 难做负载测试或估计算法复杂度

3.3 函数定义

  1. 函数声明和函数表达式
  2. 箭头函数
  3. 函数构造函数
  4. 生成器函数-ES6,能够让我们创建不同于普通函数的函数,在应用程序执行过程中,这种函数能够推出再重新进入,在这些再进入之间保留函数内变量的值。我们可以定义生成器版本的函数声明、函数表达式、函数构造函数。

3.3.1 函数声明和函数表达式

3.3.2 箭头函数

3.4 函数的实参和形参

剩余参数

function(first,...remainingNums)剩余参数只能放在函数最后一个参数

默认参数

function(a,b='b',c=a+''+b)

3.5 小结

  1. 把JavaScript看做函数式语言能书写复杂的代码
  2. 作为第一类对象,函数和JavaScript中其他对象一样,具有以下功能
  • 通过字面量创建
  • 作为函数参数传递
  • 作为函数返回值返回
  • 赋值给其他变量或方法
  • 动态创建和分配属性
  1. 回调函数是被代码随后”回来调用“的函数
  2. 函数具有属性,而且这些属性能够存储任何信息,可以利用这个特性来做很多事情:
  3. 可以在一个函数中存储另一个函数用于之后的引用和调用
  4. 可以用函数属性创建一个缓存(记忆),用于减少不必要的计算
  5. 不同类型的函数:声明函数、函数表达式、箭头函数、生成器函数
  6. 函数声明和函数表达式是两种最主要的函数类型。函数声明必须具有函数名,在代码中它必须作为一个独立语句的存在。函数表达式可以不必有函数名,但它必须作为其他语句的一部分。
  7. 箭头函数是JavaScript的一个新增特性,这个特性让我们可以用更简洁的方式来定义函数
  8. 形参是函数定义时列出的变量,而实参是函数调用时传递给函数的值
  9. 函数的形参列表和实参列表长度可以不同
  • 未赋值的形参为undefined
  • 传入的额外实参不会被赋给任何一个命名形参
  1. 剩余参数和默认参数

4 函数进阶 理解函数的调用

4.1 使用隐式函数参数

4.1.1 arguments 参数

  • 借此可以实现原生JavaScript并不能支持函数重载,并且可以实现函数参数数量可变的可变函数
  • 避免把arguments参数当成数组。他有length属性,可以通过下标访问到每一个元素。但是它并非JavaScript数组,数组的方法用在其上可能会报错
arguments作为函数参数的别名
  • 改变他既改变函数参数,改变函数参数既改变他
避免使用别名
  • 在严格模式下,arguments不再是别名

4.1.2 this参数:函数上下文

  • 函数定义方式函数定义位置函数调用环境有关

4.2 函数调用

  • 直接调用
  • 作为对象方法
  • 作为构造函数
  • apply/call
  • 作为事件回掉函数,this一般会指向触发事件的函数(不算调用,算影响调用)

4.2.1 直接调用

  • 严格模式下undefine
  • 非严格模式下window
        let a = function () {
            return this
        }
        let b = function () {
            let c = function(){
                return this
            }
            return c()
        }
        console.log(a() === window)//true
        console.log(b() === window)//true

4.2.2 作为方法调用

  • 当函数作为某个对象的方法被调用时,该对象就会成为函数的上下文,并且在函数内部可以通过参数访问(this)。
  • 方法内部可以通过this引用该方法的宿主对象。

4.2.3 作为构造函数被调用

  • 关键词new

  • 过程

    • 创建一个新对象
    • 该新对象作为this参数传递给构造函数,变成构造函数的上下文
    • 新对象作为new运算符的返回值
  • 关键点

    • 创建并初始化先对象
    • 新对象作为构造函数的返回值返回
  • 当函数有自身返回值,并且new时

    • 构造函数返回的是引用类型,则丢弃新创建的对象,返回构造函数对象
    • 构造函数返回的是非引用类型,则返回new运算符的返回值
  • 注意点

image.png

4.2.4 使用apply和call

  • 案例
    <button id="test">点击</button>
    <script>
        function Button(){
            this.clicked=false
            this.click = function(){
                this.clicked=true
            }
        }
        let button = new Button()
        let elem = document.getElementById('test')
        elem.addEventListener('click',button.click)
    </script>
    //点击之后,button.clicked=false elem.clicked=true

通常情况下,事件回调函数的上下文就是触发事件的对象在此例子中,浏览器的事件处理系统吧调用的上下文定义为事件触发的目标元素,因此上下文为元素,而非button对象

    <button id="test">点击</button>
    <script>
        function Button(){
            this.clicked=false
            this.click = function(){
                this.clicked=true
            }
        }
        let button = new Button()
        let elem = document.getElementById('test')
        elem.addEventListener('click',button.click.bind(button))
    </script>
    //用call或者apply是相当于立即执行了函数
  • apply和call的区别 apply参数为数组 call参数不是数组

4.3 解决函数上下文问题

  • 箭头函数,与定义的上下文绑定
  • apply,call执行绑定上下文
  • bind

4.3.1 使用箭头函数绕过函数上下文

    <button id="test">点击</button>
    <script>
        function Button(){
            this.clicked=false
            this.click = ()=>{
                this.clicked=true
                //这里的this是如果是由new之后的对象调用,this便会指向对象
            }
        }
        let btn = {
            clicked:false,
            click : ()=>{
                this.clicked=true
                //这里的this是window
            }
        }
        let button = new Button()
        let elem = document.getElementById('test')
        elem.addEventListener('click',button.click)
        //这里的button.click是箭头函数,this是指向button
    </script>

调用箭头函数,不会隐式传入this参数,而是从定义时的函数继承上下文。bind改变不了箭头函数

4.3.2 bind

  • bind不会修改原始函数而是创建一个全新的函数

4.4 小结

  • 当调用函数的时候,除了传入在函数定义中显示声明的参数以外,同时还传入两个隐式参数:arguments和this
    • arguments参数是传入函数的所有参数的集合。(不是数组)具有length属性,表示传入的参数的个数,通过arguments参数还可获取那些与函数形参不匹配的参数。在非严格迷失下,arguments对象是函数参数的别名,修改arguments对象会修改函数的实参,可以通过严格模式避免修改函数的实参。
    • this表示函数的上下文,即与函数调用相关联的对象。函数的定义方式和调用方式决定了this的取值。
  • 函数的调用方式有4种
    • 直接调用。一般this为window
    • 作为方法调用。this为调用方法对象
    • 作为构造函数。一般为new返回的对象
    • apply、call 指定this
  • 箭头函数没有单独的this值,this在箭头函数创建时确定(bind,apply,call不起作用的原因)
  • 所有函数均可使用bind方法,创建新函数,并绑定到bind方法传入的参数上。被绑定的函数与原始函数具有一致的行为。