emmm….今天是2025年4月23日,北邮图书馆。对于一位即将备战考研的大三计科学生,一直以来对前端技术怀有热情,作为一个能将产品最能直面用户、且最直接的一个岗位,一直带给我无限的好奇,崇尚那种所见即所得的视觉冲击、羡慕那些一眼就能留住用户吸引眼球的界面,于是便想要一探究竟,所以从大二开始从基本html5、css3 到 JavaScript 以致现在学的React、React Native,但是学到现在,感觉对于JavaScript总是不能灵活运用,虽然会写,但我深知我对这个语言的掌握程度远远不够。。。

我决定要将JavaScript完全掌握,在网上寻寻觅觅了很多资料,最终选择了《JavaScript权威指南》这本书,正如书名所说,这是业界前端开发者普遍认为的权威指南,从今天开始,我将要坚持每天半小时来阅读这本书,并且将我的学习心得记录在这篇博客下。

4月

4月23日

第三章类型、值和变量

今天学习了文本字符串部分的内容

  1. 字符串是16位值的不可修改的有序序列,其中每个值都表示一个Unicode字符。对于码点超出16位的Unicode字符会被编码为两个16位值序列(代理对),length属性为2。但在ES6中,for/of迭代的是字符不是16位值
  2. 字面量用单引号,双引号,反引号,其中任意一种都可以包含另外两种引号,反斜杠\可以用于将多行显示成一行,\n用于将一行分成多行
  3. 学习了常见的转移序列\t \n \unnnn \u{n}
  4. 学习字符串的常见方法,包括:

(1)取得字符串一部分(2)搜索字符串index (3)布尔值搜索(4)创建字符串修改版本 (5)访问个别16位值

(6)字符串填充(7)删除空格 (8)未分类其他


4月24日

第三章类型、值和变量

今天学习内容如下:

1.模板字面量通过使用${}来当做JavaScript表达式在字符串中使用,还有标签化模板字面量,如果开头的反引号前面有一个函数名,那么模板字面量中的文本和表达式的值将作为参数传给这个函数,即反引号的开头和末尾充当函数调用的圆括号

2.模式匹配,JavaScript定义了一种正则表达式的数据类型(RegExp)用于描述和匹配文本中的字符串模式。不是基础类型。一对斜杠之间的文本构成正则表达式字面量。RegExp对象定义了一些有用的方法,如test(),字符串也接收RegExp参数的方法,如search(),match()replace(),split()

3.布尔值

转为false的值有:undefined、null、0、-0、NaN、””(空串)

其他所有值,包括对象和数组都是true

4.null和undefined

typeof null --> Object

typeof undefined --> undefined

undefined表示一种系统级、意料之外或类似错误的没有值,null表示程序级别、正常或意料之中的没有值。

5.Symbol符号

要获取一个Symbol值,需要调用Symbol()函数,这个函数永远不会返回相同值。

JavaScript定义了一个全局符号注册表,Symbol.for()函数接收一个字符串参数,字符串也能通过Symbol.KeyFor()得到

6.不可修改的原始值和可修改的对象引用


4月26日

第三章类型、值和变量

今天学习的内容:

1.类型转换:JavaScript类型转换表,包含转换为字符串、数值、布尔值。尤其转换成数值较为微妙。字符串开头和末尾可以有空格。

2.转换与相等:注意==的判定标准,相当灵活。比如:

null == undefined

"0" == 0

0 == false

"0"==false

​ 都为true

3.显式转换。使用Boolean()、Number()、String()函数,除了null 、undefined之外所有值都有toString()方法,与String()结果相同。

​ 隐式类型转换: x + "" => String(x) +x => Number(x) x-0 => Number(x) !!x => Boolean(x)

​ Number类定义的toString()方法可以接受参数,指定基数,默认为 10。除此之外,Number类还有其他把数值换成字符串的方法:

toFixed()可以指定小数点后面的位数。

toExponential()使用指数计数法将数值转换成字符串,指定小数点后面位数

toPrecision()指定有效数字个数转换字符串。

