函数的预解析
- 什么是预解析
- 在代码运行前,先全部分析一遍代码,这个行为叫做预解析(预解释)
- 预解析的内容
- 声明式函数定义
- var 声明变量
// 正常书写代码
fn()
console.log(a)
function fn() {
console.log(100)
}
var a = 100
// 预解析后可以理解为
function fn() {
console.log(100)
}
var a
fn()
console.log(a)
a = 100
作用域
- 什么是作用域?
- 简答一句话概述:变量生效的范围
- 变量不是在所有地方都是可以使用的,而这个变量的可使用范围 就是作用域
全局作用域 && 局部作用域
-
全局作用域
- 最大的作用域
- 在全局作用域中定义的变量可以在任何地方使用
- 页面打开时浏览器给我们生成了一个全局作用域
window这个作用域一直存在,直到浏览器页面关闭时才会销毁 var num = 100; var num2 = 200这两行代码的变量就是存储在全局作用域下面,可以在任意地方去使用
-
局部作用域
- 局部作用域就是在全局作用域内的某一个地方,相对比较小的一些作用域
- 在局部作用域中定义的变量只能在当前的这个作用域内部使用,在全局作用域或者其他的局部作用域中不可以使用
- 在 JS 中,只有函数能生成一个局部作用域,别的都不行
- 简单来说,每一个函数内部都是一个局部作用域
var num = 100; // 全局作用域下声明的变量,在任何地方都可以使用 function fn() { var num2 = 200; // 在当前位置声明的变量都是 fn 函数局部作用域内的变量, 也就是说只能在当前 fn 函数内部使用 }
作用域链
- 作用域链是一个纯概念性的东西
- 当我们在某一个作用域内获取某一个变量时
- 会先在当前作用域查找,找到直接拿来用,没找到会向上层查找
- 如果上层作用域也没找到,那么会继续向上层作用域的上层作用域查找,一直到查找到全局作用域
- 这样一层一层向上查找构成一个链条(假设有,不是真的有链条),我们叫做作用域链
var num = 100;
function fn() {
var num2 = 200;
function fun() {
var num3 = 300;
console.log(num3); // 自己当前作用域就有(fun函数内部),拿过来直接用
console.log(num2); // 自己当前作用域没有(fun函数内部),去上一层查找,发现有(fn函数内部),拿过来用
console.log(num); // 自己当前作用域没有(fun函数内部),去上一层查找,发现没有(fn函数内部),继续向上一层作用域查找,发现有(全局作用域),直接用
console.log(a); // 自己没有,一级一级向上查找,到全局作用域还是没有,报错
}
}
变量使用规则
访问规则
- 变量的访问规则 也叫做 作用域的查找机制
- 作用域的查找机制只能向上查找,不能向下查找
function fn() {
var num = 100;
}
fn();
console.log(num); // 全局作用域没有,相当于已经查找到顶层,所以报错找不到,不会向 fn的局部作用域查找
赋值规则
- 当我们想要给某一个变量赋值的时候,就要先找到这个变量,然后再给它赋值
- 赋值规则
- 先在自己作用域内部查找,有就直接赋值
- 没有就去上一级作用域内部查找,有就直接赋值,如果没有继续向上一级作用域内部查找
- 如果一直找到全局作用域都没有,那么就把这个变量定义为全局变量,再给他赋值
function fn() {
num = 100;
}
fn();
/**
* fn 调用以后,要给 num 赋值
* 查找自己作用域没有后,向上层查找
* 上层就是全局作用域,发现还是没有
* 那么会把 num 定义为全局的变量,并给它赋值
* 所以 fn 函数调用后,全局就有了一个变量叫做 num 并且值是 100
*/
递归函数
- 什么是递归?
- 在编程世界中,递归就是一个自己调用自己的手段
- 递归函数:在一个函数内部,调用了自己,循环往复
/**
* 这就是一段简单的递归,在函数内部调用了自己,函数一执行,就调用自己一次,在调用在执行,循环往复没有尽头
*/
function fn() {
fn();
}
fn();
- 其实递归函数和循环很类似
- 需要有初始化,自增,执行代码,条件判断
- 如果没有就会是一个没有尽头的递归函数,我们通常叫这种为 死递归
写一个简单的递归
/**
* 求 1 至 5 的和
*
* 1 + 2 = 3
* 3 + 3 = 6
* 6 + 4 = 10
* 10 + 5 = 15
*/
// 写递归的第一步,先写结束条件(为了避免出现死递归)
function add(n) {
if (n == 5) {
return 5;
}
}
add(1);
// 第二步,写不满足结束条件时的递归操作
function add(n) {
if (n == 5) {
return 5;
} else {
return n + add(n + 1);
}
}
add(1);
数组去重案例
严格模式(了解)
- JS 是一个相对不是很严谨的语言, 在开发的时候一些代码也不是很严格, 严格模式就是对开发的时候写的代码做了一些要求
如何开启严格模式
- 要开启严格模式, 直接在代码最开始的位置写上字符串 'use strict'
严格模式的规则
- 声明变量必须有
var关键字 - 函数的形参不可以重复
字符串
创建字符串(了解)
- 字面量
- 构造函数创建
var str1 = 'hello'
var str2 = new String('hello')
ASCII 字符集(了解)
- 计算机只能存储二进制数据
0101010 - 我们的 大写字母; 小写字母; 符号 之类的内容也是由二进制数字组成的
- 或者说 我们的字母符号这些东西写都有一个对应的编号, 然后计算机存储的时候是存储的这些编号,不过我们看到的时候, 是通过这些编号解析成我们看到的内容
- 所以我们计算机存储的字母符号之类的并不是存储了这个字母, 而是存储了这个字母对应的编号, 然后给我们看到的时候是通过这个编号找到了对应的字母给我们看
unicode 编码
- ASCII 只有 128 个字符的编码结构, 这是因为他出现的比较早, 而且是美国发明的, 所以在早期这些内容完全足够
- 但是这个世界要存储的东西就不够, 比如我们的汉字, 所以就出现了
unicode编码, 也叫(万国码, 统一码) - unicode 和 ASCII 一样的对照表, 只不过存的东西特别多, 基本包含了世界上大部分国家的文字, 所以我们的文字在存储的时候 都是按照 unicode 编码转换成了数字进行存储
- 我们的 UTF-8 就是一种 8 位的 unicode 字符集
一些操作字符串的常用方法
-
charAt/charCodeAt/toLowerCase/toUpperCase- charAt
- 语法:
变量.charAt(索引) - 作用: 找到字符串中指定索引位置的内容然后返回
- 返回值: 字符串中指定索引位置的内容
- 语法:
- charCodeAt
- 语法:
变量.charCodeAt(索引) - 作用: 找到字符串中指定索引位置的 unicode 编码然后返回
- 返回值: 字符串中指定索引位置的 unicode 编码
- 语法:
- toLowerCase
- 语法:
变量.toLowerCase() - 作用: 将字符串转换为小写
- 返回值: 转小写后的字符串
- 语法:
- toUpperCase
- 语法:
变量.toUpperCase() - 作用: 将字符串转换为大写
- 返回值: 转大写后的字符串
- 语法:
- charAt
-
substr/substring/slice- substr
- 语法:
变量.substr(开始索引, 截取多少个) - 作用: 截取字符串
- 返回值: 截取出来的字符串
- 语法:
- substring
- 语法:
变量.substr(开始索引, 结束索引) - 作用: 截取字符串
- 返回值: 截取出来的字符串
- 注意: 参数包前不包后
- 语法:
- slice
- 语法:
变量.slice(开始索引, 结束索引) - 作用: 截取字符串
- 返回值: 截取出来的字符串
- 注意: 参数包前不包后
- 语法:
- substr
-
concat/indexOf/lastIndexOf/split- concat
- 语法:
变量.concat(字符串1, 字符串2) - 作用: 拼接字符串
- 返回值: 拼接好的字符串
- 语法:
- indexOf
- 语法:
变量.indexOf(查找的字符, 开始索引) - 作用: 查找当前字符串中是否包含指定字符
- 返回值: 找到返回第一次出现的首字母索引位置, 找不到就返回 -1
- 语法:
- lastIndexOf
- 语法:
变量.lastIndexOf(查找的字符, 开始索引) - 作用: 查找当前字符串中是否包含指定字符 (从后往前)
- 返回值: 找到返回第一次出现的首字母索引位置, 找不到就返回 -1
- 语法:
- split
- 语法:
变量.split('分隔符') - 作用: 把字符串按照分隔符分开为几段内容
- 返回值: 将字符串分割后以数组的形式分隔
- 语法:
- concat
-
trim/trimStart/trimEnd- trim
- 语法:
变量.trim() - 作用: 把字符串左右空格去除
- 返回值: 去除空格后的字符串
- 语法:
- trimStart(trimLeft)
- 语法:
变量.trimStart() - 语法:
变量.trimLeft() - 作用: 把字符串左边空格去除
- 返回值: 去除左边空格后的字符串
- 语法:
- trimEnd(trimRight)
- 语法:
变量.trimEnd() - 语法:
变量.trimRight() - 作用: 把字符串右边空格去除
- 返回值: 去除右边空格后的字符串
- 语法:
- trim
-
includes/startsWith/endsWith/repalce- includes
- 语法: 字符串.includes(字符串片段)
- 作用: 该字符串中是否包含该字符串片段
- 返回值: 一个布尔值
- true: 包含
- false: 不包含
- startsWith
- 语法: 字符串.startsWith(字符串片段)
- 作用: 判断该字符串是否以该字符串片段开头
- 返回值: 一个布尔值
- true: 是开头
- false: 不是开头
- endsWith
- 语法: 字符串.endsWith(字符串片段)
- 作用: 判断该字符串是否以该字符串片段结尾
- 返回值: 一个布尔值
- true: 是结尾
- false: 不是结尾
- includes