js红宝书学习笔记(1-6章)

就按照原书中写的章节顺序记笔记了, 还有可能我学过js一段时间了,可能有些对于新手的细节会忽略,但是会尽量写全的~

1.第一章 什么是JavaScript

1.1讲了一些历史,所以我们从1.2开始看

1.2 JavaScript的实现

完整的JaveScript包含三部分:

  • 核心:ECMAScript(下文简写为ES)
  • 文档对象模型:DOM
  • 浏览器对象模型:BOM

三者之间的关系:浏览器是ES实现可能存在的一种宿主环境,也就是说浏览器是ES运行的载体;宿主环境提供ES的基准实现和与环境自身交互必须的扩展,即浏览器提供ES实现的环境和交互的实现条件;扩展(如DOM)使用ES核心类型和语法,提供特定于环境的额外功能,即在ES标准的基础上,实现功能。

ECMAScript

ECMAScript定义的部分:语法、类型、语句、关键字、保留字、操作符、全局对象。js不等于ES,js只是实现ES的一种语言。

ES6-ES10,表示的是五个版本,ES6也可以发布年份命名为ES2015,以此类推。ES6是一次最重要的增强特性。支持了类、模块、迭代器、箭头函数、promise等众多新数据类型。

DOM

DOM文档对象模型:提供与网页内容交互的方法和接口。是一个应用编程接口,用于在HTML中使用扩展的XML。

DOM的升级历程:

  1. DOM Core提供一种映射XML文档,方便访问和操作文档任意部分的方式;DOM HTML拓展了前者,并增加了特定于 HTML 的对象和方法。

  2. 新增了以下模块,以支持新的接口。

    DOM视图:描述追踪文档不同视图(如应用css样式前后的文档)的接口。

    DOM事件:描述事件及事件处理的接口。

    DOM样式:描述处理元素CSS样式的接口。

    DOM遍历和范围:描述遍历和操作DOM树的接口。

  3. 进一步扩展DOM,增加了以统一的方式加载和保存文档的方法(包含在一个叫 DOM Load and Save 的新模块中),还有验证文档的方法(DOM Validation)。

  4. 目前,W3C 不再按照 Level 来维护 DOM 了,而是作为 DOM Living Standard 来维护,其快照称为 DOM4。DOM4 新增的内容包括替代 Mutation Events 的 Mutation Observers。

其他DOM:除了DOM Core和 DOM HTML接口,有些其他语言也发布了自己的 DOM 标准。下面列出的语言 是基于 XML 的,每一种都增加了该语言独有的 DOM 方法和接口:

  • 可伸缩矢量图(SVG,Scalable Vector Graphics)
  • 数学标记语言(MathML,Mathematical Markup Language)
  • 同步多媒体集成语言(SMIL,Synchronized Multimedia Integration Language)

此外,还有一些语言开发了自己的 DOM 实现,比如 Mozilla 的 XML 用户界面语言(XUL,XML User Interface Language)。不过,只有前面列表中的语言是 W3C 推荐标准。

BOM

BOM浏览器对象模型:提供与浏览器交互的方法和接口。总体来说,BOM 主要针对浏览器窗口和子窗口(frame),不过人们通常会把任何特定于浏览器的扩展都归在 BOM 的范畴内。比如:

  • 弹出新浏览器窗口的能力;
  • 移动、缩放和关闭浏览器窗口的能力;
  • navigator 对象,提供关于浏览器的详尽信息;
  • location 对象,提供浏览器加载页面的详尽信息;
  • screen 对象,提供关于用户屏幕分辨率的详尽信息;
  • performance 对象,提供浏览器内存占用、导航行为和时间统计的详尽信息;
  • 对 cookie 的支持;
  • 其他自定义对象,如 XMLHttpRequest 和 IE 的 ActiveXObject。

第2章 HTML中的JavaScript

2.1 script元素