​ 还有parseInt() 和 parseFloat()

4.对象到原始值的转换:

​ 对象到原始值的转换有三种基本算法:偏字符串、偏数值、无偏好。

​ 了解toString() valueOf()方法

​ 对象到原始值转换算法:

  • 偏字符串算法先尝试toString()方法,如果有定义且返回原始值,则使用该原始值,否则尝试valueOf()方法

  • 偏数值算法先尝试valueOf()方法,在尝试toString()方法。

  • 无偏好算法取决去转换对象的类。Date使用片字符串,其他类使用偏数值。


4月27日

第三章类型、值和变量

今天学习的内容是变量声明与赋值

1.使用etconst声明:let声明时可以不为其赋初值,默认undefined;但const必须在声明时初始化常量

2.何时使用const:只对那些必须不变的值使用const;对任何不会变化的值使用const,避免意外修改。

3.变量与常量作用域:letconst具有块作用域,如果声明位于顶级,称其为全局变量或常量,具有全局作用域。

4.重复声明:在嵌套作用域声明同名变量是合法的(不推荐)

5.使用var声明变量:

​ (1)var声明不具有块作用域,仅限于包含函数的函数体,无论在函数中嵌套层次多深。

​ (2)在函数体外部声明var,则会声明一个全局变量,通过var声明的变量被实现为globalThis的属性,但这个属性不能用delete删除。

​ (3)var多次声明变量是合法的

​ (4)var声明会有作用域提升(hoisting)。使用var声明时,该声明会被提高到包含函数的顶部,变量的初始化还是在代码所在位置完成。所以在初始化或声明的代码之前使用变量,值可能是undefined但不会报错。

6.使用未声明的变量:在严格模式下,使用未声明的变量,代码会运行错误。在严格模式外,将一个值赋给未使用let、const、var声明的名字,会创建一个全局变量,无论嵌套多少次都是全局的,这也是一个缺陷。


4月28日

第三章类型、值和变量、第四章表达式和操作符

今天学习的内容是解构赋值和表达式

1.解构赋值:

​ (1)解构数组值:let [x,y] = [1,2];

​ 解构赋值两边的变量数量不一定相等,左侧多余的变量设置为undefined,右侧多余的值会被忽略,左侧变量可以用逗号跳过右侧的某些值。

​ 解构赋值可以把剩余的变量收集起来:let [x, ...y] = [1,2,3,4];

​ 支持嵌套。

​ (2)解构对象值:let {r,g,b} = {r: 0, g:0, b:0, a:0};

​ 为了方便可以使用与属性名相同的变量名。但是不是必需,如:let {r: R, g:G, b:B} = {r: 0, g:0, b:0, a:0};

​ 属性名在冒号的左侧,变量名在右侧。

​ 可以通过翻转赋值来验证是否正确。

2.表达式:

​ 主表达式、对象和数组初始化程序、函数定义表达式,都比较基础

3.属性访问表达式:

​ 两种访问属性的语法:expression.idetifier / expression[expression]

​ 条件式属性访问:expression?.identifier / expression?.[expression]

​ 通过?.访问类似一种短路操作,要是不通后面就不经过了,即[]内的表达式也不会执行。


5月

5月1日

第四章表达式和操作符

今天学习内容如下:

1.调用表达式,在方法调用中,作为属性访问主体的对象或数组在执行函数体时会变成this关键字的值。

2.条件式调用,可以使用?.()来调用函数,如果括号左侧是nullundefined或者其他任何非函数值,都会抛出TypeError。而使用条件式调用使整个表达式求值为undefined,不会抛出异常

3.操作符概述:操作符表P66-67。详情请参考 https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Guide/Expressions_and_operators

4.操作符结合性:左结合性意味着操作从左到右执行,加号、减号等等w = x-y-z --> w = ((x-y)-z)

​ 右结合性意味着操作从右到左执行,幂、一元、赋值、三元条件操作符。y = a**b**c --> y=(a**(b**c))

5.算数表达式中的+操作符:

