JavaScript入门教程笔记
| 2023-1-28
0  |  阅读时长 0 分钟
日期
Aug 20, 2022 → Nov 7, 2022
Tags
笔记
前端
JavaScript

JavaScript概览

  • 轻量级脚本语言
  • 嵌入式语言,可以嵌入宿主环境(host)
    • 浏览器、Node项目
    • 宿主环境会提供额外API供JavaScript调用
    • 需要调用宿主环境提供的底层API,可以解释运行也可以编译运行(JIT)
  • 编程风格是函数式编程和面向对象编程的一种混合体
  • 支持函数式等多种编程范式
 

JavaScript语法特殊点

  1. 动态类型语言,变量可以随时更改类型(弱类型)。
  1. 变量提升(hoisting):所有的变量的声明语句,都会被提升到代码的头部
      • JavaScript 引擎的工作方式是,先解析代码,获取所有被声明的变量,然后再一行一行地运行。
  1. 严格相等运算符(===
  1. switch语句内部采用的是“严格相等运算符”
  1. JavaScript 语言允许,语句的前面有标签(label),相当于定位符,用于跳转到程序的任意位置
  1. undefined & null
      • null是一个表示“空”的对象,转为数值时为0
      • undefined是一个表示"此处无定义"的原始值,转为数值时为NaN
      • if语句中,nullundefined都会被自动转为false
  1. 布尔值转换规则:
    1. false:undefinednullfalse0NaN""''
    2. true:其余都为true,eg:[]{}
  1. 整数 | 小数:JavaScript底层没有整数,所有数都是64位浮点数
    1. 进行整数运算时:自动将64位浮点数转为32位整数
  1. 正零(+0)和负零(-0):二者在当做分母的时候返回值不相等,其他时候都是等价的
  1. NaN(Not a Number):
    1. NaN不等于任何值,包括它本身
    2. NaN在布尔运算时被当做false
    3. NaN与任何数的运算结果都是NaN
  1. Infinity无穷:
    1. Infinity大于一切数值(除了NaN),-Infinity小于一切数值(除了NaN
    2. InfinityNaN比较,总是返回false
    3. Infinitynull计算时,null会转成0,等同于与0的计算
    4. Infinityundefined计算,返回的都是NaN
  1. isNaN方法:isNaN只对数值有效,如果传入其他值,会被先转成数值
    1. 传入字符串、对象和数组的时候,它们会被先转成NaN,所以最后返回true
    2. 对于空数组和只有一个数值成员的数组,isNaN返回false
    3. 判断NaN更可靠的方法是,利用NaN为唯一不等于自身的值的这个特点,进行判断。
  1. JavaScript 使用 Unicode 字符集,只支持两字节的字符
    1. JavaScript对于四字节的字符会识别成是两个字符
    2. JavaScript 返回的字符串长度可能是不正确的
  1. 对象的引用:
    1. 不同的变量名指向同一个对象,那么它们都是这个对象的引用,也就是说指向同一个内存地址。修改其中一个变量,会影响到其他所有变量。
    2. 如果取消某一个变量对于原对象的引用,不会影响到另一个变量
  1. 表达式和语句的区分:
    1. 行首是大括号时,一律解释为代码块。
    2. 大括号前加上圆括号,解释为对象。
  1. 参数传递:
    1. 函数参数如果是原始类型的值(数值、字符串、布尔值),传递方式是传值传递(passes by value),在函数体内修改参数值,不会影响到函数外部。
    2. 函数参数是复合类型的值(数组、对象、其他函数),传递方式是传址传递(pass by reference),在函数内部修改参数,将会影响到原始值
  1. arguments对象:用来在函数体内部读取所有参数
  1. 闭包:定义在一个函数内部的函数
    1. JavaScript 语言特有的"链式作用域"结构:父对象的所有变量,对子对象都是可见的,反之则不成立
    2. 用处:
      1. 读取外层函数内部的变量
      2. 让这些变量始终保持在内存中
      3. 封装对象的私有属性和私有方法
  1. eval命令:
    1. 接受一个字符串作为参数,并将这个字符串当作语句执行。
    2. 使用别名执行evaleval内部一律是全局作用域。
  1. 数组是特殊的对象:
    1. 数组的元素可以是任意类型
    2. 数组的key是从小到大排列的整数:0,1,2…
    3. length属性:该属性是一个动态的值,等于键名中的最大整数加上1。字符串的键不影响length属性
  1. 对象的相加:
    1. 对象相加的时候先转为原始类型的值再相加
      1. 即先调用valueOf方法,再调用toString方法
      2. Date对象的实例,会优先执行toString方法。
  1. 严格相等运算符
    1. ===:严格相等运算符,比较它们是否为“同一个值”。如果两个值不是同一类型,严格相等运算符(===)直接返回false
      1. 比较复合类型值时,比较它们是否指向同一个地址
    2. ==:相等运算符,遇到不同类型的值时,会将它们转换成同一个类型,再用严格相等运算符进行比较。
  1. void运算符的作用是执行一个表达式,然后不返回任何值,或者说返回undefined
  1. 逗号运算符用于对两个表达式求值,并返回后一个表达式的值。
  1. try/catch/finally的执行顺序
    1. return语句在finally之前执行,但是在finally代码执行完毕后才返回
    2. catch代码块之中,一遇到throw语句或return语句,就会去执行finally代码块
  1. “分号的自动添加”(Automatic Semicolon Insertion,简称 ASI)
  1. Date的参数取值,月份序号从0开始,日期从1开始
20220909:
  1. 控制对象的状态:
    1. Object.preventExtensions:对象无法添加新的属性
    2. Object.seal:对象无法添加新的属性也无法删除旧属性
    3. Object.freeze:对象无法添加新属性、无法删除旧属性,也无法改变属性的值,即变对象为常量
    4. 漏洞:可以通过改变原型对象(Prototype)来增加属性
  1. JSON格式(JavaScript Object Notation)
  1. JavaScript 语言之中,一切皆对象,运行环境也是对象,所以函数都是在某个对象之中运行,this就是函数运行时所在的对象(环境)
    1. this的指向是动态的
    2. JavaScript 提供了callapplybind这三个方法,来切换/固定this的指向。
      1. call方法,可以指定函数内部this的指
          • this指向传入的对象
          • 如果参数为空、nullundefined,则默认传入全局对象。
      2. apply接收一个数组作为函数执行时的参数
      3. bind()方法用于将函数体内的this绑定到某个对象,然后返回一个新函数。
          • bind()每次调用都会返回新的函数
  1. Prototype(原型对象):JavaScript 继承机制的设计思想就是,原型对象的所有属性和方法,都能被实例对象共享
      • 每个函数都有默认的prototype属性,指向一个对象
      • 对于普通函数来说,该属性基本无用
      • 对于构造函数来说,生成实例的时候,该属性会自动成为实例对象的原型。
      • 只要修改原型对象,变动就立刻会体现在所有实例对象上。
      • 如果实例对象自身就有某个属性或方法,它就不会再去原型对象寻找这个属性或方法。
      原型对象的作用:定义所有实例对象共享的属性和方法。
  1. 原型链:对象到原型,再到原型的原型……
      • 原型链的尽头是null
      • 读取对象的某个属性时,JavaScript 引擎先寻找对象本身的属性,如果找不到,就到它的原型去找,如果还是找不到,就到原型的原型去找。如果直到最顶层的Object.prototype 还是找不到,则返回undefined
      • 如果对象自身和它的原型,都定义了一个同名属性,那么优先读取对象自身的属性,这叫做“覆盖”(overriding)。
      • prototype对象有一个constructor属性,默认指向prototype对象所在的构造函数。
  1. instanceof运算符只能用于对象,不适用原始类型的值。
  1. 模块:模块是实现特定功能的一组属性和方法的封装。
      • 简单的做法是把模块写成一个对象,所有的模块成员都放到这个对象里面。
      • 另一种做法是使用“立即执行函数”(Immediately-Invoked Function Expression,IIFE),将相关的属性和方法封装在一个函数作用域里面,可以达到不暴露私有成员的目的。
      • “放大模式”(augmentation):如果一个模块很大,必须分成几个部分,或者一个模块需要继承另一个模块,这时就有必要采用“放大模式”(augmentation)
      • 独立性是模块的重要特点,模块内部最好不与程序的其他部分直接交互。
  1. 严格模式:'use strict';
    1. 设计目的:
        • 明确禁止一些不合理、不严谨的语法,减少 JavaScript 语言的一些怪异行为。
        • 增加更多报错的场合,消除代码运行的一些不安全之处,保证代码运行的安全。
        • 提高编译器效率,增加运行速度。
        • 为未来新版本的 JavaScript 语法做好铺垫。
    2. 总结:显式报错、增强的安全措施、静态绑定、向下一个版本的JavaScript过渡
  1. 一些异步操作相关的基本概念
    1. 单线程模型:JavaScript只在一个线程上运行,好处是实现简单,执行环境单纯,坏处任务耗时长,后续任务需要排队,拖延程序执行。
    2. 同步任务:主线程上执行,只有前一个任务执行完毕,才能执行后一个任务。
    3. 异步任务:被引擎放在一边,不进入主线程、而进入任务队列的任务。只有引擎认为某个异步任务可以执行了(比如 Ajax 操作从服务器得到了结果),该任务(采用回调函数的形式)才会进入主线程执行。
    4. 任务队列:里面是各种需要当前程序处理的异步任务
      1. 机制:主线程会去执行所有的同步任务。等到同步任务全部执行完,就会去看任务队列里面的异步任务如果满足条件,那么异步任务就重新进入主线程开始执行,这时它就变成同步任务了。
      2. 异步任务的写法通常是回调函数。
    5. 事件循环:用于等待和发送消息和事件
    6. 异步操作的模式:
      1. 回调函数
      2. 事件监听
      3. 发布/订阅
    7. 串行执行/并行执行
  1. 定时器:
    1. setTimeout():指定某个函数或某段代码,在多少毫秒之后执行
        • setTimeout(f, 0):setTimeout(f, 0)会在下一轮事件循环一开始就执行
          • 可以调整事件的发生顺序
          • 用户自定义的回调函数,通常在浏览器的默认动作之前触发
          • 由于setTimeout(f, 0)实际上意味着,将任务放到浏览器最早可得的空闲时段执行,所以那些计算量大、耗时长的任务,常常会被放到几个小部分,分别放到setTimeout(f, 0)里面执行。
    2. setInterval():指定某个任务每隔一段时间就执行一次,也就是无限次的定时执行。
      1. setTimeoutsetInterval的运行机制,是将指定的代码移出本轮事件循环,等到下一轮事件循环,再检查是否到了指定时间。如果到了,就执行对应的代码;如果不到,就继续等待。
    3. clearTimeout()
    4. clearInterval()
  1. Promise对象:Promise 的设计思想是,所有异步任务都返回一个 Promise 实例。Promise 实例有一个then方法,用来指定下一步的回调函数。
    1. then方法可以接受两个回调函数,第一个是异步操作成功时(变为fulfilled状态)的回调函数,第二个是异步操作失败(变为rejected)时的回调函数(该参数可以省略)。
    2. Promise 的回调函数不是正常的异步任务,而是微任务(microtask)。它们的区别在于,正常任务追加到下一轮事件循环,微任务追加到本轮事件循环。这意味着,微任务的执行时间一定早于正常任务。
  1. DOM:JavaScript 操作网页的接口,全称为“文档对象模型”(Document Object Model)
    1. 作用:将网页转为一个 JavaScript 对象,从而可以用脚本进行各种操作(比如增删内容)
    2. 浏览器会根据 DOM 模型,将结构化文档(比如 HTML 和 XML)解析成一系列的节点,再由这些节点组成一个树状结构(DOM Tree)。所有的节点和最终的树状结构,都有规范的对外接口。
    3. DOM节点:浏览器提供一个原生的节点对象Node,七种节点都继承了Node,因此具有一些共同的属性和方法。
      1. Document
        整个文档树的顶层节点
        DocumentType
        doctype标签(比如<!DOCTYPE html>)
        Element
        网页的各种HTML标签(比如<body>、<a>等)
        Attr
        网页元素的属性(比如class="right"
        Text
        标签之间或标签包含的文本
        Comment
        注释
        DocumentFragment
        文档的片段
    4. 节点树:
      1. 浏览器原生提供document节点,代表整个文档
      2. 文档的第一层有两个节点,第一个是文档类型节点(<!doctype html>),第二个是 HTML 网页的顶层容器标签<html>,其他 HTML 标签节点都是它的下级节点
      3. 三种层级关系:
          • 父节点关系(parentNode):直接的那个上级节点
          • 子节点关系(childNodes):直接的下级节点
          • 同级节点关系(sibling):拥有同一个父节点的节点
  1. NodeList接口,HTMLCollection接口,ParentNode 接口,ChildNode 接口
  1. document节点对象代表整个文档,每张网页都有自己的document对象。window.document属性就指向这个对象。
  1. Element节点对象对应网页的 HTML 元素。每一个 HTML 元素,在 DOM 树上都会转化成一个Element节点对象(以下简称元素节点)。
  1. Text节点:文本节点(Text)代表元素节点(Element)和属性节点(Attribute)的文本内容
  1. DocumentFragment 节点:代表一个文档的片段,本身就是一个完整的 DOM 树形结构。它没有父节点,parentNode 返回null,但是可以插入任意数量的子节点。它不属于当前文档,操作DocumentFragment节点,要比直接操作 DOM 树快得多。
      • 一般用于构建一个 DOM 结构,然后插入当前文档
      • DocumentFragment节点本身不能被插入当前文档。当它作为appendChild()insertBefore()replaceChild()等方法的参数时,是它的所有子节点插入当前文档,而不是它自身
      • 一旦DocumentFragment节点被添加进当前文档,它自身就变成了空节点(textContent属性为空字符串),可以被再次使用
      • 如果想要保存DocumentFragment节点的内容,可以使用cloneNode方法。
    1. CSSStyleDeclaration 接口用来操作元素的样式。三个地方部署了这个接口;CSSStyleDeclaration 接口可以直接读写 CSS 的样式属性,不过,连词号需要变成骆驼拼写法。
        • 元素节点的style属性(Element.style
        • CSSStyle实例的style属性
        • window.getComputedStyle()的返回值
    1. StyleSheet 接口:StyleSheet接口代表网页的一张样式表,包括<link>元素加载的样式表和<style>元素内嵌的样式表。
    1. Mutation Observer API 用来监视 DOM 变动。DOM 的任何变动,比如节点的增减、属性的变动、文本内容的变动,这个 API 都可以得到通知。
        • 它等待所有脚本任务完成后,才会运行(即异步触发方式)。
        • 它把 DOM 变动记录封装成一个数组进行处理,而不是一条条个别处理 DOM 变动。
        • 它既可以观察 DOM 的所有类型变动,也可以指定只观察某一类变动。
    1. 事件的本质是程序各个组成部分之间的一种通信方式,也是异步编程的一种实现。
    1. EventTarget接口:DOM 节点的事件操作(监听和触发),都定义在EventTarget接口。
    1. 监听模型:浏览器的事件模型,就是通过监听函数(listener)对事件做出反应。浏览器监听到了这个事件,就会执行对应的监听函数。这是事件驱动编程模式(event-driven)的主要编程方式。
      1. HTML中on-属性方式指定的监听代:只会在冒泡阶段触发,不利于代码分工,因此不推荐使用
      2. 元素节点的事件属性:同一个事件只能定义一个监听函数
      3. EventTarget.addEventListener是推荐的指定监听函数的方法。它有如下优点:
          • 同一个事件可以添加多个监听函数。
          • 能够指定在哪个阶段(捕获阶段还是冒泡阶段)触发监听函数。
          • 除了 DOM 节点,其他对象(比如windowXMLHttpRequest等)也有这个接口,它等于是整个 JavaScript 统一的监听函数接口。
        • 监听函数内部的this指向触发事件的那个元素节点。
    1. 事件的传播:一个事件发生后,会在子元素和父元素之间传播(propagation)。这种传播分成三个阶段:
        • 第一阶段(捕获阶段):从window对象传导到目标节点(上层传到底层),称为“捕获阶段”(capture phase)。
        • 第二阶段(目标阶段):在目标节点上触发,称为“目标阶段”(target phase)。
        • 第三阶段(冒泡阶段):从目标节点传导回window对象(从底层传回上层),称为“冒泡阶段”(bubbling phase)。
    1. 事件的代理:由于事件会在冒泡阶段向上传播到父节点,因此可以把子节点的监听函数定义在父节点上,由父节点的监听函数统一处理多个子元素的事件。这种方法叫做事件的代理(delegation)
      1. 如果希望事件到某个节点为止,不再传播,可以使用事件对象的stopPropagation方法。stopPropagation方法只能阻止这个事件的传播,不能取消这个事件
      2. 如果想要彻底取消该事件,不再触发后面所有click的监听函数,可以使用stopImmediatePropagation方法
    1. 浏览器模型:
     
    Loading...
    目录