将 JavaScript 插入 HTML 的主要方法是使用<script>元素。<script>元素有下列8个属性。

  • async:可选。表示应该立即开始下载脚本,但不能阻止其他页面动作,比如下载资源或等待其他脚本加载。只对外部脚本文件有效。异步脚本保证会在页面的 load 事件前执行。
  • charset:可选使用 src 属性指定的代码字符集。这个属性很少使用,因为大多数浏览器不在乎它的值。
  • crossorigin:可选。配置相关请求的CORS(跨源资源共享)设置。默认不使用CORScrossorigin= "anonymous"配置文件请求不必设置凭据标志。crossorigin="usecredentials"设置凭据 标志,意味着出站请求会包含凭据。
  • defer:可选。表示脚本可以延迟到文档完全被解析和显示之后再执行。只对外部脚本文件有效。
  • integrity:可选。允许比对接收到的资源和指定的加密签名以验证子资源完整性(SRI, Subresource Integrity)。如果接收到的资源的签名与这个属性指定的签名不匹配,则页面会报错, 脚本不会执行。这个属性可以用于确保内容分发网络(CDN,Content Delivery Network)不会提供恶意内容。
  • language:废弃。最初用于表示代码块中的脚本语言(如"JavaScript"、“JavaScript 1.2” 或"VBScript")。大多数浏览器都会忽略这个属性,不应该再使用它。
  • src:可选。表示包含要执行的代码的外部文件。
  • type:可选。代替 language,表示代码块中脚本语言的内容类型(也称 MIME 类型)。按照惯例,这个值始终都是"text/javascript",尽管"text/javascript"和"text/ecmascript" 都已经废弃了。JavaScript 文件的 MIME 类型通常是"application/x-javascript",不过给 type 属性这个值有可能导致脚本被忽略。在非 IE 的浏览器中有效的其他值还有"application/javascript"和"application/ecmascript"。如果这个值是 module,则代码会被当成 ES6 模块,而且只有这时候代码中才能出现 import 和 export 关键字。

包含在script标签中的代码会被从上到下解析,元素中的代码被计算完成之前,页面的其余内容不会被加载,也不会被显示。没有使用 defer 和 async 属性的script元素也是从上到下解析。

所以把script标签写在body标签内页面内容的后面,防止页面长时间空白,如果要使用defer属性,延迟加载脚本,要记得对于 XHTML 文档,指定 defer 属性时应该写成 defer=“defer”

在使用行内 JavaScript 代码时,要注意代码中不能出现字符串</script>这会被当成标签的结束符,需要使用的话要转义<\/script>。使用外部文件中的JavaScript,必须使用src属性指明地址。

动态加载脚本的方法:通过向DOM中动态添加script元素同样可以加载指定的脚本。只要创建一个script 元素并将其添加到 DOM 即可。但是这种方式默认为异步加载。有些浏览器不支持async,可以使用以下设置为同步加载。

以这种方式获取的资源对浏览器预加载器是不可见的。这会严重影响它们在资源获取队列中的优先级。 在文档头部声明 <link rel="preload" href="gibberish.js">

let script = document.createElement('script');
script.src = 'gibberish.js';
script.async = false; //设置为同步加载
document.head.appendChild(script); 

行内代码与外部文件的加载方式,其中外部文件的优点:

  • 可维护性:用一个目录保存,更容易维护,独立于HTML页面来编辑代码
  • 缓存:重复使用多个js文件时会缓存,只需要下载一次
  • 适应未来:放到外部文件中,不必考虑XHTML的语法(与HTML相同)了

3. 语言基础

语法:很大程度上借鉴了 C 语言和其他类 C 语言,如 Java 和 Perl。

  • 区分大小写:ES 中一切都区分大小写。无论是变量、函数名还是操作符,都区分大小写。

  • 标识符:就是变量、函数、属性或函数参数的名称。标识符可以由一或多个下列字符组成:第一个字符必须是一个字母、下划线(_)或美元符号($);剩下的其他字符可以是字母、下划线、美元符号或数字。标识符中的字母可以是扩展 ASCII(Extended ASCII)中的字母,也可以是 Unicode 的字母字符,如 À 和 Æ(但不推荐使用)。

    关键字、保留字、true、false 和 null 不能作为标识符。

  • 注释://单行 /* 多行 */

  • 严格模式:在函数开头或配置文件中指定"use strict"

  • 语句:分号结尾; 代码块用{}包裹;