​ 如果有一个操作数是对象,将对象转换成原始值。转换之后,如果有对象是字符串,另一个也转换字符串,否则都转换成数值计算(或NaN)。


5月2日

第四章表达式和操作符

4.9关系表达式:

1.相等和不相等操作符:

​ === 称为严格相等操作符, == (允许类型转换)相等操作符 ,!== 和 != 刚好相反。

​ 建议在实践中使用===和 !==。

严格相等

  • 如果两个值类型不同,则不相等。
  • 如果两个值都是null或者undefined,则相等。
  • 如果两个值都是布尔值truefalse,则相等
  • 如果一个或两个值都是NaN则不相等(NaN不等于任何其他值,包括自己,可以用x!==x检验)
  • 如果两个值都是数值且值相同,则相同(-00相等)
  • 如果两个值都是字符串且相同位置包含完全相同的16位值,则相等。
  • 如果两个值引用同一个对象数组、对象或函数,则相等。否则即使两个对象有完全相同属性,也不相等

基于类型转换的相等

  • 如果两个值类型相同,则按照前面的规则测试是否相等。如果严格相等则相等,如果不严格相等,则不相等
  • 如果两个值类型不相同,==仍然可能认为相同。
    • 如果一个值是null,另一个是undefined,则相等
    • 如果一个值是数值,另一个是字符串,则把字符串转换成数值,再比较数值
    • 如果有一个为true,把他转换成1,如果有个值为false,则转化成0,再比较。
    • 如果一个值是对象,另一个值是数值或字符串,使用转换原始值算法,再比较。

2.比较操作符

比较转换规则:

  • 如果有操作数是对象,使用valueOf()方法转换原始值,否则就使用toString()
  • 如果转换后两个都是字符串,则使用字母表顺序比较
  • 如果两个至少有一个不是字符串,则都转换成数值来比较。

+比较偏向于字符串,比较操作符偏向于数值。

3.in操作符

期待右侧操作符是对象,如果左侧是右侧的对象属性名,返回true

let point = {x:1 , y:1}; "x" in point,“toString" in point;

let data = [1,3,5,7]; "0" in data; 3 in data; “0”,3是索引,不是元素。

4.instanceof操作符

期待左侧是对象实例,右侧操作数是对象类标识

let d = new Date();

d instanceof Date


5月4日

第四章表达式和操作符

1.逻辑操作符

逻辑与(&&)

&&并不总返回truefalse

首先对第一个操作数求值,如果左边的值是假植,则整个表达式的值一定是假值,&&直接返回左侧的值;

如果左侧的值是真值,则整个表达式的值取决于右侧的值,如果右侧值是真值(假值),则表达式为真值(假值),因此,在左侧为真值,返回右侧的值。

if (a==b) stop(); --> (a==b) && stop();

逻辑或

与逻辑与的理解相似。let max = maxWidth || preferences.maxWidth || 500;

如果左值已经决定整个表达式的值,就直接返回,没有必要求右值,这种行为有时候也称为短路

逻辑非

与&&和||不同,!操作符将操作数转换成布尔值后取反得到布尔值。

2.求值表达式

eval()解释源代码字符串。

如果传入非字符串,返回这个值。如果传入字符串,会尝试当成JavaScript代码解析。并且它会使用调用它的代码的变量环境。

全局eval(),直接使用eval()叫做“直接eval”,使用的是调用上下文的变量环境。其他调用方式,都会使用全局对象作为变量环境。

严格eval(),在严格模式或代码字符串有“use strict”,eval()会基于私有变量环境进行局部求值,被求值的代码可以查询和设置局部变量,但是不可以定义新的变量或函数。


5月5日

第四章表达式和操作符

1.先定义??

如果其做操作数不是null或者undefined就返回该值,否则就会返回右操作数的值。??也是短路的,只有第一个操作数求值为null或者undefined才会求值第二个操作数。

??&& ||操作符类似,优先级相等,如果混用请用圆括号说明优先级。

2.typeof操作符

一元操作符,表明操作数的类型

