章2 词法结构
1.什么是字面量,标识符,保留字?
字面量即程序中的数据的值;标识符指数据的名字(字母、下划线_或美元符号$开头,为了和数值区分开,标识符不能用数字开头,);保留字是JS保留的某些可以使用的标识符,用来给自身使用,如null,if等。
2.什么是Unicode?(补充:什么是ASCII码 ?是一套电脑编码系统,可以用来表示大小写英文字母、数字和一些符号,到目前为止共定义了128个字符。)
Unicode是一个编码规范,目前实际实现的unicode编码只要有三种:UTF-8,UCS-2和UTF-16。
JS使用Unicode字符集编写,注:不支持表情符号
Unicode的转义序列是使用ASCII字符来代表任意16位 Unicode 内码,这些 Unicode 转义序列均以 \u 为前缀,其后跟随4个十六进制数(例如 \u4e00),以便于某些支持使用老技术的系统可以处理Unicode字符集。
https://blog.csdn.net/u012672456/article/details/44750277
章3 类型,值和变量
1.JS中,只有null和undefined是不能调用方法的值,这两个值是特殊值。
2.常用的Math、Number对象属性:
Math.pow() .floor() .ceil() .abs() .max() .min() .random()
Number.MAX_VALUE .MIN_VALUE .parseInt() .parseFloat() .isNaN() .isFinite()
注:NaN=>"非数值",不等于任何值甚至自己,所以x===NaN不能得出x是否为not a number,需用Number.isNaN(x)或x !== x
toString()方法和parseInt()方法对比:
number.toString(进制)方法是把一个 Number 对象转换为一个字符串,并返回结果。
parseInt(num,基数)函数将字符串转为数值并返回一个十进制整数或NaN。
两者参数不一样,toString方法填写要转换的进制,
而parseInt函数的第二个参数是填基数(即我原本是几进制的数,不填的话则默认原本数值的以开头为 "0x" , 0, 1 ~ 9 分别为十六进制的整数,八进制或十六进制的数字,十进制的整数),它返回的数值为十进制的整数或NaN!!!
3.所有二进制编程语言都无法精确表示哪怕0.1的数,所以二进制浮点数之间不能比较其相等性(相加减之后比较,数值的精确度不一样)
4.字符串
字符串使用for/of循环或...操作符的迭代,迭代的是字符!
字符串不可修改,toUpperCase()等方法均返回新字符串!
字符串可被当作只读数组,用方括号而非charAt()方法可访问个别字符:
let s = "hello"
s[0] //"h"
位于${ 和对应的}之间的内容会被当作JS表达式来解释:
let name = "BILL";
let ee = "Hello ${name}" ;// ee==Hello BILL
5.布尔值
布尔值只有一个有用的方法:toString(),用于将自己转换为字符串true或false。[拓:除null和undefined外,所有值都有toString()方法]
假性值六个(转布尔值时均为false):undefined,null,0,-0,NaN,""(空字符串)!!!其他均为真性值。JS的所有值均可转为boolean。例子:
假设变量o要么保存一个对象,要么是null:
1)if(o !=== null)... 只要不是null就执行。当需要严格区分null、0、" "时使用
2)if(o)... 只要不是false或其他任何假性值就执行。
6.null和undefined区别?
null(关键字):值不存在,typeof null ;返回字符串 "object" ,所以它是一种特殊对象,表示”没有对象“。
undefined(全局常量):更深层次的值不存在,变量的值未初始化时为undefined,查询不存在的对象属性或数组得undefined。
注:相等操作符==认为他们相等。
两者没有属性或方法,so用.或[ ]访问这两个值的属性或方法均导致TypeError。(对应章3.1)
7.对象(引用类型)
按引用进行比较,
对象值就是引用,
分为赋值引用(浅拷贝)和创建对象新副本(深拷贝,需要显示复制对象的属性或数组的元素)
8.类型转换
JS将+看作算术运算符而不是一元运算符,so有字符串时,JS采用字符串加法运算符(+操作符计算中有一个操作数是字符串时,则另一个操作数也会被转为字符串,即优先字符串拼接):
1 + 1 + 1 + 1 + "" ;//"4" 10 + " objects" ;// "10 objects",将10转为字符串后计算
但是JS其他时候更期待数值,所以除上面特殊的情况,其他都选择将字符串转换为数值、将==操作符中的操作数转为数值:
1 + 1 + 1 + 2 * "" ;// 3,将""转为数字0后计算
1 == "1" ; //true,字符串转为数值
1 == "a" ; //false,字符串“a”转数值为NaN
"0" == false ; //true,两者均转为0
"true" == true ; //false,"true"转为NaN,true转为1
null == undefined ;//true ,这里特殊,不要试图通过转换为数据类型来解释这个结论,因为Number(null);为0,Number(undefined);为NaN。而ECMAScript 规范认为,既然 null 和 undefined 的行为很相似,并且都表示 一个无效的值,那么它们所表示的内容也具有相似性
{ }(任何对象)转布尔值为true,[ ](空数组)转布尔值为true(对应章3.5)!!
9.所有对象都继承两个在对象到原始值转换时使用的方法:toString()和valueOf()。对象到数值的转换先使用偏数值算法将对象转为一个原始值,得到的原始值转为数值,偏数值算法先尝试valueOf(),将toString()作为备用。String\Number\Boolean 这样的包装类定义的valueOf()方法也只是简单地返回被包装的原始值,Array、Function和RegExp简单地继承默认方法。Array类继承默认的valueOf()方法,该方法不返回原始值,so数组转数值时,最终会调用toString()方法。如:
Number([ ]) ; //0 ,空数组先转为空字符串,空字符串转为数值0
Number([99]) ; //99,先转为字符串“99”,再转为数值99
注:多数对象没有valueOf()方法,因此会用toString()方法转换,如 Date对象p71
1 + { } // "1[object object] ",对象转换为字符串(使用toString()方法)后再拼接
2 + null //2 ,null转换为0(使用valueOf()方法)后计算加法
2 + undefined //NaN,undefined转为NaN后计算加法
p51 let const var
10.什么是解构赋值?p55
右侧值中提取(解构)出一个或多个值,保存到左侧变量中:
let [x,y] = [1,2];//相当于let x=1,y=2
章4 表达式与操作符
1.属性访问表达式中有两种访问属性的语法:
1)表达式(指定对象)后跟一个句点和一个标识符(指定属性名)
2)表达式后跟另一个位于方括号中的表达式(指定属性名或数组元素的索引)注:位于.或[前面的表达式都会先求值。若求值结果为null或undefined,抛出TypeError,cause他们是JS中不能有属性值的两个值。但若是指定名字的属性不存在,则属性访问表达式的值是undefined。
避免报错方法:用?.或?.[ ]语法防止报错。
同样,函数和方法调用也可用?.() 而不是()来防止报错:
o.m() ; //常规调用
o ?. m() ; //条件式属性访问,常规调用
o.m?.() ; //此处o必须不是null或undefined才不会报错
2.幂、一元、赋值、三元条件操作符具有右结合性:
w=(x=(y=z)); 等价于 w=x=y=z;
3. in操作符,instanceof操作符,typeof操作符 ,delete操作符p78
4.逻辑与(&&):只有左操作数为真值时才会对右侧求值
if(a === b) stop(); //只有a===b时才调用stop()
等价于
(a === b) && stop(); //返回stop()的结果
5.先定义操作符??p87
只要左操作数不是null或undefined就返回该值,否则返回右操作数的值(也是和上面一样避免报错)
章5 语句
1. for/of 循环专门用于可迭代对象(数组,字符串,映射Map、集合Set),对象默认是不可迭代的
2.Object.keys()返回一个对象可枚举自有属性名的数组,Object.values()迭代对象属性中每个键对应的值,
Object.entries()是个取对象属性名和值放于并返回一个数组的数组。当遍历不可迭代对象时,使用以上三个方法和for/of可迭代其属性。p103、131
3.for/in 循环可遍历任意对象(区别于for/of取数组值,它取数组的索引)
for/in只遍历可枚举属性(自有或继承)
不枚举名字为符号的属性
新定义一个属性在循环体中,可能不会被枚举;但循环体中删除则不再被枚举
因此最好基于Object.keys()使用for/of循环,而不是for/in
4. try/catch/finally语句——JS中的异常处理机制
try块中发生异常调用catch,catch子句后面是finally块(清理代码,该块一定会执行)
catch和finally块都是可选的,但只要有try,就必须有其中一个
5.“use strict” p115
章6 对象
1.对象的属性有一个名字和一个值,每个属性有3个属性特性:writable(可写),enumerable(可枚举),configurable(可配置),默认情况下,我们创建的对象三者都可,但很多内置对象拥有只读,不可枚举或不可配置的属性。
2.对象的创建:通过对象字面量,new关键字,Object.create()函数创建
3.对象字面量是一个表达式,每次求值都会创建并初始化一个新的,不一样的对象。(循环体中或被重复调用的函数体内,会创建很多新对象)
4.对象属性值的获取有两种:关联数组(使用方括号和字符串,像访问数组): object["property"] 等价于 object.property(点表示法)
5.关联数组和点表示法有什么区别?
关联数组中的字符串是一种JS数组类型,so可以在程序运行期间修改和创建(字符串是动态的,可以运行时修改),而标识符是静态的,必须硬编码到程序中。如:当方法中的参数是对象的属性时,即需要在运行时才输入内容,则无法用点表示法。p125
6.对象属性在原型对象上的继承:属性赋值原型链上已有的非只读属性时,只会在当前对象上覆盖原先的属性值,而原型链上原本的被继承的对象对应的值是不会被修改的。p126
7.防止查询的对象是null或undefined时报错(null和undefined没有属性)
if(book) {
if(book.author) {
surname = book.author.surname;
}
}
等价于
surname = book && book.author && book.author.surname;(章3.5)
上面可以直接通过?.条件式属性访问:let surname = book?.author?.surname;(章4.1)
8.delete操作符只删除自有属性,不删除继承属性(需从定义属性的原型对象上删除),delete不删除configurable特性为false的属性。
9.如何检查对象是否有一个给定名字的属性?
1)in操作符:(自有属性、继承属性均可测)
let o = { x : 1 } ;
"x"(属性) in o(对象) ; //true
o.hasOwnProperty("toString")
2)hasOwnProperty():继承属性返回false
3)propertyIsEnumerable():(继承、不可枚举返回false)自有属性且该属性的enumerable特性为true才返回true
4)!== undefined可以确保属性不是未定义的,但是:
let o = { x : undefined} ;
o.x !== undefined; //false,存在,但值为undefined
o.y !== undefined; //false ,不存在
而使用in可以区分不存在的属性和值为undefined的属性:
“x” in o;//true,属性x存在
"y" in p;//false,不存在
10.序列化对象:把对象的状态转换为字符串的过程JSON.stringify()序列化和JSON.parse()恢复对象
11.拓展操作符...p137、p144
章7 数组
1.扩展操作符:
1)将可迭代的对象转换为数组或参数
eg.
let a = {x:0,y:0};
let b = {width:100,height:75};
let rect = {...a,...b};
rect.x + rect.y +rect.width +rect.height; //175
2)将已有对象的属性复制到新对象
它是创建数组副本的一种便捷方式:`
let a = [1,2,3];
let copy = [...a];
copy[0] = 0;//修改copy不会影响a的值
a[0] ; //1
3)适用于任何可迭代对象,把任意字符串(可迭代对象)转换为单个字符的数组:
eg.将字符串中重复字符删去
let letters = [..."w ooorld"]; //先将字符串转为了数组
[...new Set(letters)]; //["w"," ","o","r","l","d"]再将数组转换为集合,并用拓展操作符将它转回数组
2. Array.from() 方法期待一个可迭代对象或类数组对象作为其第一个参数,和拓展操作符一样,也是创建数组副本的一种简单方式
3.什么是稀疏数组?
数组中有些索引是没有元素的(元素不存在),其length属性的值比元素个数大。
创建稀疏数组的方法:用Array()构造函数创建 或 直接给数组的索引赋值eg. a[1000]=0;//增加了一个元素,但length变成了1001 或 用delete操作符(delete操作符不会修改length属性)
注:forEach会自动跳过其undefined元素,而delete,for/of,for不会跳过,会输出undefined
4.当将length属性设置为一个小于当前值的非负整数n,任何索引大于或等于n的数组元素都会从数组中被删除
5.一些数组方法:p152-166
forEach()[数组用于自身迭代的函数式方法],
map(),filter(),every(),some(),find(),findIndex(),reduce(),reduceRight(),flat(),flatMap(),concat(),,fill(),copyWithin(),sort(),reverse(),join(),
indexOf(),
arr.includes(给定的值)返回一个布尔值,表示某个数组是否包含给定的值,与字符串的includes方法类似
lastIndexOf()
push()数组尾部添加
pop()删除数组尾部元素,返回删除值
shift()删除数组首部元素,返回删除值
unshift()数组首部添加元素,返回数组新长度
split(),
slice(起始,结束),从已有的数组中返回选定的元素(参数2可选)
splice(起始位置,要删的数量,添加的内容)向/从数组中添加/删除项目,然后返回被删除的项目。(参数3可选)
相比较字符串的常用方法:
match(): 返回所有查找的关键字内容的数组。
replace(): 在字符串中用一些字符替换另一些字符,或替换一个与正则表达式匹配的子串。
split(): 把字符串分割成字符串数组。分割之后的内容全都要,只不过分成多份字符串放进一个数组
substr(): 返回从指定下标开始指定长度的的子字符串
substring(): 提取字符串中介于两个指定下标之间的字符。开始索引到结束索引之间的一个子集, 或从开始索引直到字符串的末尾的一个子集。
slice(): 返回字符串中提取的子字符串。
indexOf(): 返回某个指定的子字符串在字符串中第一次出现的位置
charCodeAt(): 返回指定下标位置的字符的unicode编码,这个返回值是 0 - 65535 之间的整数。(如果是大于255可以判断该字符字节长度为2(中文))
charAt(): 返回指定下标位置的字符。如果index不在0-str.length(不包含str.length)之间,返回空字符串。
toUpperCase(): 把字符串转为大写,返回新的字符串。toLowerCase(): 把字符串转为小写,返回新的字符串。
章8 函数
1.函数赋值给对象的属性,称其为该对象的方法。
2.this
每个调用除了实参还有另一个值,即调用上下文,即this关键字的值。(任何用作方法的函数实际都会隐式收到调用它的对象,就是this的值)eg.函数是在一个对象上被调用或者通过一个对象被调用,则该对象就是函数的调用上下文或this的值。
对象中方法的方法,其this值是全局对象(非严格模式)或undefined(严格模式)。(箭头函数则直接继承对象的this)
3.在语句块中定义的函数只在该块中有定义,对块的外部不可见。
4.箭头函数:用“箭头”分隔函数的参数和函数体,是表达式而不是语句。没有自己的this,arguments,没有prototype属性,so不能用作构造函数。总是继承自身定义所在环境的this值
如果箭头函数的函数体是一个return语句,但要返回的表达式是对象字面量,则必须把该对象字面量放在一对圆括号内,避免解释器分不清花括号到底是函数体还是对象字面量的花括号:
const f = x => { return { value:x }; };//f()返回一个对象
const g = x => ({ value:x });//g()返回一个对象
const h = x => { value : x };//错误,什么都不返回
const i = x => { v:x, w:x };//错误,语法错误
5.call()、apply()、bind()指定调用的this值(对箭头函数不起作用,第一个参数会被忽略)
call():方法使用自己的参数列表作为函数的参数,f.call(o,1,2);
apply():方法期待数组值作为参数, f.apply(o,[1,2]);
eg.要把函数f()作为对象o的方法进行调用(不传参数):f.call(o); f.apply(o);
bind():方法返回一个新函数。除了把函数绑定到对象,还可以柯里化(8.11)p195例子。
6.JS函数定义不会指定函数形参的类型,函数调用也不对传入的实参进行任何类型检查
if(a===undefinded) a=[]
等价于
a = a || [ ];
7.ES6中可在函数形参列表中直接为每个参数定义默认值。并且可以使用前面参数的值来定义后面参数的默认值。eg. const r = (width, height=width*2) => ({width, height});
8.剩余形参:在调用时传入比形参多任意数量的实参的函数,剩余形参前面有3个点,且必须是函数声明中最后一个参数。如果一个函数的最后一个形参是以 … 为前缀的,则在函数被调用时,该形参会成为一个数组,数组中的元素都是传递给该函数的多出来的实参的值。
与7.1的区别:
扩展运算符会“展开”数组变成多个元素,剩余操作符会收集多个元素和“压缩”成一个单一的元素。
9.Arguments对象:剩余形参是ES6引入JS的,ES6之前,变长函数是基于Arguments对象实现的。任何函数体内,标识符arguments引用该次调用的Arguments对象。该对象是一个类数组对象,允许通过数值而非名字取得传给函数的参数值。可以将其替换为...args剩余形参。
10.闭包
11.什么是柯里化?
把接受多个参数的函数变换成接受一个单一参数(最初函数的第一个参数)的函数,并且返回接受余下的参数而且返回结果的新函数的技术。
// 普通的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
12.高阶函数:操作函数的函数,接收一个或多个函数作为参数并返回一个新函数(参数为函数,返回值也为函数)
章9 类
1.类的使用是基于原型的继承。如果两个对象从同一个原型继承属性,则说这些对象是同一个类的实例。类意味着一组对象从同一个原型对象继承属性。(创建一个对象,然后创建继承自它的对象,则继承的对象均是该类的成员)
2.定义一个原型对象,然后使用Object.create()创建一个继承它的对象,则就定义了一个JS类。
3.构造函数用来初始化新对象函数,构造函数调用的关键在于构造函数的prototype属性将被用作新对象的原型。只有函数对象才有prototype属性。使用同一个构造函数创建的所有对象都继承同一个对象,因而是同一个类的成员。
4.类名一般以大写字母开头。(构造函数也是首字母大写)
5.原型对象是类标识的基本:当且仅当两个对象继承同一个原型对象时,它们才是同一个类的实例。而构造函数充当类的公共标识(外在表现)
6.可以使用instanceof操作符测试类的成员关系:r instanceof Range(构造函数是其右操作数);//true
当没有使用构造函数时,想判断某个对象原型链中是否包含指定原型,可使用isPrototypeOf()方法。
7.关于prototype:任何普通的JS函数(不包括箭头函数、生成器函数和异步函数)都可用作构造函数,而构造函数调用时需要一个prototype属性,so每个普通JS函数自动拥有一个prototype属性。该属性的值是一个对象,有一个不可枚举的constructor属性,这个constructor属性的值就是该函数对象。因为构造函数充当类的公共标识,so该constructor属性返回对象的类。p208
eg.
1)let o = new F();
o.constructor === F; //true:constructor属性指定类
2)let F = function() {};//一个函数对象
let p = F.prototype;//一个与F关联的原型对象
let c = p.constructor;//与原型关联的函数
c === F;//true,对任何F,F.prototype.constructor === F
8.使用了class关键字(可看作基础类定义机制的“语法糖”),但得到的对象是一个构造函数。
章10 模块
13. import.meta引用一个对象,该对象包含当前执行模块的元数据。
import.meta.url的主要使用场景是引用与模块位于同一(或相对)目录下的图片、数据文件或其他资源。用URL()构造函数能方便地相对于import.meta.url的绝对URL来解析相对URL。
章11 JavaScript标准库
1.集合与映射(ES6新增了Set和Map类)
11.1.1 Set类:集合,是一组值。集合没有索引或顺序,也不允许重复(唯一,添加已存在的值没有效果,按照严格相等来判断)。Set()构造函数的参数不一定是数组,但必须是一个可迭代对象:
let unique = new Set("Mississippi");//4个元素:“M","i",”s“,“p”
方法有:Set.add(),delete(),size(),has(),clear()
add()接收一个参数,如果传入的是一个数组,则会把整个数组而非数组元素添加到集合中。
has()检查某个值是不是集合的成员
includes()
2.Set对象是可迭代的,so可使用扩展操作符...把集合转换为数组或参数(章7.1)
3.JS集合是无索引的,所以不能按照索引取值,但它会记住元素的插入顺序,始终按照该顺序迭代集合。
11.1.2 Map类:该对象表示一组被称为键的值,每个键都关联(或映射到)另一个值(类似数组,允许用任何值作为”索引“)
11.1.3
WeakMap(弱映射):保持着对它们键值的“弱”引用,它的存在不妨碍其键值被回收,是不可迭代对象,所以其键是不可访问的,是“弱”。
WeakSet(弱集合):实现了一组对象,不会妨碍这些对象被作为垃圾收集。也不可迭代。
11.2 定型数组:定型数组的元素在创建时始终都会被初始化为0,全部都是数值,创建定型数组时必须指定长度(该长度不能再改变)。
11.3 正则表达式:是一种描述文本模式的对象,正则表达式字面量就是包含在一对斜杠(/)字符之间的字符。
************正则表达式字符类:
[...]方括号中的任意一个字符
[^...]不在方括号中的任意一个字符
\w 任意ASCII单词字符
\W 任意非ASCII单词字符
\s 任意Unicode空白字符
\S 任意非Unicode空白字符 (析:空白字符指 “ ”(空格符)、\r(回车符)、\n(换行符)、\t(制表符)和\f(换页符))
\d 任意ASCII数字字符。等价于[0-9]
\D 任意非ASCII数字字符
[\b] 退格字符字面值
************正则表达式重复字符:
{n,m} 匹配前项至少n次,但不超过m次
{n,} 匹配前项n或更多次
{n} 匹配前项恰好n次
? 匹配前项零或一次,即前项是可选的。等价于{0,1}
+ 匹配前项一或多次。等价于{1,}
* 匹配前项零或多次。等价于{0,}
************正则表达式锚点字符:
^ 匹配字符串开头
$ 匹配字符串末尾
\b 匹配单词边界
\B 匹配非单词边界的位置
11.4 日期与时间:
new Date();//当前时间,若传入一个数值参数,该构造函数会被解释为自1970年至今经过的毫秒数,若传入一个或多个整数参数,会被解释为本地时区的年月日时分秒和毫秒。
Date API 中,每年第一个月对应数值0,每月第一天对应数值1,若省略时间字段,Date()构造函数默认它们都为0,将时间设置为半夜12点。
****时间戳:时间戳是以毫秒为单位的,静态的Date.now()方法返回当前时间的时间戳。
Date类定义的valueOf()方法返回的是日期的时间戳。
11.5 Error类:JS的throw和catch语句可以抛出和捕获任何JS值,包括原始值。在创建Error对象时,该对象可以捕获JS的栈状态,如果异常未捕获,则会显示包含错误消息的栈跟踪信息。(有子类,以便触发ES定义的一些特殊类型的错误p277)
Error对象有两个属性:message和name(值始终是Error)还有一个toString()方法
11.6 JSON序列化与解析
当程序要保存数据或需要通过网络连接另一个程序传输数据时,必须将内存中的数据结构转换为字节或字符的序列才可以被传输或保存。将数据结构转换为字节或字符流的方式被称为序列化。
序列化数据最简单的方式是使用JSON的序列化格式。
JSON.stringify()【返回一个字符串值】和JSON.parse()【重建原始数据结构】支持JSON序列化和反序列化。
11.7 URL API:使用new URL()构造函数创建URL对象时,要传一个绝对URL作为参数。也可以将一个相对URL作为第一个参数,将其相对的绝对URL作为第二个参数。p290
11.8 计时器:setTimeout()函数:只会被调用一次。setInterval()函数:重复调用,每隔指定时间(是个近似的毫秒值)就调用一次指定函数。两者都返回一个值,该值的唯一作用:若该值保存在变量中,可以将其传给clearTimeout()或clearInterval()取消调用。
章12 迭代器与生成器
1.迭代器原理:
三个不同的类型:
1)可迭代对象:任何具有专用迭代器方法且该方法返回迭代器对象的对象
2)迭代器对象:任何具有next()方法且该方法返回迭代结果对象的对象
3)迭代结果对象:具有属性value和done的对象
2.要迭代一个可迭代对象,首先要调用其迭代器方法获得一个迭代器对象,然后重复调用该迭代器对象的next()方法,直至返回done属性为true的迭代结果对象。
3.迭代器方法用符号Symbol.iterator作为名字p296
4.生成器:是一种用新ES6语法定义的迭代器,适合要迭代的值不是某个数据结构的元素,而是计算结果的场景。
5.创建生成器首先必须定义一个生成器函数function*(简写可以直接一个*)
//调用该函数不会运行下面的代码,而只会返回一个生成器对象。调用该对象的next()会开始运行,直至一个yield语句为next()方法提供返回值。
function* one(){yield 2;yield 3;yield 5;yield 7;
}
//调用生成器函数得到一个生成器。
let primes = one();//生成器是个迭代器对象可迭代回送的值
primes.next().value; //2
primes.next().value; //3
...
primes.next().done; //true//生成器有一个Symbol.iterator方法,因此也是可迭代对象
primes[Symbol.iterator]();//primes//可像使用其他可迭代对象一样使用生成器
[...one];//2,3,5,7 扩展操作符
let sum = 0;
for(let prime of one()){
sum += prime;
sum; //17
}
注:不能使用箭头函数语法定义生成器函数。
yield*关键字迭代可迭代对象并回送得到的每个值(yield*和yield都只能在生成器中使用,yield是一个表达式,可以有值)
6.生成器的基本特性是可以暂停计算,回送中间结果,然后在某个时刻再恢复计算。
7.迭代器和生成器中的return()方法是用来提前退出而不是返回值。
章13 异步JavaScript
1.ES6新增的期约(Promise)是一种对象,代表某个异步操作暂不可用的结果。(一次异步计算的未来结果,每个通过then()方法注册的函数都只会被调用一次)
2.关键字async和await是ES2017中引入的,为简化异步编程提供了新语法,允许开发者将基于期约的异步代码写成同步的形式。
3.异步迭代器和for/await循环是ES2018引入的,允许在看起来同步的简单循环中操作异步事件流。
4.JS异步编程是使用回调实现的,回调就是函数,可以传给其他函数。
5.异步网络请求:p309
6.期约对象是在异步请求结果待定期间返回的,该期约对象有个实例方法then(),回调函数直接传给了then(),当HTTP响应到达时,响应体会被解析为JSON格式,解析后的值会被传给作为then()的参数的函数。
7.期约对象在响应体未到达前就必须返回(比异步计算早),即计算是在返回期约对象之后执行的,so没办法让该计算像以往那样返回一个值,或抛出一个可以捕获的异常。
8.期约术语:
“兑现fulfill”,then()方法调用时返回一个新期约对象,该新期约对象在传给then()的函数执行结束才兑现。
“拒绝reject”,
“待定pending”,
“落定settle”
//期约2在任务2结束时兑现,期约3在期约2兑现时才被调用
fetch(theURL)//向URL发送请求并返回期约1,设该请求为任务1.then(callback1)//调用期约1的then方法,传入callback1函数,,在期约1兑现时被调用。任务2,返回期约2,任务2在callback1被调用时(返回期约1兑现后的值)开始.then(callback2);//任务3,返回期约3,在期约2兑现时被调用
解析:fetch发送一个异步请求,这时该请求设为任务1,请求一发送就会立马返回一个期约1。当该任务1完成,则会兑现期约1,该期约1是第一个then()中的callback1回调函数返回的值,也就是该值一得到,第一个then就会被当成任务2开始执行,执行完就兑现一个期约2,期约2是第二个then的参数callback2的值,该值得到就会触发第二个then的执行,称为任务3。任务3完成时(正常结束的话),期约3也被兑现,到这里已经不再需要给期约3注册回调了,so它落定时啥也不发生,异步计算链结束。
9.期约链:以线性then()方法调用链的形式表达一连串异步操作。
10.async和await关键字(相当于.then().catch()):接收基于期约的高效代码并隐藏期约。await关键字接收一个期约并将其转换为一个返回值或抛出一个异常。只能在以async关键字声明的函数内部使用await关键字
章14 元编程
1.常规编程是写代码去操作数据,元编程是写代码去操作其他代码
2.JS的每个属性都有3个关联的特性:
可写(writable):指定是否可以修改属性的值
可枚举(enumerable):指定是否可以通过for/in循环和Object.keys()方法枚举属性
可配置(configurable):指定是否可删除、修改属性
章15 浏览器中的JavaScript
15.2
1.什么是事件?
事件是文档和浏览器窗口中发生的特定的交互瞬间。与浏览器中web页面进行某些类型的交互时,事件就发生了。浏览器会在文档、浏览器或者某些元素或与之关联的对象发生某些值得关注的事情时生成事件
什么是事件处理程序?
响应某个事件的函数就叫做事件处理程序(别名:事件侦听器)。 事件处理程序的名字是以"on"开头,所以像click的事件处理程序就是"onclick"。 load的事件处理程序就是onload。
2.注册事件处理程序的两种方式:1)设置作为事件目标的对象或文档元素的一个属性;2)把处理程序传给该对象或元素的addEventListener()方法
3.事件处理程序属性的名字都由“on”和事件名称组成,eg.onclick,onload等必须全部小写,该方式假设事件目标对每种事件最多只有一个处理程序
4.addEventListener()方法不会重写之前注册的处理程序,任何可以作为事件目标的对象(Window、Document对象和所有文档元素)都有该方法,有三个参数(第三个参数,可传入一个对象p387,该对象的capture属性为true时或者参数直接为true时函数会被注册为捕获事件处理程序,在删除事件时也需要为true,否则为事件冒泡)p386
5.目标事件是Document或其他文档元素,大多会沿DOM树向上“冒泡”,目标父元素的事件处理程序会被调用,然后注册在目标祖父元素上的事件处理程序会被调用,so只需要在它们的公共祖先元素上注册一个事件处理程序,然后在其中处理事件,eg.<form>元素上注册个“change”事件处理程序,就不用在表单每个元素上注册。
6.事件传播三阶段:事件捕获阶段、处于目标阶段、事件冒泡阶段。首先发生的事件捕获为截获事件提供机会,然后是实际的目标接收事件,最后一个阶段是事件冒泡阶段,可以在这个阶段对事件做出响应。
7.事件取消的两种方式:
浏览器对很多用户事件都会做出反应,像触屏滑动时浏览器就滚动等,若为这些事件注册了事件处理程序,就可阻止浏览器执行其默认动作,为此需调用事件对象的preventDefault()方法(第三个参数中的passive属性为true的话会导致该方法无效),或调用事件对象的stopPropagation()方法取消事件传播。
8.派发自定义事件:
一个有addEventListener()方法的对象是一个“事件目标”,则该对象也会有dispatchEvent()方法,用CustomEvent()构造函数可创建自定义事件对象,再传给dispatchEvent() p391
9.操作DOM
1)每个Window对象都有一个document属性,引用一个document对象(窗口的内容)
2)DOM中的选择符(selector)用来描述文档中元素或元素的集合,querySelector()[返回文档中第一个匹配的元素,没有则返回null]和querySelectorAll()[返回文档中所有匹配元素]方法用来找文档中与指定选择符匹配的元素。
3)元素的选择方法p394
https://www.cnblogs.com/haoqirui/p/10550007.html
4)文档的结构与遍历:Node属性,这套API对于文档中文本的变化很敏感,换行符也会被当成Text节点
5)HTML元素由标签名和一组称为属性的名/值对构成,Element类定义了通用的
setAttribute()、
hasAttribute()
removeAttribute()方法,用于查询、设置、检测、删除元素的属性
元素名.getAttribute(属性名)返回指定html元素里的某个属性(如a标签)的属性值(的target值)。区别于
window.getComputedStyle(元素,伪类(可选))方法获取css样式的所有属性,并返回一个 CSSStyleDeclaration 类型的对象,该对象是下面方法的对象
CSSStyleDeclaration.getPropertyValue(属性名,如color)方法获取对应元素的相对应属性的值
6)把HTML属性转换为JS属性,需要全部小写,(连字符分隔(在JS中是减号)的属性将映射为驼峰式属性名)。若多个单词组成,则第二个单词开始每个单词首字母大写。但事件处理程序属性要全部小写,如onclick
7)不能用delete操作符删除HTML属性,要用removeAttribute()方法
8)classList属性将class属性作为一个列表来操作,像个类名的集合,且定义了add(),remove(),contains()【判断类名是否存在】和toggle()方法p400
9)dataset属性:“数据集”属性
10)textContent属性:可以取得元素的纯文本内容(Text节点),插入修改纯文本
而innerText属性有一些少见和复杂的行为,如试图阻止表格格式化。(尽量不用)
``innerHTML:获得或插入一个元素内部的所有内容,包括标签、文本代码
11)创建、插入、删除节点
createElement()创建新元素,
append()把参数添加到孩子列表的末尾,prepend()把参数添加到孩子列表的开头,after(),before()分别可以在包含元素的孩子列表中间插入。什么区别呢?看下:
***append()
let a = document.getElementById("e");
a.append(" world");
console.log(a);
***after()
let a = document.getElementById("e");
a.after(" world");
console.log(a);
解释:通过上面两个,可看出append()是在节点里面的内容末尾插入内容,而after()是在整个节点后面换行并插入内容,且控制台无法查看到该内容。另外两个方法类似。
12)JS中设置HTML中的style属性,只针对自己的行内样式,样式必须加引号,有单位的必须加单位,如px表示像素,pt表示点。(要将CSS属性设置计算值时,需在计算表达式后面加上单位)
10.操作CSS
1)CSS动画和事件
2)文档元素的位置以CSS像素度量,x像右,y向下增大
“视口”:浏览器窗口中实际显示文档内容的区域(坐标随窗口滚动而变化)
“文档”:文档大小(滚动之后,和视口的坐标系就不同了。)
3)CSS像素(px,js中的像素,缩放会改变大小),设备像素比dpr=物理像素(设备、硬件像素)/CSS(软件)像素【看成一个css像素=dpr个物理像素】p413
dpr=2,代表每个软件像素实际上是一个2*2硬件像素的网格(两个硬件像素填充一个CSS像素)
4)getBoundingClientRect()用于获取某个元素相对于视口的位置及元素的大小集合。返回的对象中有top, right, bottom, left,height,width等属性。无参数。
返回值类型:
rectObject.top:元素上边到视窗上边的距离;
rectObject.right:元素右边到视窗左边的距离;
rectObject.bottom:元素下边到视窗上边的距离;
rectObject.left:元素左边到视窗左边的距离;
5)
document对象表示整个HTML页面,同时它也是window对象的一个属性,nodeType为9,一个页面有且只有一个。而Element对象的nodeType为1,它表示页面中的那些标签元素,比如你用getElementById('myId')获取的元素。document的chlidNodes包含Element,但Element不包含document。Window对象封装了窗口标题、工具按钮、地址栏、状态栏等,这些窗口的组成部分,也被定义为浏览器对象,都是window的成员对象,因此,构成一种层次结构,也就是浏览器对象模型(Browser Object Model)
6)关于视口、内容大小、滚动位置
window.innerWidth,innerHeight获得视口大小
移动设备优化:在<head>中使用<meta name="viewport">标签为页面设置视口宽度
文档宽高获取:使用document.documentElement的getBoundingClientRect()方法或offsetWidth和offsetHeight属性(返回CSS像素大小)
文档在视口中的滚动位移获取:window.scrollX和window.scrollY(只读,不能通过设置它们的值来滚动文档),滚动文档应该用window.scrollTo()
关于滚动的更多属性p415
11.Web组件
Web组件是在JS中定义的,在HTML中使用Web组件,需要包含定义该组件的JS文件。p417
Web组件不能使用自关闭标签定义,不能写成<search-box/>,HTML文件必须包含开标签和闭标签。
Web组件需要子组件时会放在插槽(slot)中,slot属性是对HTML的扩展,用于指定把哪个子元素放到哪里。
8)什么是shadow DOM?作用?
直译为潜藏在黑暗中的 DOM 结构,也就是我们无法直接控制操纵的 DOM 结构。shadow-dom
其实是浏览器的一种能力,它允许在浏览器渲染文档(document)的时候向其中的 Dom 结构中插入一棵 DOM 元素子树,但是特殊的是,这棵子树(shadow-dom)并不在主 DOM 树中。
以 w3c 上的一个 <video>
例子为例,我们仅仅是填写了一个空白的标签,再加上 src
属性里填上视频地址,就可以播放视频了:我们仅仅填写了一行代码,却拥有比这行代码更多的功能,譬如暂停,播放,音量控制,全屏按钮,进度条等等。这些就是影子DOM封装好的内容。
在控制台的shadow-root中可看到并操作属性。
12.SVG是可伸缩矢量图形,是一种图片格式,SVG“图片”是一种对绘制期望图形的精确的、分辨率无关(“可伸缩”)的描述。它通过XML标记语言描述。
什么是XML语言?
XML(扩展性标识语言。)它只是用来创造标记语言(比如HTML)的元语言。XML不是HTML的升级,它只是HTML的补充。不能用XML来直接写网页。即便是包含了XML数据,依然要转换成HTML格式才能在浏览器上显示。
1)<canvas>与图形:有强大的绘图API。使用画布(canvas)绘图要调用方法,使用SVG创建图形需构建XML元素树。
2)网页中包含的音频和视频---Audio API
使用<audio>和<video>标签播放音频、视频
创建方法:通过document.createElement()或者直接使用Audio()构造函数动态创建<audio>元素。播放媒体不一定要把创建的元素添加到文档中,只要调用其play()方法。
cloneNode()方法可当用户快速点击时,同时播放多个重叠的音效。会有多个Audio元素。(由于Audio元素并未添加到文档中,so播放结束后会被当做垃圾清理)
13.Window和document对象的location属性引用的都是Location对象,该对象表示当前窗口显示文档的URL,提供了在窗口中加载新文档的API。p455
Location对象中的:
href属性以字符串形式返回整个URL,和toString()一样
hash属性返回URL的“片段标识符”部分(如果有),包含#和一个元素ID
search属性返回URL中以问号开头的部分,通常是一些查询字符串
14.fetch规范(传给它一个URL,它返回一个期约 章13)
- 当接收到一个代表错误的 HTTP 状态码时,从 fetch()返回的 Promise 不会被标记为 reject, 即使该 HTTP 响应的状态码是 404 或 500。相反,它会将 Promise 状态标记为 resolve (但是会将 resolve 的返回值的 ok 属性设置为 false ),仅当网络故障时或请求被阻止时,才会标记为 reject。
- fetch()的第一个参数是一个用于指定URL的字符串或URL对象。第二个参数用于提供额外选项,包括请求头部,请求方法或请求体。
15.跨源请求
同源:协议、主机名、端口都相同
*想中断已经发出的fetch()请求,需在创建请求前先创建一个AbortController对象(new一下),即中断控制器,想中断请求时调用控制器对象的abort()方法
16.服务器发送事件p473
17.WebSocket
WebSocket API是一个复杂,强大的网络协议对外暴露的简单接口。服务器端和客户端可以进行双向发送。
https://zhuanlan.zhihu.com/p/74326818
18.客户端存储:
1)Web Storage:其API包含localStorage、sessionStorage对象(引用Storage对象),本质上是映射字符串键和值的持久化对象(适合存储大量数据)
1.1)Storage对象必须是字符串(只能存储字符串,而数值会自动转换为字符串),存储的属性是持久化的。删除所有属性用clear()、删除属性用delete操作符,可被getItem()、setItem()、deleteItem()代替
1.2)localStorage:刷新页面仍能访问属性中保存的值,存储的数据为永久性的,不同浏览器访问数据存储相互获取不到。数据发生变化时,在其他可见的window对象(不包括导致该变化的窗口)上触发“storage”事件(可看作广播机制)。
*注册“storage”事件:使用window.onstorage事件属性或调用window.addEventListener()并传入“storage”
1.3)sessionStorage:窗口或标签页关闭之后,数据都会被删除(特殊:打开最近关闭的标签页并恢复上次浏览会话时,其生命周期拉长)。不同标签页相互隔离,不能读取或重写另一标签页的数据。
2)Cookie:古老的客户端存储机制,该API难实现,只适合保存少量数据。默认的生命周期也是只在会话期间,但可指定其max-age属性。数据会自动在浏览器和web服务器之间传输(服务器端脚本可读写存储在客户端的cookie值)。cookie默认是不安全的(即在普通不安全的http连接上传输),但可在HTTPS或其他传输协议上安全传输,通过secure属性设置(布尔值)。其path属性和domain属性用来设置可以共享该cookie的网页url路径前缀p484
3)IndexedDB:异步API,可访问支持索引的对象数据库,每个源可以有任意数量的IndexedDB数据库,每个数据库的名字必须在当前来源下唯一。(IndexedDB中,数据库就是一个名为对象存储的集合,对象存储中存储的是对象)
19.工作线程与消息传递
Worker类:该类的实例代表与主线程和事件循环同时运行的线程。
Worker运行于独立的运行环境,有独立的全局对象,与主线程只能通过异步消息机制通信。
Worker对象的方法:postMessage()、addEventListener()、removeEventListener()、terminate()p491 importScripts()同步地按顺序加载并执行文件 close()、preventDefault()
postMessage()方法:调用该方法会触发关联消息端口的”message“事件。:
对于工作线程,它为两个独立的线程提供了无须共享内存就能通信的安全机制;
对于窗口,为两个独立的来源提供了安全交换消息的受控机制。
20.防御XSS安全漏洞、Content-Security-Policy HTTP头部、CSP、CORS跨源
章16 Node服务器端 JavaScript
1.什么是Node?
一个基于Chrome V8引擎的JavaScript运行环境,一个让JavaScript运行在服务端的开发平台。可以 让JS程序读写文件、执行子进程以及实现网络通信。
2.特点:由其默认异步的API赋能的单线程基于事件的并发能力。
3.CommonJS模块指Node的模块系统:使用require()函数向模块中导入值,用exports对象或module.exports属性从模块中导出值。(JS代码保存在.cjs结尾的文件中)p230章10也有
ES6模块使用import和export声明(JS代码在.mjs结尾的文件中)、
若没有上面的两个文件,Node会在同级目录及所有包含目录中查找一个最近的名为package.json的文件,检查其中JSON对象的顶级type属性,type属性的值为module,则按照ES6模块来加载,值为commonjs,按CommonJS模块加载。
4.什么是callback回调函数?
调用一个函数并传一个函数c给它,它执行完之后将c函数调用并返回给我,则该c函数就是回调函数。https://zhuanlan.zhihu.com/p/22677687
5.Node中的流是什么?https://www.cnblogs.com/yinhaiying/p/10784880.html
流数据:就是字节数据,在应用程序中各种对象之间交换与传输数据的时候,总是先将该对象中所包含的数据转化为字节数据也就是流数据。再通过流的传输,到达目的对象后,再将流数据转化为该对象中可以使用的数据。
流:在一个应用程序中,流是一组有序的,有起点和终点的字节数据(流数据)的传输手段。
作用:处理数据的算法中,需要先把所有数据读到内存中,进行处理,然后再把数据写到某个地方。而流的算法可以把数据分割成小块,内存中不会保存全部数据,这样就不需要使用copyFile()函数(必须分配足够的内存来保存文件的全部内容,且该函数不能在读完旧文件之前写新文件)
6.管道
https://blog.csdn.net/u011413061/article/details/50311457
章17 JavaScript工具和扩展
1.ESLint检查代码
2.Prettier格式化代码
3.Jest做单元测试
4.npm管理依赖包
5.使用Babel转译:是一个编译工具,“转译器”,将用现代语言特性编写的JS代码编译为旧版本的代码,兼容只支持ES5的浏览器
6.JSX:JS中的标记表达式,使用HTML风格的语法定义元素树,eg. let line = <hr/>;
使用了JSX后,需要用Babel把JSX表达式编译为常规JS
7.Flow检查类型:Flow是一个相对窄的语言扩展,只为JS代码添加类型注解,然后可以运行Flow工具分析代码、报告类型错误。
等修复错误并准备好运行代码之后,可以使用Babel从代码中剥离Flow类型注解,返回标准JS代码