关键字和保留字:关键字有特殊用途,比如表示控制语句的开始和结束, 或者执行特定的操作。不能用作标识符或属性名。
在这里插入图片描述

变量:声明:var 和 let const,后两者只能在ES6及以上版本中使用

var:可重复声明 有变量提升 没有块级作用域

let/const: 不可重复声明 没有变量提升 块级作用域。(const为常量,不能修改且声明时必须初始化)

ES6的数据类型:Undefined Boolean String Number Object Function Symbol
  • undefined:声明一个变量但没有初始化,等于赋值undefined。但是当用typeof value 检查一个值的时候,返回值为undefined,并不能确定这个变量未赋值还是变量不存在

  • Null:null类型只有一个值null,表示一个空对象指针,一般用null初始化对象。null派生出了undefined,所以null==undefined

  • Boolean:与其他类型数值的转换:转为false的值: 空字符串, 0,NaN,null,undefined

  • Number:默认为十进制,可以通过0开头转为八进制,但在严格模式下无效。八进制和16进制创建的数值在所有数学操作中都会视为十进制进行操作(Infinity无穷 NaN非数字)

  • String:字符串可以用 ‘xx’ “xx” ``这三种包裹。前两种都是普通字符串,最后一种则称为模板字符串。可以在其中使用变量和常量混合的形式,变量用${key}插值方法使用。如:

    const name = 'liqiang';
    `hello, my name is ${name}`
    
  • Symbol:用Symbol()函数初始化(不需要new关键字)。只要创建 Symbol()实例并将其 用作对象的新属性,就可以保证它不会覆盖已有的对象属性,无论是符号属性还是字符串属性。Symbol具有唯一性。

    一些函数:

  • Object:对象类型, 对象就是一组数据和功能的集合。Object实例都会有的方法和属性:

    • constructor:用于创建当前对象的函数
    • hasOwnProperty(name):判断当前对象实例上是否有name属性(不进行原型链查找)
    • isPrototypeOf(object):判断当前对象是否为另一个对象的原型
    • propertyIsEnumerable(name):判断给定的属性是否可以for-in枚举
    • toLocaleString():返回对象的字符串表示
    • valueOf():返回对象对应的字符串、数值或布尔值表示
操作符
  • 一元操作符:递增:a++; ++a; 递减:a–;–a;
  • 位操作符:按位非~;按位与&; 按位或|;按位异或^;左移<<;有符号右移>>;无符号右移>>>;
  • 布尔操作符:逻辑非!;逻辑与&&;逻辑或||(或有惰性,第一个为真直接返回第一个;第一个不为真才去检验第二个);
  • 乘性操作符:乘法*; 除法/; 取余(模)%;
  • 指数操作符:指数**(等同于Math.pow())
  • 加性操作符:加法+;减法-;
  • 关系操作符:大于>;小于<;小于等于<=;大于等于>=
  • 相等操作符:相等==;全等===(比较数据类型);不等于!=;不全等!==;
  • 条件操作符(三元运算符):条件?a:b;条件为真取a,条件为假取b
  • 赋值操作符:赋值=;
  • 逗号操作符:逗号, 在一条语句中执行多个操作,比如连续声明变量let a=1, b, c;
语句
  • if语句:if(表达式){},表达式为真则执行后面的代码块;if-else;或者 if-else if-else 等都可以

  • do-while语句:do{}while(表达式),执行do中的语句,然后判断表达式,直到表达式值为false跳出执行do中的代码块。代码块中的语句至少执行一次

  • while语句:while(表达式){};表达式的值为真则执行代码块中的语句,先判断再执行,最少0次

  • for(初始;条件;操作){}:可以给初值,条件判断为真执行代码块,然后执行操作;再去判断条件,直到条件不符合跳出循环;

  • for(关键字 in 对象){}:遍历对象的所有属性,对象所有可枚举属性都会返回一次

  • for(关键字 of 数组){}:遍历数组的所有元素

  • 标签语句:start: for (let i=0; i<count; i++){} start是个标签,标签语句的典型应用场景是嵌套循环

  • break和continue语句:break直接关闭循环;continue结束本次循环,开始下次循环

  • with语句:多用于对一个对象反复操作时(严格模式禁用)。在使用with的代码块内部,变量首先会被认为是个局部变量,如果未找到则会搜索with(对象)对象身上是否有同名属性。

    with(location){
    	let qs = search.substring(1);
    	let hostName = hostname; //hostname先被认为是否局部变量,没有则查找location.hostname
    }
    
  • switch语句:switch(检验值){ case value: break;} case的用法类似于if,检验值等于value的时候执行下面的语句,break用于跳出switch结构。