typeof undefined --> undefined

typeof null --> object

typeof true 或 false --> boolean

任意函数 --> function

任意非函数对象 --> object

3.delete操作符

尝试删除操作数指定的对象属性或数组元素。

let o = {x:1 , y:2}; delete o.x

let a=[1,2,3]; delete a[2];

如果删除数组元素,并不会改变数组长度,导致数组是一个稀疏数组

如果操作数不是左值,什么也不做且返回true;并非所有属性都可以删除,不可配置属性不可删除

在严格模式下,delete操作数如果是未限定操作符,比如变量,函数等等导致SyntaxError,严格模式下删除不可配置属性,会抛出TypeError

4.await操作符、void操作符、逗号操作符不做过多介绍,详情见P90

5月7日

第五章 语句

1.表达式语句:赋值语句、函数调用语句。

2.复合语句与空语句:语句块{}内可以写多个语句,组合成一个复合语句, 空语句;只有这一个符号。

3.条件语句:

if:默认情况下else子句属于最近的if语句,但是防止混淆,建议使用花括号

else if

switch:注意用break来结束每个case,也可以使用return 语句。case匹配使用的是===全等操作符。避免使用包含副效应的case表达式,比如赋值表达式或函数调用表达式。

4.循环语句

whiledo whilefor

5月9日

第五章 语句

1.for/of

ES6定义了一种新的循环语句,专门用于可迭代对象,例如数组、字符串、集合、映射。

for/of与对象:对象默认不可迭代。使用for/of容易TypeError。如果迭代对象属性,可以使用for/in或者Object.keys()

1
2
3
4
5
6
let o = {x:1, y:2, z:3};
let keys = "";
for(let k of Object.keys(o)){
keys += k;
}
keys // => "xyz"

​ 如果想要对象每个键的值。Object.values()

1
2
3
4
5
6
let o = {x:1, y:2, z:3};
let sum = 0;
for(let v of Object.values(o)){
sum += v;
}
sum //=> 6

​ 如果既要对象的键又要值

1
2
3
4
5
6
let o = {x:1, y:2, z:3};
let pairs = "";
for(let [k,v] of Object.entries(o)){
pairs += k+v;
}
pairs //=> "x1y2z3"

for/of与字符串:逐字符按照Unicode码点迭代。字符串”I❤️y”长度为4,因为表情符号要两个UTF-16字符表示,但是循环体迭代3次。

for/of与Set和Map:

​ 循环体对集合中的每个元素都会运行一次。

​ Map会迭代键值对,每次迭代,迭代器都会返回一个数组,第一个元素是键,第二个元素是值。

2.for/in

for/in后面可以是任意对象,循环指定对象的属性名

for(variable in obejct) statement

首先求值object表达式,如果是null或者undefined会跳转下一表达式,否则解释器会对每个可枚举对象属性执行循环体。

可以用下面代码项对象所有属性赋值到数组中

1
2
3
let o = {x:1, y:2, z:3}
let a = [], i = 0;
for(a[i++] in o) ;//空循环体

对于数组,数组索引是数组的属性。

手写代码定义的所有属性和方法都是可枚举的,但是也有一些不可枚举的属性。

5月12日

第五章 语句 - 跳转语句

1.语句标签

identifier: statement

给循环加标签:

1
2
3
4
mainloop: while(token !== null){
//...
continue mainloop;
}

identifier可以是任何标识符,标签与变量和函数不在同一个命名空间,因此同一个标识符既可以作为语句标签,也可以作为变量名或函数名。如果两条语句没有嵌套关系,标签可以同名,否则不可同名。

2.break

switch和循环中使用,JavaScript允许break关键字后跟一个语句标签,会跳转到指定标签的包含语句的末尾或终止该语句。

break与labelname之间不可以出现换行。因为JavaScript会将换行符变成分号,这样会误认为使用一个没有标签的break语句。

注意:不能给一个函数定义加标签并在函数内部使用该标签。

3.continue

continue语句只能在循环体内部使用。

