黑马Pink老师的JavaScript教程:https://www.bilibili.com/video/BV1Sy4y1C7ha?from=search&seid=3161590902859712011
本文在原教程的基础上对目录结构进行了排序和裁剪,一些太基础的概念没有写入。针对视频中的讲解、案例、PPT和源码材料作了一些总结,仅用于个人复习以及学习交流分享。
目录
Chapter1. 概述
1.1 JavaScript及其历史
JavaScript是具有面向对象能力的、解释型的程序设计语言。它是基于对象和事件驱动并具有相对安全性的客户端脚本语言。不需要在一个语言环境下运行,只需要支持它的浏览器。主要目的:验证发往服务端的数据、增加web互动、加强用户体验感。
1995年诞生,最初为网景公司称为liveScript,后与sun公司合作为JavaScript。
JavaScript的诞生是为了验证表单输入,在此前都是通过服务端验证的,速度极慢。而JavaScript也从输入验证变得强大。
ECMA(原欧洲计算机制造商协会)。ECMA-262标准定义了叫做ECMAScript的全新脚本语言。
拓展1:解释型语言和编译型语言的区别
计算机不能直接理解任何除机器语言以外的语言,所以必须要把程序员所写的程序语言翻译成机器语言才能执行程序。程序语言翻译成机器语言的工具,被称为翻译器。
翻译器翻译的方式有两种:一个是编译,另外一个是解释。两种方式之间的区别在于翻译的时间点不同。
- 编译器是在代码执行之前进行编译,生成中间代码文件。
- 解释器是在运行时进行及时解释,并立即执行(当编译器以解释方式运行的时候,也称之为解释器)
比喻:
编译语言:首先把所有菜做好,才能上桌吃饭。
解释语言:好比吃火锅,边吃边涮,同时进行。
拓展2:标识符、关键字、保留字
标识符:就是指开发人员为变量、属性、函数、参数取的名字。标识符不能是关键字或保留字。
关键字:是指 JS本身已经使用了的字,不能再用它们充当变量名、方法名。
ECMA-262第6版(es6)规定的所有关键字:
break do in typeof
case else instanceof var
catch export new void
class extends return while
const finally super with
continue for switch yield
debugger function this
default if throw
delete import try
保留字:实际上就是预留的“关键字”,意思是现在虽然还不是关键字,但是未来可能会成为关键字,同样不能使用它们当变量名或方法名。
abstract
boolean
byte
char
class
const
debugger
double
enum
export
extends
final
float
goto
implements
import
int
interface
long
native
package
private
protected
public
short
static
super
synchronized
throws
transient
volatil
1.2 JavaScript作用
- 表单动态检验
- 网页特效
- 服务端开发(node.js)
- 桌面程序(electron)
- app(cordova)
- 控制硬件-物联网(ruff)
- 游戏开发
1.3 HTML/CSS/JavaScript
HTML/CSS标记语言-描述类语言(人的身体和衣服)
JS脚本语言-编程类语言(人的动作)
1.4 浏览器执行JS
渲染引擎:用来解析HTML与CSS,俗称内核,比如 chrome 浏览器的 blink ,老版本的 webkit。
JS引擎:也称为 JS 解释器。 用来读取网页中的JavaScript代码,对其处理后运行,比如 chrome 浏览器的 V8。
浏览器本身并不会执行JS代码,而是通过内置 JavaScript 引擎(解释器) 来执行 JS 代码 。JS 引擎执行代码时逐行解释每一句源码(转换为机器语言),然后由计算机去执行,所以 JavaScript 语言归为脚本语言,会逐行解释执行。
1.5 JS的组成
一个完整的JavaScript由以下三个不同的部分组成:
- 核心 ECMAScript
- 文档对象模型DOM
- 浏览器对象模型BOM
ECMAScript(ES)
ECMAScript:ECMAScript 规定了JS的编程语法和基础核心知识,是所有浏览器厂商共同遵守的一套JS语法工业标准。
ECMAScript定义的是这门语言的基础,而在这个基础上可以构建更完整的脚本语言。它与web浏览器没有依赖关系,还可以在ActionScript,ScriptEase环境寄宿。组成部分有:语法、类型、语句、关键字、保留字、操作符和对象等。
DOM-文档对象模型
文档对象模型(Document Object Model,简称DOM),是W3C组织推荐的处理可扩展标记语言的标准编程接口。
通过 DOM 提供的接口可以对页面上的各种元素进行操作(大小、位置、颜色等)。
BOM - 浏览器对象模型
BOM (Browser Object Model,简称BOM) 是指浏览器对象模型,它提供了独立于内容的、可以与浏览器窗口进行互动的对象结构。通过BOM可以操作浏览器窗口,比如弹出框、控制浏览器跳转、获取分辨率等。
1.6 JS初体验
三种书写位置:行内式、内嵌式、外部引用。
- 行内式
<input type="button" value="点我试试" onclick="alert('Hello World')" />
- 内嵌式
<script>
alert('Hello World~!');
</script>
- 外部JS文件
<script src="my.js"></script>
引用外部 JS文件的 script 标签中间不可以写代码
1.7 JavaScript输入输出语句
prompt('这是一个输入框');
alert('这是一个提示框');
console.log('控制台输出,给程序员调试用的');
注:vscode中console.log快捷输入为log+enter
Chapter2. 变量
2.1 变量概述
变量:存放数据的容器。本质是在内存中申请一块用来存放数据的空间。
2.2 变量使用
变量的初始化:声明变量并赋值。声明变量的本质就是去内存申请空间。
<script>
// 1. 声明了一个age 的变量
var age;
// 2. 赋值 把值存入这个变量中
age = 18;
// 3. 输出结果
console.log(age);
// 4. 变量的初始化
var myname = 'pink老师';
console.log(myname);
</script>
2.3 变量的语法扩展
2.3.1 更新变量
一个变量被重新复赋值后,它原有的值就会被覆盖,变量值将以最后一次赋的值为准。
2.3.2 同时声明多个变量
同时声明多个变量时,只需要写一个 var, 多个变量名之间使用英文逗号隔开。
2.3.3 声明变量的特殊情况
不声明也可以直接使用,但不提倡,因为会变成全局变量。还是提倡先声明后赋值。
情况 | 说明 | 结果 |
---|---|---|
var age; console.log(age); | 只声明,不赋值 | undefined |
console.log(age); | 不声明,不赋值,直接使用 | 报错 |
age=10; console.log(age); | 不声明,只赋值 | 10 |
2.4 变量命名规范
- 由字母、数字、下划线、美元符号组成
- 严格区分大小写
- 不能以数字开头
- 不能是关键字、保留字
- 变量名有意义
- 遵循驼峰命名法(首字母小写,后面大写)
注:name不是关键字也不是保留字,但在某些浏览器中有特殊意义,也尽量不作为变量名。
Chapter3. 数据类型
3.1 概述
数据类型就是数据的类别型号。在计算机中,不同的数据所需占用的存储空间是不同的,为了便于把数据分成所需内存大小不同的数据,充分利用存储空间,于是定义了不同的数据类型。
3.2 变量的数据类型
JavaScript是弱类型或者说动态语言:JS的变量数据类型是只有程序在运行过程中,JS引擎根据等号右边的值来确定的。变量声明时,不知道变量的类型。也不用提前声明变量的类型。
JavaScript是动态语言,同时也意味着相同的变量可用作不同的类型。
3.3 数据类型的分类
3.3.1 简单数据类型
简单数据类型 | 说明 | 默认值 |
---|---|---|
Number | 数字型,包含整型值和浮点型值 | 0 |
Boolean | 布尔值类型,true和false,等价于1和0 | false |
String | 字符串类型,js中字符串都带引号 | “” |
undefined | var a; 声明了变量但没有赋值,a = undefined | undefined |
Null | var a = null; 声明了a为空值 | null |
Number数字型
既可以用来保存整数,也可以用来保存小数(浮点数)。
var num = 10; // num 数字型
var PI = 3.14 // PI 数字型
进制
最常见进制有二进制、八进制、十进制、十六进制。
ES6中,二进制前面加0b,八进制前面加0o,十六进制前面加0x。
// 1. 八进制 0 ~ 7 我们程序里面数字前面加0 表示八进制 var num1 = 010; console.log(num1); // 010 八进制 转换为 10进制 就是 8 var num2 = 012; console.log(num2); // 2. 十六进制 0 ~ 9 a ~ f #ffffff 数字的前面加 0x 表示十六进制 var num3 = 0x9; console.log(num3); var num4 = 0xa; console.log(num4);
范围
Number.MAX_VALUE和Nubmer.MIN_VALUE
// 3. 数字型的最大值 console.log(Number.MAX_VALUE); // 4. 数字型的最小值 console.log(Number.MIN_VALUE);
特殊值
无穷大:Infinity
无穷小:-Infinity
非数值:NaN(Not a number)
// 5. 无穷大 console.log(Number.MAX_VALUE * 2); // Infinity 无穷大 // 6. 无穷小 console.log(-Number.MAX_VALUE * 2); // -Infinity 无穷大 // 7. 非数字 console.log('pink老师' - 100); // NaN
判断是否为非数字类型:isNaN()
String字符串型
字符串类型可以是单引号也可以是双引号,推荐使用单引号。(因为HTML标签属性中使用的是双引号)
引号嵌套
外双内单或内单外双。
转义字符
转义字符都是以’ \ '开头,但它们要写到引号里面。
转义符 | 说明 |
---|---|
\n | 换行 |
\ \ | 斜杠 |
\ ’ | 单引号 |
\ " | 双引号 |
\t | tab缩进 |
\b | 空格,blank |
字符串长度
使用字符串的length属性
var str = 'my name is andy'; console.log(str.length); // 15
字符串拼接
字符串 + 任何类型 = 拼接之后的新字符串,拼接前会把与字符串相加的任何类型转成字符串,再拼接成一个新的字符串。
console.log(str.length); // 15 // 2. 字符串的拼接 + 只要有字符串和其他类型相拼接 最终的结果是字符串类型 console.log('沙漠' + '骆驼'); // 字符串的 沙漠骆驼 console.log('pink老师' + 18); // 'pink老师18' console.log('pink' + true); // pinktrue console.log(12 + 12); // 24 console.log('12' + 12); // '1212'
Boolean布尔型
布尔型和数字型相加的时候, true 的值为 1 ,false 的值为 0。
console.log(flag + 1); // 2 参与加法运算当1来看 console.log(flag1 + 1); // 1 参与加法运算当 0来看
undefined未定义
一个变量声明后未赋值。
和字符串str相加:undefinedstr
和数字相加:NaN
var str; console.log(str); var variable = undefined; console.log(variable + 'pink'); // undefinedpink console.log(variable + 1); // NaN undefined 和数字相加 最后的结果是 NaN##### null空和字符串str相加:nullstr和数字相加:数字```javascript var space = null; console.log(space + 'pink'); // nullpink console.log(space + 1); // 1
3.3.2 复杂数据类型
object对象
3.4 获取变量数据类型
3.4.1 typeof
typeof 可用来获取检测变量的数据类型。返回的是这个数据类型的字符串值。
数据类型 | 例子 | 结果 |
---|---|---|
String | typeof “小白” | “string” |
Number | typeof 18 | “number” |
Boolean | typeof true | “boolean” |
Undefined | typeof undefined | “undefined” |
Null | typeof null | “object” |
注意typeof null,判断认为它是一个空的对象,这是第一版JavaScript留下来的bug,因此返回的是"object"这个字符串值。
3.4.2 字面量
字面量是在源代码中一个固定值的表示法,通俗来说,就是字面量表示如何表达这个值。
3.5 数据类型转换
3.5.1 概述
数据类型转换:把一种数据类型的变量转换成另外一种数据类型。
- 转换为字符串类型
- 转换为数字型
- 转换为布尔型
3.5.2 转换为字符串
- 变量.toString()
- String(变量)
- +’’
// 1. 把数字型转换为字符串型 变量.toString() var num = 10; var str = num.toString(); console.log(str); console.log(typeof str); // 2. 我们利用 String(变量) console.log(String(num)); // 3. 利用 + 拼接字符串的方法实现转换效果 隐式转换 console.log(num + '');
3.5.3 转换为数字型(重点)
- parseInt(变量)
- parseFloat(变量)
- Number(变量)
- -*/
// var age = prompt('请输入您的年龄'); // 1. parseInt(变量) 可以把 字符型的转换为数字型 得到是整数 // console.log(parseInt(age)); console.log(parseInt('3.14')); // 3 取整 console.log(parseInt('3.94')); // 3 取整 console.log(parseInt('120px')); // 120 会去掉这个px单位 console.log(parseInt('rem120px')); // NaN // 2. parseFloat(变量) 可以把 字符型的转换为数字型 得到是小数 浮点数 console.log(parseFloat('3.14')); // 3.14 console.log(parseFloat('120px')); // 120 会去掉这个px单位 console.log(parseFloat('rem120px')); // NaN // 3. 利用 Number(变量) var str = '123'; console.log(Number(str)); console.log(Number('12')); // 4. 利用了算数运算 - * / 隐式转换 console.log('12' - 0); // 12 console.log('123' - '120'); console.log('123' * 1);
3.5.4 转换为布尔型
Boolean()
- 代表空、否定的值会被转换为false
- 其他值转换为true
console.log(Boolean('')); // false console.log(Boolean(0)); // false console.log(Boolean(NaN)); // false console.log(Boolean(null)); // false console.log(Boolean(undefined)); // false console.log('------------------------------'); console.log(Boolean('123')); // true console.log(Boolean('你好吗')); // true console.log(Boolean('我很好')); // true
Chapter4. 运算符
运算符:操作符,用于实现赋值、比较和执行算术运算。
4.1 算术运算符
4.1.1 浮点数的精度问题
浮点数值的最高精度是 17 位小数,但在进行算术计算时其精确度远远不如整数。因为小数转成二进制再进行算术运算会有误差。
// 浮点数在算数运算里面会有问题 console.log(0.1 + 0.2); // 0.30000000000000004 console.log(0.07 * 100); // 7.000000000000001 // 我们不能直接拿着浮点数来进行相比较是否相等 var num = 0.1 + 0.2; console.log(num == 0.3); // false
4.2 递增和递减运算符
递增++,递减–
在 JavaScript 中,递增(++)和递减( – )既可以放在变量前面,也可以放在变量后面。放在变量前面时,我们可以称为前置递增(递减)运算符,放在变量后面时,我们可以称为后置递增(递减)运算符。
- 前置:先自加,后运算(先已后人)
- 后置:先原值运算,后自加(先人后己)
4.3 比较运算符
运算符 | 说明 | 案例 | 结果 |
---|---|---|---|
< | 小于 | 1<2 | true |
> | 大于 | 1>2 | false |
>= | 大于等于 | 2>=2 | true |
小于等于 | 3<=2 | false | |
== | 判等号(有隐式转换) | 37==‘37’ | true |
!= | 不等 | 37!=37 | false |
=== | 全等(要求值和数据类型都一致) | 37===‘37’ | false |
!== | 不全等 | 37!==‘37’ | true |
4.4 逻辑运算符
4.4.1 概述
逻辑运算符 | 说明 |
---|---|
&& | 逻辑与,简称与,and |
|| | 逻辑或,简称或,or |
! | 逻辑非,简称非,not |
4.4.2 短路运算(逻辑中断)
如果&&和||两边任意一个式子不是比较运算,则进入逻辑中断。
原理:当有多个表达式(值)时,左边的表达式值可以确定结果时,就不再继续运算右边的表达式的值。
4.4.2.1 逻辑与
语法: 表达式1 && 表达式2
- 如果第一个表达式的值为真,则返回表达式2
- 如果第一个表达式的值为假,则返回表达式1
console.log(123 && 456); // 456console.log(0 && 456); // 0console.log(0 && 1 + 2 && 456 * 56789); // 0console.log('' && 1 + 2 && 456 * 56789); // ''
4.4.2.2 逻辑或
语法: 表达式1 || 表达式2
- 如果第一个表达式的值为真,则返回表达式1
- 如果第一个表达式的值为假,则返回表达式2
console.log(123 || 456); // 123
console.log(123 || 456 || 456 + 123); // 123
console.log(0 || 456 || 456 + 123); // 456
4.5 赋值运算符
赋值运算符 | 说明 |
---|---|
= | 直接赋值 |
+=、-= | 加、减一个数后再赋值 |
*=、/=、%= | 乘、除、取模后再赋值 |
4.6 运算符优先级
优先级 | 运算符 | 顺序 |
---|---|---|
1 | 小括号 | () |
2 | 一元运算符 | ++ – ! |
3 | 算术运算符 | 先 / % 后+ -* |
4 | 关系运算符 | > >= < <= |
5 | 相等运算符 | == != === !== |
6 | 逻辑运算符 | 先&&后|| |
7 | 赋值运算符 | = |
8 | 逗号运算符 | , |
Chapter5. 流程控制
5.1 流程控制
- 顺序结构
- 分支结构
- 循环结构
5.2 分支结构
5.2.1 if语句
if (条件表达式) { // 执行语句1} else { // 执行语句2 }
5.2.2 三元表达式
表达式1 ? 表达式2 : 表达式3;
如果表达式1为 true ,则返回表达式2的值,如果表达式1为 false,则返回表达式3的值。
5.2.3 switch语句
switch (表达式) { case value1:// 执行语句1; break; case value2:// 执行语句2; break;// ... default:// 执行最后的语句;}
注:执行case 里面的语句时,如果没有break,则继续执行下一个case里面的语句。
5.2.4 switch与if else if的区别
- switch…case 语句通常处理 case为比较确定值的情况, 而 if…else…语句更加灵活,常用于范围判断(大于、
等于某个范围) - switch 语句进行条件判断后直接执行到程序的条件语句,效率更高。而if…else 语句有几种条件,就得判断多
少次。 - 当分支比较少时,if… else语句的执行效率比 switch语句高。
- 当分支比较多时,switch语句的执行效率比较高,而且结构更清晰。
5.3 循环结构
- for
- while
- do…while
5.3.1 for循环
for (初始化变量; 条件表达式; 操作表达式) {// 循环体}
5.3.2 断点调试
断点调试可以帮我们观察程序的运行过程。
断点调试是指自己在程序的某一行设置一个断点,调试时,程序运行到这一行就会停住,然后你可以一步一步往下调试,调试过程中可以看各个变量当前的值,出错的话,调试到出错的代码行即显示错误,停下。
浏览器中按 F12–> sources -->找到需要调试的文件–>在程序的某一行设置断点
Watch: 监视,通过watch可以监视变量的值的变化,非常的常用。
F11: 程序单步执行,让程序一行一行的执行,这个时候,观察watch中变量的值的变化。
5.3.3 while循环
while (条件表达式) {// 循环体代码}
- 使用 while 循环时一定要注意,它必须要有退出条件,否则会成为死循环
- while 循环和 for 循环的不同之处在于 while 循环可以做较为复杂的条件判断,比如判断用户名和密码
- 如果是用来计次数,跟数字相关的,三者使用基本相同,但是我们更喜欢用 for
5.3.4 do-while循环
do {// 循环体代码 - 条件表达式为 true 时重复执行循环体代码} while(条件表达式);
先再执行循环体,再判断,至少会执行一次循环体代码。
5.3.5 continue break
continue 关键字用于立即跳出本次循环,继续下一次循环。
break 关键字用于立即跳出整个循环。
Chaper6. 数组
数组:指一组数据的集合,其中的每个数据被称作元素,在数组中可以存放任意类型的元素。数组是一种将一组数据存储在单个变量名下的优雅方式。
6.1 创建数组
JS创建数组:
- 利用new创建数组
- 利用数组字面量创建数组(数组的字面量就是[])
// 利用new 创建数组 var arr = new Array(); // 创建了一个空的数组// 利用数组字面量创建数组 []var arr = []; // 创建了一个空的数组var arr1 = [1, 2, 'pink老师', true];
声明数组并赋值称为数组的初始化
数组中可以存放任意类型的数据,例如字符串,数字,布尔值等
6.2 获取数组元素
索引(下标):用来访问数组元素的序号(数组下标从 0 开始)。
通过“数组名[索引]”的形式来获取数组中的元素。
console.log(arr1); console.log(arr1[2]); // pink老师 console.log(arr1[3]); // true
6.3 遍历数组
遍历:就是把数组中的每个元素从头到尾都访问一次。通过 for 循环索引遍历数组中的每一项。
var arr = ['red', 'green', 'blue']; for (var i = 0; i < 3; i++) { console.log(arr[i]); }
6.4 数组的长度
使用“数组名.length”可以访问数组元素的数量(数组长度)。
var arrStus = [1,2,3];alert(arrStus.length); // 3
6.5 数组中新增元素
- 通过修改length长度来实现数组扩容的目的。
var arr = ['red', 'green', 'blue', 'pink'];arr.length = 7;console.log(arr);console.log(arr[4]);console.log(arr[5]);console.log(arr[6]);// 其中索引号是 4,5,6 的空间没有给值,就是声明变量未给值,默认值就是 undefined。
- 通过修改数组索引来追加数组元素(更常用)
var arr = ['red', 'green', 'blue', 'pink'];arr[4] = 'hotpink';console.log(arr);
- 不能直接给数组名赋值,否则会覆盖掉以前的数据,该变量的类型从数组变成新赋的值
6.6 数组案例
6.6.1 删除数组指定元素/数组去重
解法:
- 需要一个新数组用于存放筛选之后的数据。
- 遍历原来的数组,把不是 0 的数据添加到新数组里面( 此时要注意采用数组名+索引的格式接收数据)。
- 新数组里面的个数,用 length 不断累加。
var arr = [2, 0, 6, 1, 77, 0, 52, 0, 25, 7];var newArr = [];for (var i = 0; i < arr.length; i++) { if (arr[i] != 0) { newArr[newArr.length] = arr[i]; }}console.log(newArr);
6.6.2 数组冒泡排序
冒泡排序:每一趟把最大值交换到数组的最右边
var arr = [4, 1, 2, 3, 5];for (var i = 0; i <= arr.length - 1; i++) { // 外层循环管趟数 for (var j = 0; j <= arr.length - i - 1; j++) { // 里面的循环管 每一趟的交换次数 // 内部交换2个变量的值 前一个和后面一个数组元素相比较 if (arr[j] < arr[j + 1]) { var temp = arr[j]; arr[j] = arr[j + 1]; arr[j + 1] = temp; } }}console.log(arr);
Chapter7. 函数
7.1 函数的概念
函数:封装了一段可被重复调用执行的代码块。通过此代码块可以实现大量代码的重复使用。
7.2 函数的使用
函数使用分为两步:
- 声明函数
- 调用函数
7.2.1 声明函数
// 声明函数function 函数名() { //函数体代码}
- function 是声明函数的关键字,必须小写
- 函数名一般为动词
7.2.2 调用函数
声明函数本身不会执行代码,只有调用函数时才会执行函数体代码。
// 调用函数函数名(); // 通过调用函数名来执行函数体代码
7.2.3 函数的封装
函数的封装:把一个或多个功能通过函数的方式封装起来,对外只提供一个简单的函数接口。
7.3 函数的参数
7.3.1 形参和实参
形参:在声明函数时,在函数名称后面的小括号中添加的一些参数。
实参:调用该函数时,同样也需要传递相应的参数,就是实参。
参数的作用:在函数内部某些值不能固定,我们可以通过参数在调用函数时传递不同的值进去。
// 带参数的函数声明function 函数名(形参1, 形参2 , 形参3...) { // 可以定义任意多的参数,用逗号分隔 // 函数体}// 带参数的函数调用函数名(实参1, 实参2, 实参3...);
7.3.2 函数参数的传递过程
- 调用时,实参值传递给形参
- 形参可理解为不用声明的变量
7.3. 形参和实参个数不匹配的问题
参数个数 | 说明 |
---|---|
实参个数==形参个数 | 输出正确结果 |
实参个数>形参个数 | 只取到形参的个数 |
实参个数<形参个数 | 多的形参定义为undefined,结果为NaN |
- 在JS中,形参的默认值是undefined
- 尽量要将实参和形参个数一一匹配
function sum(num1, num2) { console.log(num1 + num2);}sum(100, 200); // 形参和实参个数相等,输出正确结果sum(100, 400, 500, 700); // 实参个数多于形参,只取到形参的个数sum(200); // 实参个数少于形参,多的形参定义为undefined,结果为NaN
7.4 函数的返回值
7.4.1 return语句
函数只是实现某种功能,最终的结果需要返回给函数的调用者函数名(),通过return实现。
// 声明函数function 函数名(){ ... return 需要返回的值;}// 调用函数函数名(); // 此时调用函数就可以得到函数体内return 后面的值
- 在使用 return 语句时,函数会停止执行,并返回指定的值
- 如果函数没有 return ,返回的值是 undefined
7.4.2 return终止函数
return 语句之后的代码不被执行。
function add(num1,num2){ //函数体 return num1 + num2; // 注意:return 后的代码不执行 alert('我不会被执行,因为前面有 return');}
7.4.3 return的返回值
return 只能返回一个值。如果用逗号隔开多个值,以最后一个为准。
function add(num1,num2){ //函数体 return num1,num2;}var resNum = add(21,6); // 调用函数,传入两个实参,并通过 resNum 接收函数返回值alert(resNum); // 6
7.4.4 函数没有return返回undefined
函数都是有返回值的:
- 如果有return 则返回 return 后面的值
- 如果没有return 则返回 undefined
7.4.5 break,continue,return的区别
- break :结束当前的循环体(如 for、while)
- continue :跳出本次循环,继续执行下次循环(如 for、while)
- return :不仅可以退出循环,还能够返回 return 语句中的值,同时还可以结束当前的函数体内的代码
7.5 arguments的使用
当我们不确定有多少个参数传递时,可以用arguments来获取。在JavaScript中,arguments实际上是当前函数的一个内置对象。所有函数都内置了一个arguments对象,arguments对象中存储了传递的所有实参。
只有函数才有arguments对象,而且是每个函数都内置好了这个arguments。
arguments展示形式是一个伪数组,因此可以进行遍历。伪数组有以下特点:
- 具有length属性;
- 按索引方式存储数据;
- 不具有数组的push,pop方法。
案例:利用函数求任意个数的最大值
// 利用函数求任意个数的最大值 function getMax() { // arguments = [1,2,3] var max = arguments[0]; for (var i = 1; i < arguments.length; i++) { if (arguments[i] > max) { max = arguments[i]; } } return max; } console.log(getMax(1, 2, 3)); console.log(getMax(1, 2, 3, 4, 5)); console.log(getMax(11, 2, 34, 444, 5, 100));
7.6 函数的两种声明方式
7.6.1 自定义函数(命名函数)
自定义函数:利用函数关键字 function 自定义函数方式。
// 声明定义方式function fn() {...}// 调用 fn();
- 调用函数的代码既可以放到声明函数的前面,也可以放在声明函数的后面。
7.6.2 函数表达式(匿名函数)
函数表达式:类似声明变量。
// 这是函数表达式写法,匿名函数后面跟分号结束var fn = function(){...};// 调用的方式,函数调用必须写到函数体下面fn();
- 函数没有名字,被称为匿名函数
- 函数表达式方式的原理和声明变量的方式是一致的,这个变量里面存的是函数
- 函数调用的代码必须写在函数体后面
Chapter8. 作用域
8.1 作用域概述
作用域:一段程序代码中所用到的名字并不总是有效和可用的,而限定这个名字的可用性的代码范围就是这个名字的作用域。作用域的使用提高了程序逻辑的局部性,增强了程序的可靠性,减少了名字冲突。
JavaScript(ES5)的作用域有两种:
- 全局作用域
- 局部作用域(函数作用域)
全局作用域:作用于所有代码执行的环境(整个 script 标签内部)或者一个独立的 js 文件。
局部作用域:作用于函数内的代码环境,就是局部作用域。 因为跟函数有关系,所以也称为函数作用域。
ES5没有块级作用域。
ES6 中新增了块级作用域。块作用域由 { } 包括,if语句和 for语句里面的{ }也属于块作用域。
8.2 变量的作用域
在JavaScript中,根据作用域的不同,变量可以分为两种:
- 全局变量
- 局部变量
全局变量:在全局作用域下声明的变量叫做全局变量(在函数外部定义的变量)。
- 全局变量在代码的任何位置都可以使用
- 在全局作用域下 var 声明的变量 是全局变量
- 特殊情况下,在函数内不使用 var 声明的变量也是全局变量(不建议使用)
局部变量:在局部作用域下声明的变量叫做局部变量(在函数内部定义的变量)
- 局部变量只能在该函数内部使用
- 在函数内部 var 声明的变量是局部变量
- 函数的形参实际上就是局部变量
全局变量和局部变量的区别:
- 全局变量:在任何一个地方都可以使用,只有在浏览器关闭时才会被销毁,因此比较占内存
- 只在函数内部使用,当其所在的代码块被执行时,会被初始化;当代码块运行结束后,就会被销毁,因此更节省内存空间
8.3 作用域链
作用域链:内部函数访问外部函数的变量,采取的是链式查找的方式来决定取哪一个值,这就是作用域链。(其实就是就近原则)
- 只要是代码,就至少有一个作用域
- 写在函数内部的是局部作用域
- 如果函数中还有函数,那么在这个作用域中就又可以诞生一个作用域
- 根据在内部函数可以访问外部函数变量的这种机制,用链式查找决定哪些数据能被内部函数访问,就称作作用域链
function f1() { var num = 123; function f2() { var num = 0; console.log(num); // 站在目标出发,一层一层的往外查找 } f2(); } var num = 456; f1();// num = 0
Chapter9. 预解析
9.1 预解析概述
JavaScript代码是由浏览器中的JS解析器执行的。JS解析器在运行JavaScript代码的时候分为两步:预解析和代码执行。
- 预解析:在当前作用域下,JS代码执行之前,浏览器会默认把JS里面所有的var还有function提升到当前作用域的最前面。
- 代码执行:按照代码书写的顺序从上往下执行。
9.2 变量预解析和函数预解析
预解析分为变量预解析(变量提升)和函数预解析(函数提升)。
变量提升:将所有变量声明提升到当前作用域的最前面,不提升赋值操作。
函数提升:把所有函数声明提升到当前作用域的最前面,不调用函数。
9.3 预解析案例
案例1:
// 案例1 var num = 10; fun(); function fun() { console.log(num); var num = 20; } // 相当于执行了以下操作 var num; function fun() { var num; console.log(num);// undefined num = 20; } num = 10; fun();
案例2:
// 案例2 f1(); console.log(c); console.log(b); console.log(a); function f1() { var a = b = c = 9; console.log(a); console.log(b); console.log(c); } // 相当于以下代码 function f1() { var a; a = b = c = 9; // 相当于var a = 9;b = 9;c = 9; b和c直接赋值,没有var声明,当全局变量看。 // 集体声明:var a = 9, b = 9, c = 9; console.log(a); console.log(b); console.log(c); } f1(); console.log(c); console.log(b); console.log(a);
- 注:飘红报错Uncaught ReferenceError: a is not a defined是未声明,输出undefined是已声明、未定义(未赋值)。
Chapter10. 对象
10.1 对象概述
对象:在JavaScript中,对象是一组无序的相关属性和方法的集合,所有的事物都是对象,例如字符串、数值、数组和函数等。
对象是由属性和方法组成的。
属性:事物的特性。
方法:事务的行为。
10.2 创建对象的三种方式
在JavaScript中,现阶段可以用三种方式创建对象:
- 利用字面量创建对象
- 利用new Object创建对象
- 利用构造函数创建对象
10.2.1 利用字面量创建对象
对象字面量:花括号{}。里面包含了表达这个具体事物(对象)的属性和方法。
{}里面采取键值对的形式表示。
- 键:相当于属性名
- 值:相当于属性值,可以是任意类型的值
var star = { name : 'pink', age : 18, sex : '男', sayHi : function(){ alert('大家好啊~'); }};
对象的两种属性调用:
- 对象.属性名
- 对象[‘属性名’]
对象的方法调用:
- 对象.方法名()
console.log(star.name) // 调用名字属性console.log(star['name']) // 调用名字属性star.sayHi(); // 调用 sayHi 方法,注意,一定不要忘记带后面的括号
变量、属性、函数、方法的总结:
变量和属性都是用于存储数据的。函数和方法都是实现某种功能的。
- 变量:单独声明并赋值,单独存在。
- 属性:对象里面的变量就是属性,不需要声明,用于描述对象的特征。
- 函数:单独存在,通过函数名()的方法调用。
- 方法:对象里面的函数就是方法,不需要声明,使用对象.方法名()调用,方法用来描述该对象的行为和功能。
10.2.2 利用new Object创建对象
var andy = new Obect();andy.name = 'pink';andy.age = 18;andy.sex = '男';andy.sayHi = function(){ alert('大家好啊~');}
- 对象.属性 = 值;
10.2.3 利用构造函数创建对象
构造函数:一种特殊的函数,主要用于初始化对象,即为对象成员变量赋初始值,总与new运算符一起使用。把对象中一些公共的属性和方法抽取出来,然后封装到这个函数里,这个函数就是构造函数。(封装对象的函数,就是构造函数)
function Star(uname, age, sex) { this.name = uname; this.age = age; this.sex = sex; this.sing = function(sang) { console.log(sang); } } var ldh = new Star('刘德华', 18, '男'); // 调用函数返回的是一个对象 // console.log(typeof ldh); console.log(ldh.name); console.log(ldh['sex']); ldh.sing('冰雨'); var zxy = new Star('张学友', 19, '男'); console.log(zxy.name); console.log(zxy.age); zxy.sing('李香兰')
- 构造函数用于创建某一类对象
- 构造函数首字母要大写
- 构造函数内的属性和方法前需要添加this,表示当前对象的属性和方法。
- 构造函数不需要return返回结果
- 当我们创建对象时,必须用new来调用构造函数
JavaScript里的构造函数类似于java里的类。利用构造函数创建对象的方法也称为对象实例化。
10.3 new关键字
new关键字执行过程:
- new构造函数在内存中创建一个空的对象
- this指向刚创建的空对象
- 执行构造函数里面的代码,给这个新对象添加属性和方法
- 返回这个新对象(所以构造函数里面不需要return)
10.4 遍历对象属性
for…in语句用于对数组或者对象的属性进行循环操作。
//for(变量 in 对象) {}for (var k in obj) { console.log(k); // k变量输出得到的是属性名 console.log(obj[k]); // obj[k]得到是属性值}// for in里面的变量喜欢写k或key
Chapter11. 内置对象
11.1 内置对象概述
JavaScript中有三种对象:自定义对象、内置对象、浏览器对象。前两种属于ECMAScript,第三个是JS独有的,后面讲解。
内置对象:JS语言自带的一些对象,供开发者使用,并提供了一些基本而必要的功能(属性和方法)。帮助我们快速开发。内置对象有Math, Date, Array, String 等。
11.2 查阅文档
学习一个内置对象的使用,只要学会其常用成员的使用即可,我们可以通过查文档学习,可以通过MDN/W3C来查询。
Mozilla 开发者网络(MDN)提供了有关开放网络技术(Open Web)的信息,包括 HTML、CSS 和万维网及 HTML5 应用的 API。
MDN: https://developer.mozilla.org/zh-CN/
- 查阅该方法的功能
- 查看里面参数的意义和类型
- 查看返回值的意义和类型
- 通过 demo 进行测试
11.3 Math
11.3.1 Math概述
Math 对象不是一个构造函数,不需要new来调用,只需要直接使用里面的属性和方法即可。
console.log(Math.PI); // 一个属性,圆周率,3.1415926
11.3.2 Math的几个常用方法
Math.max() 最大值和Math.min() 最小值
console.log(Math.max(1, 99, 3)); // 99 console.log(Math.max(-1, -10)); // -1 console.log(Math.max(1, 99, 'pink老师')); // NaN console.log(Math.max()); // -Infinity
Math.abs() 绝对值
console.log(Math.abs(1)); // 1
console.log(Math.abs(-1)); // 1
console.log(Math.abs('-1')); // 隐式转换 会把字符串型 -1 转换为数字型
console.log(Math.abs('pink')); // NaN
Math.floor() 向下取整
console.log(Math.floor(1.1)); // 1
console.log(Math.floor(1.9)); // 1
Math.max() 向上取整
console.log(Math.ceil(1.1)); // 2
console.log(Math.ceil(1.9)); // 2
Math.round() 四舍五入
console.log(Math.round(1.1)); // 1 console.log(Math.round(1.5)); // 2 console.log(Math.round(1.9)); // 2 console.log(Math.round(-1.1)); // -1 console.log(Math.round(-1.5)); // 注意:这个结果是-1!!
注:四舍五入的情况,其他数字都是四舍五入,但是.5特殊,全部都要往大了取
11.3.3 Math的随机数方法random()
random() 方法可以随机返回一个小数,其取值范围是[0,1)。
想要得到两数之间的随机数(包括两个数在内的):
function getRandom(min, max) { return Math.floor(Math.random() * (max - min + 1)) + min;}
11.4 Date
11.4.1 Date()概述和使用
Date对象和Math对象不一样,它是一个构造函数,所以我们需要实例化后使用。Date实例用来处理日期和时间。
// 使用Date必须用new关键字实例化 var date = new Date(); console.log(date);
- 如果Date()不写参数,就返回当前时间
- 如果Date()写参数,就返回括号里面输入的时间
参数有两种写法:数字型和字符串型
var date1 = new Date(2019, 10, 1); console.log(date1); // 返回的是 11月 不是 10月 var date2 = new Date('2019-10-1 8:8:8'); console.log(date2);
11.4.2 日期格式化
11.4.3 获取日期的总的毫秒形式
11.5 Array
11.6 String
Chapter12. 简单数据类型和复杂数据类型
12.1 简单类型和复杂类型
简单类型:基本数据类型/值类型。在存储时,变量存储的是值本身,因此叫做值类型。JavaScript中有五大基本类型:Number, String, Boolean, undefined, null。
复杂类型:引用类型。在存储时,变量存储的仅仅是地址(引用)。通过new关键字创建的对象(可以是系统对象,可以是自定义对象),如Object, Array, Date等。
12.2 堆和栈
栈:由操作系统自动分配释放存放函数的参数值、局部变量的值等。其操作方式类似于数据结构中的栈。
堆:存储复杂类型(对象),一般由程序员分配释放,若程序员不释放,由垃圾回收机制回收。
12.3 内存分配
值类型变量的数据之间存放在变量(栈空间中)。
引用类型变量(栈空间)里存放的是地址,真实的对象放在堆空间中。
12.4 简单类型传参
函数的形参可以看做是一个变量,当我们把一个值类型变量作为参数传给函数的形参时,其实是把变量在栈空间里的值复制了一份给形参,那么在方法内部对形参作任何修改,都不会影响到外部变量。
// 简单数据类型传参
function fn(a) {
a++;
console.log(a); // 11
}
var x = 10;
fn(x);
console.log(x); // 10
12.5 复杂类型传参
函数的形参也可以看做是一个变量,当我们把引用类型变量传给形参时,其实是把变量在栈空间里保存的堆地址复制给了形参,形参和实参其实保存的是同一个堆地址,所以操作的是同一个对象。
// 复杂数据类型传参
function Person(name) {
this.name = name;
}
function f1(x) { // x = p
console.log(x.name); // 2. 这个输出什么 ? 刘德华
x.name = "张学友";
console.log(x.name); // 3. 这个输出什么 ? 张学友
}
var p = new Person("刘德华");
console.log(p.name); // 1. 这个输出什么 ? 刘德华
f1(p);
console.log(p.name); // 4. 这个输出什么 ? 张学友