函数

结构:function functionName(参数){语句}

第四章 变量、作用域和内存

原始值和引用值

把一个基本数据类型的值赋值给其他变量的时候,赋的是原始值,就是变量实际的值。在操作对象赋值的时候,赋的是引用值,就是让变量也指向那个内存地址。

  • 动态属性:就是给变量添加属性,但是变量必须是对象属性才可以保存,否则是undefined。
  • 复制值:在通过变量把一个原始值(基本数据类型)赋值到另一个变量时,这个值跟存储在原始变量中的值是完全独立的。当把引用值从一个变量复制给另一个变量时,只是复制了一个指针,二者指向同一个位置。
  • 传递参数:ES中所有函数的参数都是按值传递的。也就是说,对于对象来说,对象这个整体是一个引用类型,但是里面的基本数据类型的属性是复制的值,并不是指向。
  • 确定类型:
    • typeof:只能准确判断String、Number、Boolean、undefined;
    • 其他数据类型:instanceof(前面几个也可以用instanceof来判断)。用法:a instanceof Array,返回值Boolean。但是instanceof检验任何引用值和object构造函数都会返回true。
执行上下文与作用域

变量或函数的执行上下文决定了他们可以访问哪些数据以及他们的行为。而我们常说的this指向,也就是执行上下文的一个具体化表现。上下文中的代码在执行的时候,会创建变量对象的一个作用域链。上下文在其所有代码都执行完毕后会被销毁,包括定义在它上面的所有变量和函数

  • 函数上下文:作用域为当前函数。则外部的语句无法访问函数内部的变量。

  • 全局上下文:最外层的上下文(根据宿主环境 全局上下文的对象可能不一样)浏览器中就是window对象,var定义的全局函数和变量会挂在window上,而let和const的顶级声明不会再全局上下文中,但在作用域链解析后效果相同。

    下文中的代码在执行的时候,会创建变量对象的一个作用域链,这个作用域链决定了各级上下文中的代码在访问变量和函数时的顺序。代码正在执行的上下文位于作用域链最前,全局上下文始终在最末。也就是说,从里层向外找,当前没有就向外找一层,直至找到或作用域链结束。

作用域链增强

某些语句会导致在作用域链前端临时添加一个上下文,这个上下文在代码执 行后会被删除。

  • try/catch语句里的catch块:创建一个新的变量对象,包含要抛出的错误对象的声明。
  • with语句:向作用域链前端添加指定的对象
变量声明

ES6新增了let和const声明变量。所以var和let const的比较以前也会经常被问到

  • 作用域:var声明的变量是函数作用域,函数内部可以访问,外部不可以

    ​ let声明的变量是块级作用域,{let a}花括号内部可以访问a,外部不可以

  • 变量提升:var有变量提升,也就是说可以在声明一个变量前读取和使用该变量,但值为undefined

    ​ let没有变量提升,不可以在声明前使用,会报错

  • 重复声明:var可以重复声明,比如 var a ; var a=1;

    ​ let不可以重复声明,会报错

  • const与let类似,唯一区别就是const用来声明常量,声明并赋值,因为后续任何时候都不可以再赋值。但是如果是引用类型,不修改引用地址,只修改内部的属性是不会报错的。

垃圾回收

js有垃圾回收机制,执行环境负责在代码执行时管理内存。通过自动内存管理实现内存分配和闲置资源回收。标记不再使用的变量的两种主要实现方式:标记清理和引用计数

标记清理

