目录
一.计算机编程基础
二.初识 JavaScript
三.JavaScript 变量
四.JavaScript 数据类型
五.标识符、关键字、保留字
六.JavaScript 运算符(操作符)
七.JavaScript 流程控制
八.JavaScript 数组
九.JavaScript 函数
十.JavaScript 作用域
十一.JavaScript 预解析
十二.JavaScript 对象
十三.JavaScript 内置对象
十四.JavaScript 简单数据类型和复杂数据类型
一.计算机编程基础
- 计算机语言分类:
- 机器语言(01011),汇编语言(直接对硬件操作,本质01011),高级语言(C、JAVA等)
- 高级语言必须经过 翻译器 转换,将源代码 二进制化为 机器语言
- 编程语言和标记语言的区别:
- 编程语言:主动的,有很强的逻辑性
- 标记语言:不向计算机发出指令,被动的,被读取的
- 硬盘、内存保存的是 二进制数据;安装软件本质:把程序文件复制到硬盘中
- 运行软件的过程:打开某程序,先从 硬盘 中把程序代码加载到 内存 中,CPU执行 内存中的代码
- 数据存储单位:
- 位(bit): 1bit 可以保存一个 0 或者 1 (最小的存储单位)
- 字节(Byte):1B = 8b
- 太字节(TB): 1TB = 1024GB
二.初识 JavaScript
- JavaScript 定义:
- 运行在客户端的脚本语言 (Script 是脚本的意思)
- 不需要编译,运行过程中由 JS 解释器(JS引擎)【逐行】解释并执行,浏览器本身不执行 JS 代码
- 浏览器分成两部分:渲染引擎 和 JS 引擎
- 渲染引擎:解析HTML与CSS,俗称内核,比如 chrome浏览器的 blink ,老版本的 webkit
- JS 引擎:JS 解释器,读取网页中的 JavaScript代码,对其处理后运行,比如 chrome浏览器的 V8
- JavaScript 作用:
- 表单动态校验(密码强度检测) ( JS 产生最初的目的 )
- 网页特效
- 服务端开发(Node.js)
- 桌面程序(Electron)
- App(Cordova)
- 控制硬件-物联网(Ruff)
- 游戏开发(cocos2d-js)
- JavaScript 组成:
- ECMAScript:规定 JS 的基础语法
- DOM(文档对象模型):提供接口,对页面上的各种元素进行操作(大小、位置等)
- BOM(浏览器对象模型):提供与浏览器窗口进行互动的对象结构,如弹出框、控制浏览器跳转、获取分辨率等
- JavaScript 输入输出语句:
方法 说明 归属 alert(msg) 浏览器弹出警示框(显示消息给用户看) 浏览器 console.log(msg) 浏览器控制台打印输出信息(显示消息给程序员看) 浏览器 prompt(info) 浏览器弹出输入框(用户可以输入) 浏览器
三.JavaScript 变量
- 变量:用于存放数据的容器,通过 变量名 获取 / 修改数据
- 变量本质:是内存里的一块空间,用来存储数据,通过变量名访问这个空间
- 声明变量 var:计算机会自动为变量分配内存空间
- 变量初始化:声明一个变量并赋值(如 var age = 18;)
- 声明多个变量:写一个 var, 多个变量名间,用 英文逗号 隔开并换行(如var age = 10, name = 'xyc', sex = 2; )
- 特殊情况:
情况 说明 结果 var age ; console.log (age);
只声明 不赋值 undefined console.log(age) 不声明 不赋值 直接使用 报错 age = 10; console.log (age); 不声明 只赋值 10 - 交换两个变量的值:
var temp; // 声明了一个临时变量 为空 var apple1 = '青苹果'; var apple2 = '红苹果'; temp = apple1; // 把右边给左边 apple1 = apple2; apple2 = temp;
四.JavaScript 数据类型
1.数据类型定义
- 数据类型决定了:如何将 代表这些值的位 存储到内存中
- JavaScript 是一种弱类型 / 动态语言,即不用提前声明变量类型,程序运行过程中,类型会被自动确定
- JS 是动态语言,变量的数据类型是 可以变化 的:
- var x = 10; // x 是数字型
x = 'TeaMeow'; // x 字符串型2.数据类型分类
- 简单数据类型 (Number,String,Boolean,Undefined,Null)
- 复杂数据类型 (Object)
3.数字型 Number
- Number.MAX_VALUE:最大值,这个值为: 1.7976931348623157e+308
- Number.MIN_VALUE:最小值,这个值为:5e-32
- Infinity :代表无穷大,大于任何数值,如:Number.MAX_VALUE * 2
- -Infinity :代表无穷小,小于任何数值,如:-Number.MAX_VALUE * 2
- NaN :Not a number,代表一个非数值,如:'茶茶子爱吃鸡块'+10086
- isNaN():判断变量是否为 非数值,返回 true(是非数值) 或 false(是数值)
4.字符串型 String
- HTML 使用 双引号,所以 JS 推荐 单引号,不加引号会报错
- 引号嵌套:外双内单,外单内双
- 字符串 + 其他任何数据类型 = 新字符串:alert('11' + 12); // 1112
- 字符串转义字符:
转义符 解释说明 \n 换行符,n 是 newline 的意思 \ \ 斜杠 \ \t tab 缩进 \b 空格 ,b 是 blank 的意思 5.布尔型 Boolean
- console.log(true + 1); // 2 true 相当于1
- console.log(false + 1); // 1 false 相当于0
6.Undefined 和 Null
- 变量声明后,没有赋值:会有默认值 undefined ( 相连【字符串+undefined】、相加【NaN】)
var variable; console.log(variable); // undefined console.log('你好' + variable); // 你好undefined console.log(11 + variable); // NaN console.log(true + variable); // NaN
- 变量声明后,赋 null值:里面存的值为空(相连【字符串+null】、相加【其他变量不变】)
var vari = null; console.log('你好' + vari); // 你好null console.log(11 + vari); // 11 console.log(true + vari); // 1
7.获取变量数据类型 (typeof 变量名)
- prompt() 取过来的值是 字符型的
- var age = prompt('请输入年龄');
console.log(typeof age); // 结果为 String8.数据类型转换
8.1 转换为字符串
- 三种转换方式:
- 变量.toString():var str = num.toString();
- String(变量) :String(num);
- 利用 + 拼接字符串实现转换(隐式转换):console.log(num + '');【最常用】
8.2 转换为数字型(重点)
- parseInt(变量) :可以把 字符型 转换为 整数,注意 parseInt 大小写,不会四舍五入 可以去除数字单位
- parseFloat(变量) :可以把 字符型 转换为 浮点数,注意 parseFloat 大小写,不会四舍五入 可以去除数字单位
- Number(变量)
- 利用算数运算 - * / 隐式转换
var age = prompt('请输入年龄'); 前面说了prompt()获取的是 String类型 console.log(parseInt(age)); console.log(parseInt('3.94')); // 3 取整 不会四舍五入 console.log(parseInt('120px')); // 120 会去到这个px单位 console.log(parseInt('rem120px')); // NaN 数字在最前面 否则不能去除单位 var str = '123'; console.log(Number(str)); console.log('12' - 0); // 12 利用算数运算 +-*/ 隐式转换
8.3 转换为布尔型
- 代表空、否定的值会被转换为 false ,如: ''、0、NaN、null、undefined,console.log(Boolean('')); // false
- 其余值都会被转换为 true,如:console.log(Boolean('比特是狗')); // true
五.标识符、关键字、保留字
1.解释型语言和编译型语言
- 翻译器翻译的方式有两种:一个是编译,一个是解释
- 两种方式区别在于:翻译的时间点不同
- 编译器:在 代码执行之前 进行编译,生成中间代码文件(如 Java 中的 .class 文件)
- 解释器:在 运行时 进行解释,并立即执行(当编译器以解释方式运行的时候,也称之为解释器)
2.标识符、关键字、保留字
- 标识符:指开发人员为变量、属性、函数、参数取的名字,不能是 关键字、保留字
- 关键字:指 JS 本身已经使用了的字,不能再充当变量名、方法名
- 关键字包括:break、case、catch、continue、default、delete、do、else、finally、for、function、if、in、instanceof、new、return、switch、this、throw、try、typeof、var、void、while、with 等
- 保留字:指预留的“关键字”,现在还不是关键字,但未来可能会成为关键字,同样不能当变量名或方法名
- 保留字包括:boolean、byte、char、class、const、debugger、double、enum、export、extends、fimal、float、goto、implements、import、int、interface、long、mative、package、private、protected、public、short、static、super、synchronized、throws、transient、volatile 等
- 如果将保留字用作变量函数名,除非将来的浏览器实现了该保留字,否则可能收不到任何错误消息
六.JavaScript 运算符(操作符)
1.算数运算符
- 浮点数精度问题:浮点数值最高精度是 17 位小数,但进行算术计算时 精确度 远不如整数
- 所以:不要直接判断两个浮点数是否相等 !
var result = 0.1 + 0.2; // 结果不是 0.3,而是:0.30000000000000004 console.log(0.07 * 100); // 结果不是 7,而是:7.000000000000001 // 不能直接拿着浮点数进行比较 var num = 0.1 + 0.2; console.log(num == 0.3); // false
2.递增、递减运算符
- 前置递增运算符(先自加,后返回值)
- 后置递增运算符(先返回原值,后自加)
var num = 10; alert(++num + 10); // 21 // 先执行 ++num 这个表达式,使之结果为11 // 再执行 ++num + 10 这个表达式,使之结果为21 var num = 10; alert(10 + num++); // 20 // 先执行 10 + num++ 这个表达式,使之结果为20,此时是 num++ = 10 参与计算 // 再执行 num++ 这个表达式,使之结果为11 var e = 10; var f = e++ + ++e; // 1.e++ = 10 e = 11 2.e = 12 ++e = 12 console.log(f); // 22
3.比较运算符
//1. 程序里的等于符号 是 == 默认转换数据类型 会把字符串型的数据转换为数字型 只要求值相等就可以 console.log(18 == '18'); // true console.log('茶茶子' == '不喜欢特特'); // flase // 2. 程序里面有全等 要求 两侧的值 还有 数据类型完全一致 console.log(18 === 18); // true console.log(18 === '18'); // false
4.逻辑运算符
- 分类:逻辑与&&、逻辑或||、逻辑非!
- 短路运算(逻辑中断):当有多个表达式时,假设左边表达式可以确定结果,就不再继续运算右边表达式
- 逻辑与:表达式1 && 表达式2,左真返右,左假返左。(简单理解:一个为假就是假)
// 如果有空的或者否定的为假 其余是真的 0 '' null undefined NaN console.log( 123 && 456 ); // 456 console.log( 0 && 456 ); // 0 console.log('' && 1 + 2 && 456 * 56789); // ''
- 逻辑或:表达式1 || 表达式2,左真返左,左假返右。(简单理解:一个为真就是真)
//如果 表达式1 的值为真,则返回 表达式1 //如果 表达式1 的值为假,则返回 表达式2 console.log( 0 || 456 ); // 456 console.log( 123 || 456 || 789 ); // 123
5.赋值运算符
七.JavaScript 流程控制
- 流程控制三种结构:顺序结构、分支结构、循环结构
- 顺序流程控制:程序按照代码的 先后顺序,依次执行
1.分支流程控制
- 分支流程控制:根据不同条件,执行不同路径代码,得到不同结果
- 两种分支结构语句:if 语句、switch 语句
- if else(双分支) 判断闰年:
function backDay() { var year = prompt('请您输入年份:'); if (isRunYear(year)) { // 只有是闰年时 才是true if分支才可以执行 alert('当前年份是闰年2月份有29天'); } else { alert('当前年份是平年2月份有28天'); }} backDay(); function isRunYear(year) { // 如果是闰年返回true 否则返回false var flag = false; if (year % 4 == 0 && year % 100 != 0 || year % 400 == 0) { flag = true; } return flag;}
- if else if(多分支) 判断成绩:成绩从大往小写
var score = prompt('请您输入分数:'); if (score >= 90) { alert('宝贝,你是我的骄傲'); } else if (score >= 80) { alert('你已经很出色了'); } else if (score >= 70) { alert('你要继续加油'); } else { alert('等着挨打吧'); }
- 三元表达式:表达式1 ? 表达式2 : 表达式3,1真执行2,1假执行3
- 时间补0:
var time = prompt('请输入 0-59 之间的一个数字'); var result = time < 10 ? '0' + time : time; alert(result);
- switch 语句:对变量设置 固定值 的选项时,使用 switch
switch :开关 转换 , case :小例子 选项- 执行 case 里面的语句时,如果没有break,则继续执行下个 case里面的语句
- switch中的值 必须和 case中的值 全等===,即 数值+类型 完全相同
- 查询水果:
// case 后面的值写水果名称,一定要加引号 ,因为必须全等匹配 var fruit = prompt('请您输入查询的水果:'); switch (fruit) { case '苹果': alert('苹果的价格是 3.5/斤'); break; default: alert('没有此水果'); }
- switch 语句和 if else if 语句的区别:
- switch 语句通常处理 case 为 确定值 的情况, 而 if…else…语句更加灵活,常用于 范围判断
- switch 语句仅执行符合条件的代码,效率更高,而if…else 语句所有条件代码都得执行,效率不如前者
- 当分支比较少时,if… else 语句的执行效率高
- 当分支比较多时,switch 语句的执行效率高,结构更清晰
2.循环流程控制
2.1 for 循环(与计数有关)
- 断点调试过程:
- 浏览器中按 F12 --> sources --> 找到需要调试的文件 --> 在程序的某一行设置断点
- Watch:监视,通过 watch 可以监视变量的值的变化,非常常用
- 浏览器中按 F11,让程序一行一行的执行,观察 watch 中变量的值的变化
- 班级平均成绩:
var num = prompt('请输入班级的总人数:'); var sum = 0; // 求和的变量 var average = 0; // 求平均值的变量 for (var i = 1; i <= num; i++) { var score = prompt('请您输入第' + i + '个学生成绩'); sum = sum + parseFloat(score); // 字符串型需要转换为数字型 } average = sum / num; alert('班级总的成绩是' + sum); alert('班级平均分是:' + average);
2.2 双重 for 循环
- 外层循环执行一次,内层循环要执行全部次数
- 打印 n行n列 星星:
- 逻辑:内层循环负责打印一行 n个 星星,外层循环负责打印 n行
var rows = prompt('请您输入行数:'); // 行 var cols = prompt('请您输入列数:'); // 列 var str = ''; // 原来的星星是 一个空的字符串 for (var i = 1; i <= rows; i++) { // 外层循环 负责打印总行数 for (var j = 1; j <= cols; j++) { // 内层循环 负责打印每行个数 str = str + '★'; // 在空字符串基础上不断链接星星字符串 } str += '\n'; // 打印了一行星星之后 记得追加换行符号 } console.log(str);
- 打印乘法表:
- 逻辑:外层循环负责行数,内层循环负责每行公式,每行公式的个数 = 行数, j <= i;
var str = ''; // 最初的乘法表是空的 for (var i = 1; i <= 9; i++) { // 外层循环 控制行数 i,打印9行 for (var j = 1; j <= i; j++) { // 内层循环 控制每行公式个数 j j = i str += j + '×' + i + '=' + i * j + '\t'; // 空字符串追加乘法公式 } str += '\n'; // 打印完一行乘法公式 换行 } console.log(str);
2.3 while 循环
- 使用 while 循环时一定要有 退出条件(完成计数器更新),否则会成为死循环
var num = 1; // 计数器 初始化变量 while (num <= 100) { console.log('特特喜欢茶茶'); num++; // 操作表达式 完成计数器的更新 防止死循环 } do { // 至少执行一次 var message = prompt('特特你喜欢我吗?'); } while (message !== '我喜欢你') alert('我也喜欢你ww');
2.4 区分 continue、break
- continue 关键字 退出本次(当前次的循环) 继续执行剩余次数循环
- break 关键字 退出整个循环
- 求除了能被7整除之外的整数的和案例(continue应用)
var sum = 0; for (var i = 1; i <= 100; i++) { if (i % 7 == 0) { continue; } // 只要遇见 continue就退出本次循环 直接跳到 i++ sum += i;} console.log(sum);
八.JavaScript 数组
1.数组定义
- 数组是指 一组数据的集合,其中的每个数据被称作 元素,数组中可以 存放任意类型的元素
- 数组是 将一组数据存储在单个变量名下的 优雅方式
2.创建数组
- 利用 new 创建数组:var arr = new Array();
- 利用 数组字面量 创建数组(使用最多):var cute = ['特特','茶茶','桃西西',9999,true];
- 数组中可以存放任意类型的数据,例如:字符串,数字,布尔值等,如上
3.获取数组中的元素
- 获取数组中的元素:数组名[索引号],索引号从 0 开始
- 如果没有和索引号对应的元素,则输出值是 undefined
4.遍历数组(for 循环)
- 数组的 length 属性可以被修改
- 如果 length 大于数组元素个数,则会在数组末尾追加空白元素
- 如果 length 小于数组元素个数,则会把超过的数组元素删除
索引号从 0 开始的 数组下标, 数组长度是 元素个数// 将数组 ['red', 'green', 'blue', 'pink'] 转换为字符串,并且用 | 或其他符号分割 var arr = ['red', 'green', 'blue', 'pink']; var str = ''; // 采用字符串追加的方式 实现数组到字符串的转换 var sep = '|'; // 分割符号变量 for (var i = 0; i < arr.length; i++) { // 遍历数组 str += arr[i] + sep; // 给空字符串追加 数组元素 以及 分割符号 } console.log(str);
5.新增数组元素
- 修改 length长度
- 修改索引号,追加数组元素,注意不是给数组名直接赋值
var arr = ['red', 'green', 'blue']; // 此时数组长度是3 arr.length = 5; // 修改 length长度 新增数组元素 console.log(arr); // 有五个元素 其中两个因为是空的不显示 console.log(arr[4]); // undefined arr1[7] = 'hotpink'; // 修改索引号 追加数组元素 arr1[0] = 'yellow'; // 替换原来的数组元素 arr1 = '就这?'; // 直接给 数组名赋值 里面的数组元素都没有了
6.筛选数组元素
- 将数组 [2, 0, 6, 1, 77, 0, 52, 0, 25, 7] 中大于等于 10 的元素选出来,放入新数组
- 思路:声明新数组,遍历旧数组,用 新数组[新数组长度] 追加 符合要求的元素
var arr = [2, 0, 6, 1, 77, 0, 52, 0, 25, 7]; var newArr = []; // 1、声明新数组,用于存放新数据newArr for (var i = 0; i < arr.length; i++) { // 2、遍历原数组,找出大于等于 10 的元素 if (arr[i] >= 10) { newArr[newArr.length] = arr[i]; // 3、刚开始 newArr.length 是0 }} console.log(newArr);
7.数组元素去重
- 将数组[2, 0, 6, 1, 77, 0, 52, 0, 25, 7]中的 0 去掉后,形成一个不包含 0 的新数组
- 思路:声明新数组,遍历旧数组,用 新数组[新数组长度] 追加 符合要求的元素
var arr = [2, 0, 6, 1, 77, 0, 52, 0, 25, 7]; var newArr = []; // 1、新建一个数组用于存放筛选之后的数据 for (var i = 0; i < arr.length; i++) { // 2、遍历原来的数组 if (arr[i] != 0) { newArr[newArr.length] = arr[i]; // 3、把不是 0 的数据添加到新数组里 }} console.log(newArr);
8.数组翻转
- 将数组 ['red', 'green', 'blue', 'pink', 'purple'] 的内容反过来存放
- 思路:反过来遍历原数组
var arr = ['red', 'green', 'blue', 'pink', 'purple', 'hotpink']; var newArr = []; // 1、声明一个新数组 newArr for (var i = arr.length - 1; i >= 0; i--) { //2、反过来遍历原来的数组 newArr[newArr.length] = arr[i] } console.log(newArr);
9.冒泡排序
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);
九.JavaScript 函数
1.函数定义
- 函数:封装了一段 可被重复调用执行 的代码块
- 声明函数:function 函数名(形参1,形参2,...){函数体}
- 调用函数:函数名(实参1,实参2,...);
- 声明函数 本身并不会执行代码,只有 调用函数 才会执行 代码
2.函数参数
- 函数可以带参数也可以不带参数,多个参数中间用逗号分隔
- 声明函数的时候,函数名括号里的是形参,形参默认值undefined,相当于不用声明的变量
- 调用函数的时候,函数名括号里的是实参,调用时实参传递给形参
- 形参的个数 可以 和实参个数不匹配,但是结果不可预计(undefined / null),尽量要匹配
3.函数返回值
- return 终止函数,并返回指定的值,return 后的代码不执行
- 如果函数没有 return ,返回的值是 undefined
- return 只能返回最后一个值,如:return num1, num2; // 返回结果是 num2
- return 如果想返回多个值,可以考虑数组,如: return [num1 + num2, num1 * num2, num1 / num2];
- 经常用一个变量来接受 函数的返回结果 如:var re = getArrMax([5, 2, 99, 101, 67, 77]);
- break ,continue ,return 的区别:
- break :结束当前的循环体(如 for、while)
- continue :跳出本次循环,继续执行下次循环(如 for、while)
- return :不仅退出循环,还能够返回 return语句中的值,同时结束当前的函数体内的代码
4.arguments 的使用
- 只有函数才有 arguments对象,而且是每个函数都内置好了 arguments对象
- 当不确定有多少个参数传递的时候,可以用 arguments 来获取
- arguments对象存储了 实参,在函数内部使用
- arguments 是一个伪数组,可以遍历
- 关于伪数组:
- 具有 length属性
- 按索引方式储存数据
- 不具有数组的 push() , pop() 等方法
- 利用函数求任意个数的最大值(不确定输入数,考虑 arguments):
function getMax() { var max = arguments[0]; // 设第一个元素为最大值 for (var i = 1; i < arguments.length; i++) { // arguments.length if (arguments[i] > max) { // 遍历 arguments max = arguments[i]; }} return max; } console.log(getMax(1, 2, 3)); // arguments中存储了这些实参 console.log(getMax(1, 2, 3, 4, 5));
5.函数声明
- 自定义函数方式 ( 命名函数 ):function fn() {}
- 自定义函数:函数调用 既可以放到声明函数的前面,也可以放在声明函数的后面
- 函数表达式 ( 匿名函数):var fn = function(){};
- 匿名函数:函数调用 必须写到 函数体下面;fn是变量名,不是函数名
十.JavaScript 作用域
1.全局作用域和局部作用域
- 全局作用域:作用于所有代码执行的环境
- 局部作用域:作用于函数内的代码环境,也称为函数作用域
- 目的:减少命名冲突
- JS 没有块级作用域 {}(ES6之前)
if(true){ int num = 123; system.out.print(num); // java输出:123 js输出:123 } system.out.print(num); // java输出:报错 js输出:123 // java代码会报错,因为代码中 {} 即一块作用域,其中声明的变量 num,在 “{}” 之外不能使用 // js中没有块级作用域(在ES6之前)
2.全局变量和局部变量
- 在全局作用域下声明的变量 是全局变量 :任何位置都可以使用 浏览器关闭时才会被销毁 比较占内存
- 如果在函数内部 没有声明(写 var),直接赋值 的变量也属于全局变量(不建议使用)
- 在函数内部声明的变量 是局部变量 :只能在该函数内部使用 代码结束就销毁 节约内存
- 函数的形参实际上就是局部变量
var num = 10; // num 是全局变量 任何位置都能使用 function fun(aru) { var num1 = 10; // num1 是局部变量 只能在函数内部使用 num2 = 20; // 没使用函数声明var 所以即使在函数内部 num2依旧是全局变量 }
3.作用域链
- 采取 就近原则 方式来查找变量最终值
var a = 1; function fn1() { var a = 2; var b = '22'; fn2(); function fn2() { var a = 3; fn3(); function fn3() { var a = 4; console.log(a); //a的值 ? 4 就近 console.log(b); //b的值 ? 字符串22 就近 }}} fn1();
十一.JavaScript 预解析
- 预解析定义:变量和函数 的声明 在代码执行之前执行完成,也叫变量 / 函数提升
- 变量提升(变量预解析): 变量的声明会被提升到当前作用域的最上面,变量的赋值不会提升
- 函数提升(函数预解析): 函数的声明会被提升到当前作用域的最上面,但是不会调用函数
var num = 10; fun(); function fun() { console.log(num); var num = 20; } // 相当于执行了以下操作 // var num; // 变量声明提升 // function fun() { // 函数声明提升 // var num; // 函数内部变量声明提升 // console.log(num); // 函数内部代码顺序执行 控制台输出 // num = 20; // 函数内部代码顺序执行 赋值 // } // num = 10; // 外部函数顺序执行 赋值 // fun(); // 外部函数顺序执行 调用内部函数
- 集体声明 和 预解析:
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);
十二.JavaScript 对象
1.使用字面量创建对象(键值对)
var obj = {}; // 创建了一个空的对象 var MeowMeowTea = { name : 'MeowMeowTea', // 键:属性名 值:属性值 age : 20, // 多个属性 用逗号隔开 sayHi : function(){ // 这是匿名函数 alert('茶茶喜欢特特'); }}; // 不要忘记;
- 区分 变量、属性、函数、方法:
- 变量 / 函数:单独声明赋值,单独存在,不是对象的一部分
- 属性 / 方法:对象里面的变量称为属性,不需要声明,是对象的一部分
2.使用 new Object 创建对象
var s = new Obect(); // Object() :第一个字母大写 此时创建了一个空对象 s.name = 'Tea'; // 利用 = 赋值的方法 添加对象的属性和方法 s.age = 20; // 每个属性和方法之间用 分号 结束 s.sayHi = function(){ alert('特特喜欢茶茶'); }
3.使用构造函数创建对象(对象实例化)
- 使用构造函数的原因:减少重复代码
- 前面两种方法每次只能创建一个对象,构造函数每次可创建多个对象
- 构造函数中 不需要 return 返回结果
- 创建对象的时候,必须用 new 来调用构造函数
function Star(uname, age, sex) { // 构造函数名字首字母要大写 this.name = uname; // 属性和方法前面必须添加 this this.age = age; this.sex = sex; this.sing = function(sang) { console.log(sang); }} var obj1 = new Star('茶茶子', 20, '女'); // 用 new 调用函数返回的是一个对象
- new关键字的作用:
- 代码执行之前,创建一个空对象
- 修改 this指向,指向创建出来的空对象
- 给空对象添加属性和方法
- 函数完成之后,返回 this,即创建出来的对象
4.遍历对象(重要)
for (var k in obj) { // key 是变量 可以自己改名 obj是对象名字 console.log(k); // 这里的 k 是属性名 console.log(obj[k]); // 这里的 obj[k] 是属性值 }
十三.JavaScript 内置对象
1.内置对象前言
- JavaScript 中的对象分为3种:自定义对象 、内置对象、 浏览器对象 (JS 独有)
- JS 基础内容包括:自定义对象 + 内置对象,属于 ECMAScript
- JavaScript 提供了多个内置对象:Math、 Date 、Array、String 等
2.Math对象(不是构造函数)
- 不需要实例化 Math (即使用 new 调用)就可以调用里面的属性方法
属性、方法名 功能 Math.PI 圆周率 Math.floor() 向下取整 Math.ceil() 向上取整 Math.round() 四舍五入 就近取整 注意 -3.5 结果是 -3 Math.abs() 绝对值 Math.max() / Math.min() 求最大和最小值 Math.random() 获取范围在[0,1)内的随机值,含0不含1
- 获取指定范围内的随机整数(背下来就可以了):
function getRandom(min, max) { return Math.floor(Math.random() * (max - min + 1)) + min; } // 扩展: 随机点名 var arr = ['茶', '御茶', '茶茶子', '夏小朋友', '鲜柠芦荟茶', '特特给我背锅']; // 令数组下标是个随机数就可以了 console.log(arr[getRandom(0, arr.length - 1)]);
- 寻找最大值、绝对值、取整:
console.log(Math.max(1, 99, '一只比特')); // NaN console.log(Math.max()); // -Infinity // 1.绝对值方法 Math.abs() console.log(Math.abs(-1)); // 1 console.log(Math.abs('-1')); // 隐式转换 会把字符串型 -1 转换为数字型 console.log(Math.abs('Tea')); // NaN // 2.三个取整方法 // (1) Math.floor() 地板 向下取整 往最小了取值 console.log(Math.floor(1.9)); // 1 // (2) Math.ceil() ceil 天花板 向上取整 往最大了取值 console.log(Math.ceil(1.1)); // 2 // (3) Math.round() 四舍五入 其他数字都是四舍五入,但是 .5 特殊 它往大了取 console.log(Math.round(-1.5)); // 这个结果是 -1 ∵取大的 -1 > -2
3.Date对象(是构造函数)
- 需要实例化 Date(使用 new) 才可以调用里面的属性方法
var now = new 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);
- 格式化 年月日:
var date = new Date(); // 别忘记 实例化 Date() var year = date.getFullYear(); // 返回当前日期的年 2020 var month = date.getMonth() + 1; // 返回的月份小1个月 月份+1!! var dates = date.getDate(); // 返回的是 几号 var day = date.getDay(); // 周一返回的是 1 周日返回的是 0 var arr = ['星期日', '星期一', '星期二', '星期三', '星期四', '星期五', '星期六']; console.log('今天是:' + year + '年' + month + '月' + dates + '日 ' + arr[day]);
- 总毫秒数的含义:基于1970年1月1日(世界标准时间)起的毫秒数
- 获取总毫秒数(时间戳):var now = +new Date();
- 倒计时效果 (原理:时间戳、时间格式化):
// 1.核心算法:输入的时间 - 现在的时间 = 剩余的时间,即倒计时 // 2.用时间戳来做:用户输入时间总的毫秒数 - 现在时间的总的毫秒数 // 3.剩余时间总毫秒数 转换为天、时、分、秒 (时间戳转换为时分秒) function countDown(time) { var nowTime = +new Date(); // 当前时间总的毫秒数 var inputTime = +new Date(time); // 用户输入时间总的毫秒数 var times = (inputTime - nowTime) / 1000; // 剩余时间总的秒数 var d = parseInt(times / 60 / 60 / 24); // 天 d = d < 10 ? '0' + d : d; var h = parseInt(times / 60 / 60 % 24); // 时 h = h < 10 ? '0' + h : h; var m = parseInt(times / 60 % 60); // 分 m = m < 10 ? '0' + m : m; var s = parseInt(times % 60); // 当前的秒 s = s < 10 ? '0' + s : s; return d + '天' + h + '时' + m + '分' + s + '秒'; } console.log(countDown('2020-3-22 18:00:00'));
4.Array对象
4.1 检测数组类型
- instanceof 运算符:检测是否为数组
- Array.isArray():检测是否为数组,H5 新增的方法
var arr = [1, 23]; var obj = {}; console.log(arr instanceof Array); // true console.log(Array.isArray(obj)); // false
4.2 添加删除数组元素
- push(数组后)、unshift(数组前):增加元素,每次添加一个或多个,返回新数组长度
- pop(数组后)、shift(数组前):删除元素,每次只能删除一个,返回被删除的的元素
var arr = [1, 2, 3]; console.log(arr.push(4, 'tea')); // 1. push() 数组末尾 添加一个或多个数组元素 console.log(arr.unshift('red', 'purple')); // 2. unshift() 数组开头 添加一个或多个数组元素 console.log(arr.pop()); // 3. pop() 删除数组的最后一个元素 一次只能删除一个 console.log(arr.shift()); // 4. shift() 删除数组的第一个元素 一次只能删除一个
4.3 数组排序(翻转+排序)
- sort()方法:需要传入参数来设置升序、降序排序
- 如果传入“function(a,b){ return a-b;}”,则为升序
- 如果传入“function(a,b){ return b-a;}”,则为降序
- 翻转数组:reverse()方法
// 1. 翻转数组 var arr = ['pink', 'red', 'blue']; arr.reverse(); // 2. 数组排序(冒泡排序) var arr1 = [13, 4, 77, 1, 7]; arr1.sort(function(a, b) { // return a - b; 升序的顺序排列 return b - a; // 降序的顺序排列 });
4.4 查找指定数组元素
- indexOf(数组元素):返回该数组元素的索引号,从 前面 开始查找
- lastIndexOf(数组元素) :返回该数组元素的索引号,从 后面 开始查找
- 只返回 第一个 满足条件的 索引号,如果找不到 数组元素,则返回的是 -1
- 数组去重:
// ['c', 'a', 'z', 'a', 'x', 'a', 'x', 'c', 'b'] 去除重复元素 // 核心算法: 遍历旧数组,用旧数组去查询新数组,若该元素在新数组里没出现过,就添加,否则不添加 // 利用 新数组.indexOf(数组元素) 如果返回时 - 1 就说明 新数组里面没有该元素 // 封装一个 去重的函数:unique() 独一无二的 function unique(arr) { var newArr = []; for (var i = 0; i < arr.length; i++) { // 遍历就旧数组 if (newArr.indexOf(arr[i]) === -1) { // 在新数组中查询旧数组元素 newArr.push(arr[i]); // 新数组查不到旧数组元素 就向里添加旧数组元素 }} return newArr; // 返回新数组 } var demo = unique(['c', 'a', 'z', 'a', 'x', 'a', 'x', 'c', 'b']) console.log(demo);
4.5 数组转换为字符串
- toString():将数组转化为字符串
- join():给数组添加指定分隔符
// 1. toString() 将我们的数组转换为字符串 var arr = [1, 2, 3]; console.log(arr.toString()); // 1,2,3 // 2. join(分隔符) var arr1 = ['green', 'blue', 'pink']; console.log(arr1.join()); // green,blue,pink console.log(arr1.join('-')); // green-blue-pink
5.String对象
5.1 基本包装类型
- 基本包装类型:把 简单数据类型 包装成为 复杂数据类型,这样 基本数据类型 就有了 属性和方法
- 比如 String 作为简单数数据类型不应该有 length属性,但实际上它有,因为被 JS 包装了
5.2 字符串的不可变
- 在内存中重新给字符串赋值,会重新在内存中开辟空间存新值,变量之前保存的旧值不会被修改,旧值仍占据原来的内存空间,这个特点就是字符串的不可变
- 由于字符串的不可变,大量拼接字符串 会有效率问题
5.3 根据字符返回位置
- str.indexOf('要查找的字符', [起始的位置]
- 查找字符串"abcoefoxyozzopp"中所有 o 出现的位置及次数:
var str = "oabcoefoxyozzopp"; var index = str.indexOf('o'); // 查找第一个o出现的位置索引 var num = 0; // 用于统计 o 个数 while (index !== -1) { // 只要存在 o(indexOf 返回的结果不是 -1 )就一直查找 console.log(index); // 打印 o 当前的位置索引 num++; index = str.indexOf('o', index + 1); // 当前索引加1,从而继续向后查找 } console.log('o 出现的次数是: ' + num);
5.4 根据位置返回字符(重点)
- charAt(index):根据位置返回字符,如str.charAt(3)
- 遍历所有的字符:for (var i = 0; i < str.length; i++) {console.log(str.charAt(i));}
- charCodeAt(index) :返回字符ASCII值,判断用户按键
- 判断一个字符串 'abcoefoxyozzopp' 中出现次数最多的字符,并统计其次数:
// 核心算法:利用 charAt() 遍历这个字符串 // 1. 遍历对象,得到最大值和该字符 var str = 'abcoefoxyozzopp'; var o = {}; // 创建了一个空对象 for (var i = 0; i < str.length; i++) { // 遍历字符串 var chars = str.charAt(i); // chars 是字符串的每一个字符 if (o[chars]) { // o[chars] 得到的是属性值 o[chars]++; // 对象存在这个属性 属性出现次数就+1 } else { o[chars] = 1; // 对象不存在这个属性 属性出现次数就是1 }} console.log(o); // 2. 遍历对象 var max = 0; var ch = ''; for (var k in o) { if (o[k] > max) { max = o[k]; // o[k] 属性值 ch = k; // k 属性名 }} console.log(max); console.log('最多的字符是' + ch);
5.5 字符串操作方法(重点)
- 追加指定字符串:concat();
- 截取指定字符串:substr();
// 1. concat('字符串1','字符串2'....) 追加字符串 var str = 'Tea'; console.log(str.concat('red')); // Teared // 2. substr('截取的起始位置', '截取几个字符'); var str1 = '改革春风吹满地'; console.log(str1.substr(2, 2)); // 春风
- 替换指定字符串:replace('被替换的字符', '替换为的字符') ,只会替换第一个字符
- 把字符串转换成数组:split();,前面学过 join:把数组转换为字符串
// 有一个字符串 'abcoefoxyozzopp' 要求把里面所有的 o 替换为 * var str1 = 'abcoefoxyozzopp'; while (str1.indexOf('o') !== -1) { // 只要里面能查到字符 o str1 = str1.replace('o', '*'); // 就把字符 o 替换成 * } console.log(str1); // 2. 字符转换为数组 split('分隔符') var str2 = 'red&pink&blue'; console.log(str2.split('&')); // 得到数组[red,pink,blue]
十四.JavaScript 简单数据类型和复杂数据类型
1.简单数据类型和复杂数据类型
1.1 简单类型(基本数据类型、值类型)
- 在存储时变量中存储的是值本身,包括string ,number,boolean,undefined,null
- 存放在 栈 里面 里面直接开辟一个空间存放值
var timer = null; console.log(typeof timer); // 简单数据类型 null 返回的是一个空的对象 object // 如果有个变量以后打算存储为对象,暂时没想好放啥, 这个时候就给 null
1.2 复杂数据类型(引用类型)
- 在存储时变量中存储的是地址(引用),通过 new 关键字创建的对象,如 Object、Array、Date 等
- 首先在 栈 里面存放地址 十六进制表示 然后这个地址指向 堆 里面的数据
2.堆栈
- 栈:由操作系统自动分配释放存放函数的参数值、局部变量的值等,类似于数据结构中的栈
- 堆:存储复杂类型(对象),一般由程序员分配释放,若程序员不释放,由垃圾回收机制回收
- 简单数据类型的存储方式:值类型变量的数据直接存放在变量(栈空间)中
- 复杂数据类型的存储方式: 引用类型变量(栈空间)里存放的是地址,真正的对象存放在堆中
3.简单数据类型传参
- 函数形参被传送 值类型的实参 时,其实是把变量在 栈 里的值 复制 了一份给形参
- 在方法内部对形参做任何修改,都不会影响到的外部变量
function fn(a) { a++; console.log(a); } var x = 10; fn(x); console.log(x); // 10
4.复杂数据类型传参
- 函数形参被传送 对象类型的实参 时,其实是把变量在 栈 里保存的 堆地址 复制给了形参
- 形参和实参其实保存的是同一个堆地址,所以操作的是同一个对象,会互相影响
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. 这个输出什么 ? 狗比特