continue在while循环和for循环中的区别:在while中直接返回到条件;在for循环中会先求increment表达式,然后返回到条件。

continue也可以使用标签,并且中间不能换行。

4.return

return如果不带expression,则会向调用者返回undefined。

5.yield

在后面章节学习到。

6.throw

表示发生某种意外情形或错误,可以使用try/catch/finally语句捕获异常。

throw expression:expression可能求值任何类型的值。JavaScript解释器抛出错误时会使用Error类或子类。

Error对象有一个name属性和message属性,分别用于指定错误类型和保存传入构造函数的字符串

throw new Error("an error occured");

异常是沿JavaScript方法的词法结构和调用栈向上传播的。如果没有找到任何异常处理程序,则会报告错误。

7.try/catch/finally

try子句用于定义要处理的异常的代码块。try后面紧跟着catch句,在try中发生异常时调用。catch子句后面是finally块,包含清理代码,无论try中发生什么,都会执行这个块的内容。

catch和finally都是可选的,但是只要有try块,就必须至少有他们两中的一个。三种块都要有花括号,即使只有一条语句。

如果try中有异常,且有关联的catch快来处理,则会先执行catch块然后执行finally块,如果没有catch块则执行finally,再跳转最接近的包含catch子句。

如果finally本身发生跳转,或者抛出异常,则解释器会抛弃等待的跳转,执行新跳转。

5月15日

第五章 语句 - 其他语句

1.with语句

with会运行一个代码块,就好像指定对象的属性是该代码块作用域中的变量一样。有如下语法

1
2
3
with(object)

statement

with在严格模式下被禁用,尽可能不要使用它。如果在with语句体中创建声明一个新变量或常量,也只是普通变量或常量,不会定义新属性

2.debugger

可以执行某种调试操作。这个语句就像一个断点,执行的JavaScript会停止,可以使用调试器打印变量值、检查调用栈等等。

3.use strict

增强了错误检查,增强安全性,具体区别在P115

4.声明

const、let、var

function:无论函数什么时候声明,这些函数都会被提升

class

import export

5月16日

第6章 对象

1.对象简介

对象是一个属性的无序集合,每个属性有名字和值。JavaScript对象是动态的,可以动态添加和删除属性。

对象是可以修改的,是按引用操作而不是按值操作。

除了名字和值之外,每个属性都还有3个属性特性:writable(可写)、enumerable(可枚举)、configurable(可配置)

2.创建对象

通过对象字面量、new关键字、Object.create()创建

2.1对象字面量

1
2
3
4
5
6
let empty = {}
let point = {x:1,y:2}
let book = {
"main title": "JavaScript",
"sub-title": "The Definitive Guide"
}

属性名是标识符或字符串字面量(可以空串)。属性值是任何JavaScript表达式

2.2使用new创建对象

new关键字后的函数调用可以称之为构造函数

1
2
3
4
let o = new Object();
let a = new Array();
let d = new Date();
let r = new Map();

2.3原型

几乎每个对象都有另一个与之关联的对象。另一个对象称之为原型(prototype),第一个对象从这个对象继承属性。

使用字面量创建的所有对象都有相同的原型对象,在JavaScript可以通过Object.prototype来引用这个原型对象

使用new关键字创建的对象使用构造函数prototype属性的值作为原型。例如new Object()继承自Object.prototype

new Array()以Array.prototype为原型。正是这些有prototype属性的对象为所有其他对象定义了原型

Object.prototype是没有原型的对象,它不继承任何属性。

多数内置构造函数的原型都继承自Object.prototype,例如Date.prototypeObject.prototype继承属性,这种原型对象链接起来的序列被称为原型链。

2.4Object.create()

用于创建一个新对象,使其第一个参数作为新对象的原型

1
2
let o1 = Object.create({x:1,y:2}) //o1继承属性x和y
o1.x + o1.y // => 3

传入null值可以继承一个没有原型的新对象。这样的对象不会继承任何东西,连toString()都没有

1
let o3 = Object.create(Object.prototype) //类似{}或者new Object()