垃圾回收程序运行的时候,会标记内存中存储的所有变量(记住,标记方法有很多种)。然后,它会将所有在上下文中的变量,以及被在上下文中的变量引用的变量的标记去掉。在此之后再被加上标记的变量就是待删除的了,原因是任何在上下文中的变量都访问不到它们了。随后垃圾回收程序做一次内存清理,销毁带标记的所有值并收回它们的内存。

js最常用的垃圾回收策略就是标记清理。上下文中的对象在上下文执行结束就会被销毁(如果没有其他地方引用)

引用计数

思路是对每个值都记录它被引用的次数。声明变量并给它赋一个引用值时,这个值的引用数为 1。如果同一个值又被赋给另一个变 量,那么引用数加 1。类似地,如果保存对该值引用的变量被其他值给覆盖了,那么引用数减 1。当一个值的引用数为 0 时,就说明没办法再访问到这个值了,因此可以安全地收回其内存了。垃圾回收程序下次运行的时候就会释放引用数为 0 的值的内存。

这种策略没那么常用,当循环引用的时候,这种策略下,循环引用的变量在函数结束后还会存在,因为它们的引用数永远不会变成 0。如果函数被多次调用,则会导致大量内存永远不会被释放。为避免这种情况,在确认变量不再使用可以赋值为null。

内存管理

解除引用:如果数据不再必要,那么把它设置为 null,从而释放其引用。(这个建议最适合全局变量和全局对象的属性。局部变量在超出作用域后会被自动解除引用)

  • 用const和let声明提升性能:都是块级作用域,与var相比有助于改进垃圾回收的过程。

  • 隐藏类和删除操作:能够共享相同隐藏类的对象性能会更好,也就是说不要对实例先创建再补充属性,而要在构造函数中一次性声明所有属性,听过传值造成差别,这样可以共享一个隐藏类。不需要其中一个实例的时候,不要delete a去删除,而是令a=null。 这样可以保持隐藏类不变和继续共享,也不耽误垃圾回收。

  • 内存泄漏:大部分由于不合理的引用引起。

    • 意外声明全局变量:声明变量时没用任何关键字,解释器会默认为window.a
    • 定时器一直运行:定时器一直运行,会导致垃圾回收一直无法清理其中引用的外部变量。
    • 闭包使用不当:let outer = function() { let name = 'Jake'; return function() { return name; }; }; 调用 outer()会导致分配给 name 的内存被泄漏。以上代码执行后创建了一个内部闭包,只要返回 的函数存在就不能清理 name,因为闭包一直在引用着它。
  • 静态分配与对象池:理论上,如果能合理使用分配的内存,同时避免多余的垃圾回收,就可以保住因释放内存而损失的性能。浏览器决定何时运行垃圾回收程序的一个标准就是对象更替的速度。如果有很多对象被初始化,然后一下子又都超出了作用域,那么浏览器就会采用更激进的方式调度垃圾回收程序运行,这样当然会影响性能。

    • 使用对象池:在初始化的某一时刻,可以创建一个对象池,用来管理一组可回收的对象。 应用程序可以向这个对象池请求一个对象、设置其属性、使用它,然后在操作完成后再把它还给对象池。 由于没发生对象初始化,垃圾回收探测就不会发现有对象更替,因此垃圾回收程序就不会那么频繁地运行。

      如果对象池只按需分配矢量(在对象不存在时创建新的,在对象存在时则复用存在的),那么这个实现本质上是一种贪婪算法,有单调增长但为静态的内存。这个对象池必须使用某种结构维护所有对象,数组是比较好的选择。不过,使用数组来实现,必须留意不要招致额外的垃圾回收。避免动态分配操作,可以在初始化时就创建一个大小够用的数组,从而避免先删除再创建的操作。不过,必须事先想好这个数组有多大。

小结

JavaScript 变量可以保存两种类型的值:原始值和引用值。原始值可能是以下 6 种原始数据类型之 一:Undefined、Null、Boolean、Number、String 和 Symbol。原始值和引用值有以下特点。

  • 原始值大小固定,因此保存在栈内存上。
  • 从一个变量到另一个变量复制原始值会创建该值的第二个副本。
  • 引用值是对象,存储在堆内存上。
  • 包含引用值的变量实际上只包含指向相应对象的一个指针,而不是对象本身。
  • 从一个变量到另一个变量复制引用值只会复制指针,因此结果是两个变量都指向同一个对象。
  • typeof 操作符可以确定值的原始类型,而 instanceof 操作符用于确保值的引用类型。

