目标
了解 JS 基础语法
如何创建变量
let、var、const 之间的区别
了解掌握流程控制等相关语法
解构
模板字符串
掌握字符串的Api
ES6 的发展过程
ECMAScript 6.0(ES6)是 JavaScript 语言的新一代标准,它于 2015 年 6 月正式发布,它的目标是使得 JavaScript 语言可以用来编写复杂的大型应用程序,成为企业级开发语言。ECMAScript 和 JavaScript 的关系是,前者是后者的规格,后者是前者的一种实现,日常场合,这两个词是可以互换的。
在 ES6 之前,JavaScript 语言是非常落后的,很多现代化的特性都不具备,难以支撑大型应用的开发,ES6 的发布,使得 JavaScript 彻底改变。
目前 ES 的版本升级成为了一个不断滚动的流程,标准委员会最终决定,标准在每年的 6 月份正式发布一次,作为当年的正式版本。接下来的时间,就在这个版本的基础上做改动,知道下一年的 6 月份,草案就变成了新一年的版本,这样一来,就不需要以前的版本号了,只需要用年份来标记。
ES6 于 2015 年发布,也称为 ES2015,之后每年发布的版本变化都非常小,因此,ES6 既是一个历史名词,也是一个泛指,涵盖了 ES6 之后的所有标准,所以我们简单认为 ES6 就是指的“新一代的 JavaScript”语言,在发布之初 ES6 面临着许多兼容性的问题,主流的 JavaScript 引擎支持程度还不够高,通常需要使用 Babel 之类的工具来进行转义,现在我们可以借助最新的 JS 引擎来直接执行原生 ES6 代码了。
ES6 包含的内容非常多,本课程内容不会对 JavaScript 基础语法做过多的讲解,这部分内容需要自行学习,这里主要介绍一些常见 API 的使用,如果想要熟练使用 JavaScript,首先需要熟练掌握常用的 API。
jQuery 已经完成了它的历史使命,它的很多 API 如今已经成为标准,得到了原生的支持,在我们后面的课程中不会涉及 jQuery,也不允许在作业中使用。本章内容假定同学们已经完成了前面要求的 JS 相关基础知识的自学。
基础语法
let
ES6 新增了 let 命令用来声明变量,它的用法类似于 var,区别在于它只在 let 声明的代码块内有效,并且 let 在同一作用域内不能重复声明,我们建议在平时的开发中使用 let 替代 var。
function varTest() { var x = 1 if (x === 1) { var x = 2 // 两个x是同一个变量 console.log(x) // 输出:2 } console.log(x) // 输出:2 }
function letTest() { let x = 1 if (x === 1) { let x = 2 // 两个x是不同的变量 console.log(x) // 输出:2 } console.log(x) // 输出:1 }
另外,在程序和方法的最顶端,var 声明的变量会给全局对象增加属性,但是 let 不会,例如:
var x = 'hello' let y = 'hello' console.log(this.x) // "hello" console.log(this.y) // undefined
上面的 this 取决于执行环境,如在浏览器中执行,指向的是 window 对象,如在 Node.js 中执行,指向的则是 global 对象。
另外需要注意的是,let 在同一块作用域中不允许重复声明,例如:
if (flag) { let test = 1 let test = 2 // SyntaxError }
使用大括号 {} 可以用来定义一个块级作用域。
const
const 常量也是块级范围的,这一点与 let 相似,但 const 声明的值是无法被改变的,也不能被重新声明,全局常量也不会变为 window 对象的属性,所以,常量必须在声明的时候就指定它的值。
const number = 123 number = 456 // Uncaught TypeError: Assignment to constant variable
一般我们建议在声明常量的时候全部采用大写字母,例如:
const MY_NUMBER = 123
需要注意的是,如果 const 用来定义数组或对象,那么对于他们子项或者属性的修改是允许的,但是不能够对自身重新赋值,例如:
const MY_ARRAY = [1, 2, 3] MY_ARRAY.push(4) // 允许 MY_ARRAY = [] // 不允许 const MY_OBJECT = { key: 123 } MY_OBJECT.key = 456 // 允许 MY_OBJECT = { key: 456 } // 不允许
如果想要冻结对象属性的修改,可以使用 Object.freeze() 来时对象不可变,例如
const MY_OBJECT = { key: 123 } Object.freeze(MY_OBJECT) MY_OBJECT.key = 456 // 常规模式下该语句不会起作用,但是也不会报错,严格模式下会报错
练习
通过练习寻找总结 var、let、const 之间的区别。
布尔与关系操作符
关系操作符
特殊情况的比较结果
布尔操作符
练习
在使用这些运算符进行比较的时候,会发生类型转换。他们是如何转换的,请练习总结。
附加:其他的操作符
除了这两种操作符外,还有其他的操作符,例如一元操作符,逗号操作符等等,请自行了解。
强制类型转换
在使用上述两种操作符时,都会进行类型转换,请课后自行了解。
程序控制
if…else
if(a == 1) { console.log('a=1');} else if(a == 2) { console.log('a=2');} else { console.log('a=other');}
switch…case
switch(n) { case 1: { break } case 2: { break } default: { }}
for循环
for(let i = 0; i < 10; i++) { if(i%2==0) { continue; } console.log(i)}
while循环
while(true) { console.log("true");}
练习
猜数字小游戏:
设定一个谜底数字,输入一个四位数的数字,输出一个字符表示是否猜对
例如要谜底数字是1234
猜测1233,则输出3A1B
猜测1234,则输出4A0B
思考:除了for、while还有哪些其他的循环的方法
解构赋值
解构赋值语法是一种 JavaScript 表达式,通过解构赋值,可以将属性、值从对象、数组中取出,赋值给其他变量,以前如果我们想要给变量赋值,只能直接指定变量的值,例如:
let a = 1let b = 2let c = 3
如果我们想要从数组中取出值,需要这么来写:
let array = [1, 2, 3]let a = array[0]let b = array[1]let c = array[2]
如果我们想要从对象中取出属性和值,需要这么来写:
let object = { a: 1, b: 2, c: 3 }let a = object.alet b = object.blet c = object.c
通过上面的例子我们可以看到,书写起来非常的繁琐,不够简洁,现在通过 ES6 的解构赋值语法,我们就可以轻松实现。
解构数组
基本语法如下,左侧的变量名和右侧数组中的元素一一对应
let [a, b, c] = [1, 2, 3]console.log(a) // 1console.log(b) // 2console.log(c) // 3
可以给左边数组中的变量设置默认值,例如
let [a = 1, b = 2] = [5]console.log(a) // 5console.log(b) // 2
可以通过解构直接交换两个变量,在没有解构的时候,我们需要一个中间临时变量
let a = 1let b = 2// 不使用解构来交换let c = aa = bb = c// 使用解构来交换[ (a, b)] = [b, a]console.log(a) // 2console.log(b) // 1
function foo() { return [1, 2]}let [a, b] = foo()console.log(a) // 1console.log(b) // 2
可以忽略掉某些值。例如
let [a, , , b] = [1, 2, 3, 4]console.log(a) // 1console.log(b) // 4
剩余模式,将剩余部分的数组赋值给一个变量
let [a, ...b] = [1, 2, 3]console.log(a) // 1console.log(b) // [2, 3]
解构对象
基本语法如下:
let object = { a: 1, b: 2, c: 3 }let { a, b } = objectconsole.log(a) // 1console.log(b) //
可以从一个对象中提取变量并赋值给和属性名不同的新变量名
let object = { a: 1, b: 2, c: 3 }let { a: aa, b: bb } = objectconsole.log(aa) // 1console.log(bb) // 2
解构对象也可以指定默认值,例如:
let object = { a: 5 }let { a = 1, b = 2 } = objectconsole.log(a) // 5console.log(b) // 2
解构对象也支持剩余模式,例如
let { a, ...b } = { a: 1, b: 2, c: 3 }console.log(a) // 1console.log(b) // { b: 2, c: 3 }
解构对象的一个典型应用场景是从函数参数对象中提取数据,例如下面的代码,函数接收的参数是一个对象,如果不使用解构,需要专门去读取参数对象中的属性值
function test(user) { console.log(user.id, user.name)}let user = { id: 1, name: 'test',}test(user)
如果我们使用解构对象,接可以直接将属性取出来
function test({ id, name }) { console.log(id, name)}let user = { id: 1, name: 'test',}test(user)
模板字符串
模板字符串是增强版的字符串,用反引号 (`)来标识,它可当作普通字符串来使用,也可以用来定义多行文本,或者通过 ${} 在字符串中嵌入变量或表达式。
let a = `template string` // 普通字符串let name = 'Frank'let b = `Hello ${name}!`console.log(b) // Hello Frank!
模板字符串的另外一大作用就是多行文本定义变得更加方便,对比例子:
let name = 'Frank'let a = `<div> <p>Hello ${name}!</p></div>`let b = '<div>\n <p>Hello ' + name + '!</p>\n</div>'console.log(a === b) // true
字符串操作
字符串处理是我们在编程的时候非常常用的功能,这里介绍一些基本的字符串处理方法,有的是ES6之前就存在的。
substring
该方法返回一个字符串在开始索引到结束索引之间的一个子集,或者从开始索引到字符串末尾的一个子集。
语法
参数
indexStart:需要截取的第一个字符的索引,该索引位置的字符作为返回的字符串的首字母。
indexEnd:可选参数,一个0到字符串长度之间的整数,以该数字为索引的字符串不包括在截取的字符串内。
返回值
包括给定字符串的指定部分的新字符串
下面查看一些示例:
let str = '0123456789'console.log(str.substring(0, 3)) // '012'console.log(str.substring(3, 6)) // '345'console.log(str.substring(0, -3)) // 相当于 str.substring(0, 0),输出为空字符串
slice
slice 的作用和 substring 非常类似,不同的是,slice 的参数可以为负数,表示倒数第几个字符
let str = '0123456789'console.log(str.slice(0, 3)) // '012'console.log(str.slice(3, 6)) // '345'console.log(str.slice(0, -3)) // '0123456',表示从第0各字符提取到倒数第三个字符console.log(str.slice(-3, -1)) // '78'
includes
方法用于判断一个字符串是否包含在另一个字符串中,根据情况返回 true 或 false。
参数
searchString:要搜索的字符串
position:开始搜索的索引位置,默认为0,可选
示例:
let str = '0123456789'console.log(str.includes('123')) // trueconsole.log(str.includes('123', 4)) // false
startsWith
startsWith 方法用来判断当前字符串是否以另外一个给定的子字符串开头,并根据判断结果返回 true 或 false。
参数
searchString:要搜索的字符串
position:开始搜索的索引位置,默认为0,可选
示例:
let str = '0123456789'console.log(str.startsWith('0123')) // trueconsole.log(str.startsWith('1234')) // falseconsole.log(str.startsWith('1234', 1)) // true
endsWith
endsWith 与 startsWith 作用类似,用来判断当前字符串是否以另外一个给定的子字符串结尾,endsWith 的第二个参数是可选的 str 长度,示例如下:
let str = '0123456789'console.log(str.endsWith('789')) // trueconsole.log(str.endsWith('456', 7)) // true,相当于判断 '0123456'.endsWith('456)
repeat
该方法返回一个新字符串,表示将原字符串重复 n 次,示例如下:
'abc'.repeat(2) // 'abcabc'
padStart、padEnd
这两个方法提供了字符串补全长度的功能,如果某个字符串不够指定的长度,会在头部或者尾部补全,padStart 用于头部补全,padEnd 用于尾部补全,这个在格式化字符串的时候非常有用,示例如下:
'5'.padStart(5, '0') // '00005''123'.padEnd(5) // '123 ',默认使用空格补全'12345'.padStart(4) // '12345',超出长度,不会变化
trim、trimStart、trimEnd
这三个方法的作用类似,trim 用来消除字符串首尾的空格,trimStart 用来消除字符串头部的空格,trimEnd 用来消除字符串尾部的空格,他们返回的都是新字符串,不会改变原值,示例如下:
let str = ' abc 'str.trim() // 'abc'str.trimStart() // 'abc 'str.trimEnd() // ' abc'
replaceAll
以前js的字符串替换方法 replace() 只会替换第一个匹配,如果想要替换所有的匹配,需要写正则表达式,例如:
'aabbcc'.replace('b', '_') // 'aa_bcc''aabbcc'.replace(/b/g, '_') // 'aa__cc'
写正则增加了复杂度,现在新增的 replaceAll() 方法,可以一次性替换所有匹配
'aabbcc'.replaceAll('b', '_') // 'aa__cc'
split
该方法使用指定的分割字符将一个字符串分割成子字符串数组,以一个指定的分割字符串来决定每个拆分的位置
console.log('Hello JavaScript'.split(' ')) // [ 'Hello', 'JavaScript' ]console.log('Hello'.split('')) // [ 'H', 'e', 'l', 'l', 'o' ]
附加:正则表达式