该方法的一个用途是防止被某个第三方库函数意外修改,不要直接传入对象,应该传入一个继承自他的对象

5月17日

第6章 对象

3.查询和设置属性

获得一个属性的值可以用.或方括号[]操作符

使用方括号,其中的表达式必须求值为一个字符串或者一个可以转换成字符串或符号的值

3.1作为关联数组的对象

使用.操作符访问时,属性名是通过标识符来表示的,不能被程序操作

使用[]访问属性时,属性名是通过字符串来表示的。

可以与for/in循环一起使用,

1
2
3
4
5
6
7
function computeValue(p){
let total = 0;
for(let s in p){
let share = p[s];
total += share;
}
}

此处不能使用p.s因为p对象没有名为s的属性,但是可以用p[s]其中s求值为p的属性

3.2继承

JavaScript有一组“自有属性”,同时也从原型对象继承一组属性。

假设从对象o中查询属性x。如果o没有这个名字的属性,则会从o的原型对象查询属性x。如果原型对象也没有,但它有自己的原型,则会继续查询这个原型的原型。一直持续到找到属性x或者查询到一个原型为null的对象。

3.3属性访问错误

如果没有找到对象的属性,会返回undefined,如果对象是null或者undefined,则表达式失败。

可以使用if判断语句;可以使用&&的短路效应;可以使用?.支持条件式访问

5月18日

第6章 对象

3.4删除属性

delete操作符用于从对象中移除属性。它不操作属性的值,而是操作属性本身

1
2
3
delete book.auther;

delete book["main title"]

如果delete操作成功或者没有带来影响(删除不存在的属性),则delete表达式求值为true。对于非属性访问表达式使用delete,也不会造成影响,返回为true

delete不会删除configurable为false的属性,某些内置对象的属性是不可配置的。在严格模式下,尝试删除不可配置属性会导致TypeError,在非严格模式下delete直接求值为false

在非严格模式下,删除全局对象的可配置的属性是,可以省略对全局对象的引用,例如

1
2
globalThis.x = 1
delete x // => true这个可以删除

在严格模式下,操作数如果是这样的非限定标识符,不报错SyntaxError

1
delete x; //=> SyntaxError

3.5测试属性

JavaScript对象可以看成是一组属性,检查对象是否有一个给定名字的属性,可以使用inhasOwnProperty()propertyIsEnumerable()方法,或者直接查询。

对于hasOwnProperty(),用于测试对象是否有给定的属性,但是对于继承的属性,返回false

propertyIsEnumerable在传入的属性不仅是自有属性且这个属性的enumerable特性为true,这个方法才会返回true,通常常规JavaScript代码创建的属性都是可枚举的。

还可以配合使用!==

1
2
3
4
let o = {x: 1}
o.x !== undefined // => true
o.y !== undefined //=> false
o.toString !== undefined //=> true

但是in可以区分不存在的属性和存在的属性但是设置成undefined的属性。

1
2
3
let o = {x: undefined};
o.x !== undefined // => false
"x" in o // => true 存在这个属性

3.6枚举属性

对象继承的内置方法是不可枚举的,但自己的代码添加给对象的属性默认是可枚举的。

为防止通过for/in枚举继承的属性,可以在循环体内加一个显示测试

1
2
3
for(let p in o){
if(!hasOwnProperty()) continue; //=>跳过继承属性
}

有时候可以通过for/of先获取对象所有属性名的数组,在通过for/of循环遍历该数组

  • Object.keys()返回对象可枚举自有属性名的数组,不包含不可枚举属性、继承属性或是名字是符号的属性
  • Object.getOwnPropertyNames()与前一个类似,但会返回不可枚举自有属性名的数组,只要名字是字符串
  • Object.getOwnPropertySymbols()返回名字是符号的自有属性,无论是否可枚举
  • Reflect.keys()返回所有属性名,包括可枚举和不可枚举,字符串和符号

5月19日

3.7 扩展对象

把一个对象的属性复制到另一个对象上