任何变量(不管包含的是原始值还是引用值)都存在于某个执行上下文中(也称为作用域)。这个 上下文(作用域)决定了变量的生命周期,以及它们可以访问代码的哪些部分。执行上下文可以总结如下。

  • 执行上下文分全局上下文、函数上下文和块级上下文。
  • 代码执行流每进入一个新上下文,都会创建一个作用域链,用于搜索变量和函数。
  • 函数或块的局部上下文不仅可以访问自己作用域内的变量,而且也可以访问任何包含上下文乃 至全局上下文中的变量。
  • 全局上下文只能访问全局上下文中的变量和函数,不能直接访问局部上下文中的任何数据。
  • 变量的执行上下文用于确定什么时候释放内存。

JavaScript 是使用垃圾回收的编程语言,开发者不需要操心内存分配和回收。JavaScript 的垃圾回收 程序可以总结如下。

  • 离开作用域的值会被自动标记为可回收,然后在垃圾回收期间被删除。
  • 主流的垃圾回收算法是标记清理,即先给当前不使用的值加上标记,再回来回收它们的内存。
  • 引用计数是另一种垃圾回收策略,需要记录值被引用了多少次。JavaScript 引擎不再使用这种算 法,但某些旧版本的 IE 仍然会受这种算法的影响,原因是 JavaScript 会访问非原生 JavaScript 对象(如 DOM 元素)。
  • 引用计数在代码中存在循环引用时会出现问题。
  • 解除变量的引用不仅可以消除循环引用,而且对垃圾回收也有帮助。为促进内存回收,全局对 象、全局对象的属性和循环引用都应该在不需要时解除引用。

第五章 基本引用类型

5.1 Date

日期对象,为1970.1.1零点至今的毫秒数(时间戳)创建:new Date(); 两个辅助方法

  • Date.parse()接受一个表示日期的字符串参数,将字符串转为时间戳。字符串不表示日期返回NaN。同时new Date(“May 23, 2019”) === new Date(Date.parse(“May 23, 2019”))。使用前者时,Date会自动调用Date.parse

  • Date.UTC()方法也返回时间戳,但是参数是年、0起月数、日、时、分、秒、毫秒。年月必须,不传默认日=1,其他为0;如:new Date(Date.UTC(2005, 4, 5, 17, 55,55))//2005.5.5 17:55:55

    new Date(Date.UTC(2000,0)) //2000.1.1 0:0:0,同Date.parse(), Date.UTC()也会被隐式调用

  • Date.toLocaleString(),返回与浏览器运行的本地环境一致的日期和时间

  • Date.toString(),返回带时区信息的日期和时间。

  • Date.valueOf(),返回的是日期的毫秒表示,因此直接用<、>等操作符就可以返回他们的值

日期的格式化方法:返回值都是字符串,但是输出会因浏览器而异,所以不能保证在用户界面显示一致的时间。

  • toDateString()显示日期中的周几、月、日、年(格式特定于实现)
  • toTimeString()显示日期中的时、分、秒和时区(格式特定于实现)
  • toLocaleDateString()显示日期中的周几、月、日、年(格式特定于实现和地区)
  • toLocaleTimeString()显示日期中的时、分、秒(格式特定于实现和地区)
  • toUTCString()显示完整的 UTC 日期(格式特定于实现)。

Date的其他方法
在这里插入图片描述
在这里插入图片描述

5.2 RegExp正则表达式

正则表达式匹配标记的模式/^ $/x,即x位置所允许的模式。在创建表达式对象的时候可以定义他们的模式:let pattern2 = new RegExp(“[bc]at”, “i”)

  • g:全局模式,查找字符串的全部内容,而不是找到一个匹配就结束
  • i:不区分大小写,表示在查找时忽略pattern和字符串的大小写
  • m:多行模式,查
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值