1
2
3
4
5
let target = {x:1},source = {y:2, z:3};
for(let key of Object.keys(source)){
target[key] = source[key];
}
target // => {x:1,y:2,z:3}

ES6中可以使用以Object.assign()形式

它会修改并返回第一个参数,第一个参数是目标对象,后面的第二个及后续参数都是来源对象。会按照参数列表逐个处理来源对象,并且会覆盖目标对象的同名属性。

3.8序列化对象

对象序列化是把对象的状态转换成字符串的过程,之后从中恢复成对象的状态。

JSON.stringifyJSON.parse用于序列化和恢复JavaScript对象

3.9对象方法

toString()

toLocaleString()

valueOf()

toJSON()

5月24日

对象字面量扩展语法

1.简写属性

如果想创建一个具有属性x,y且值分别为相应变量值的对象(即属性名和属性值同名)

1
2
3
4
5
6
7
8
let x = 1, y = 2;
let o = {
x: x,
y: y
}

//在ES6之后,可以简写
let o = {x , y};

2.计算的属性名

当属性的名字不是编译时确定的,而是存在一个变量中,或是调用函数的一个返回值。不能对这种属性使用基本对象字面量。必须先创建对象后,再为其添加属性。 但是在ES6中,可以直接用称为计算属性的特性更简单地创建类似对象。

1
2
3
4
5
6
7
8
const PROPERTY_NAME = "P1";
function computename() { return "p"+ 2}

let p = {
[PROPERTY_NAME]: 1,
[computename()]: 2,
}
p.p1 + p.p2 // => 3

用这个语法,可以在方括号内加入任意JavaScript表达式。对这个表达式求值得到的结果(必要时转换成字符串)用作属性的名字。

3.符号作为属性名

在ES6之后,属性名可以为符号。可以使用计算属性语法将符号作为属性名

1
2
3
4
5
6
const extension = Symbol("my extension");
let o = {
[extension]:{x : 1, y: 2}
}

o[extension].x = 0;

4.扩展操作符

在对象字面量中使用“扩展操作符” ...把已有对象的属性复制到新对象中:

1
2
3
let position = {x: 0, y: 0};
let dimensions = {width: 100, height: 100}
let rect = {...position, ...dimensions};

...仅在对象字面量中,三个点才会产生这种把一个对象的属性复制到另一个对象的插值行为。

注意: 三个点可能对JavaScript解释器带来巨大的工作量

5.简写方法

在ES6以前,需要与定义对象的其他属性一样,通过函数定义表达式在对象字面量中定义方法

1
2
3
let square = {
area: function() {return 100;}
}

但是在ES6中,有一种省略function和冒号的简写方法

1
2
3
let squre = {
area(){return 100;},
}

除了上述的方法,可以使用字符串字面量和计算的属性名,包括符号属性名:

1
2
3
4
5
6
7
const METHOD_NAME = "m";
const symbol = Symbol();
let weirdMethods = {
"method With Space"(x){return x + 1},
[METHOD_NAME](x){return x + 3;},
[symbol](x){return x + 2},
}

6.属性的获取方法与设置方法

JavaScript支持为对象定义访问器属性,这是一个或两个访问器方法(getter)和一个设置方法(setter),当程序查询一个访问器属性的值时,JavaScript会调用获取方法。这个方法返回的值就是属性访问表达式的值。同理,当程序设置一个访问器属性的值时,JavaScript会调用设置方法,传入赋值语句右边的值。

如果一个属性既有获取方法和设置方法,则该属性是一个可读写属性,如果只有一个获取方法,这是一个只读属性。如果只有一个设置方法,就是一个只写属性,读取得到undefined

访问器属性是通过一个或两个方法来定义的,方法名就是属性名。除了前缀是get和set,写法和简写语法定义一样

1
2
3
4
5
6
let o = {
dataProp: value,

get accessProp() { return this.dataProp; },
set accessProp(value) { this.dataProp = value; }
}

6月

6月2日

第七章 数组

7.1创建数组

创建数组有如下几种方式:

  • 数组字面量

    1
    2
    3
    4
    5
    6
    let empty = []
    let primes = [2, true, 1.1 ,"a"]

    //允许连续包含多个逗号,即稀疏数组
    let count = [1,,3]
    let undefs = [,,] //长度为2,不是3,允许末尾有,号
  • 对可迭代对象使用...扩展操作符

    1
    2
    let a = [1,2,3];
    let b = [0, ...a, 4];

    这是一种浅副本(拷贝)的构造方式

    扩展操作符适用于任何可迭代对象(可以用for/of循环遍历)

    1
    2
    let digits = [..."abcdef"]
    digits //=> ["a","b","c","d","e","f"]
  • Array()构造函数

    有三种方式可以构造

    • let a = Array()创建一个没有元素的空数组。

    • let a = Array(10)创建一个指定长度的数组

    • 传入两个或更多的数组元素,或传入一个非数值元素

      let a = Array(5,2,1,4,"testing", "hello");

  • 工厂方法 Array.of() Array.from()

    Array()的方法无法创造一个只含一个元素的数组,可以用Array.of()这是一个工厂方法

    Array.of() //=> []

    Array.of(10) //=> [10]

    Array.of(1,2,3) //=> [1,2,3]

Array.from()期待一个可迭代对象,与使用扩展操作符一样,

let copy = Array.from(original);

​ 该方法可接受可选第二个参数,在创建新数组时,每个源对象的元素都会传入这个函数,该函数返回值将嗲提原始值成为新数组元 素,与map方法很像

6月15日

7.2 读写数组元素

可以使用[]操作符访问数组元素。

数组是一种特殊的对象,用于访问数组元素的方括号与用于访问对象属性的方括号是类似的

JavaScript会将索引1转换成字符串“1”,然后作为属性名。

如果使用了负数或非整数来索引,会被当成常规的对象属性,而不是数组索引;相反,如果使用非负整数的字符串来索引数组,会成为数组索引,而不是常规对象属性。

查询任何不存在的属性都不会导致错误,只会返回undefined

7.3稀疏数组

如果数组稀疏,length值会大于元素个数。

构造方法:(1)使用Array()构造稀疏数组 (2)直接给大于等于当前数组length的数组索引赋值 (3)字面量例如[1,,3]也会创建稀疏数组

注:可以将稀疏数组当成包含undefined元素的非稀疏数组

7.4数组长度

length属性就是数组中元素的个数,这个值比数组的最高索引大1。

对于稀疏数组,length属性会大于数组元素个数。

数组有两个特殊行为:(1)给一个索引大于等于length的数组元素赋值,length属性会被设置为索引+1。(2)如果设置length为一个小于当前值的非负索引,任何索引大于或等于length的值都会删除。

6月17日

7.5添加和删除数组元素

添加元素

(1)索引赋值

(2)push()

删除元素 delete a[2]相当于给元素设置undefined

splice()是一个可以删除、插入、替换数组元素的通用方法

7.6迭代数组

(1) for/of

(2)forEach()

(3)for

7.7多维数组

6月18日

7.8数组方法

迭代器方法、栈和队列方法、子数组方法、搜索和排序方法

1. 数组迭代器方法

forEach()迭代数组的每个元素,并对每个元素都调用一次我们指定的函数,调用的函数接受三个参数(数组元素的值,数组元素的索引和数组本身)

1
2
let data = [0,1,2,3,4,5], sum = 0;
data.forEach(value => {sum += value;});

map()把调用的数组的每个元素分别传给指定的函数,返回返回值构成的数组,与forEach()不同,函数会返回值,但是不会修改原数组。

稀疏数组的缺失元素不会调用该函数,但返回的数组也会是稀疏的,即长度相同

filter() 返回一个数组,包含调用数组的子数组。传入的函数应该是个断言函数,返回truefalse,返回true的传给子数组。

fliter()会跳过稀疏数组的缺失元素,因此可以使用filter()清理稀疏数组

1
let dense = sparse.filter(() => true);

find() findIndex()