1. 数据类型转化
使用表单、prompt 获取过来的数据默认是字符串类型的,此时就不能直接简单的进行加法运算,而需要转换变量的数据类型。通俗来说,就是把一种数据类型的变量转换成另外一种数据类型。
1.1 转换为字符串类型
// 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 + '');
1.2 转换为数字型
// 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.14console.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); // 12console.log('123' - '120');console.log('123' * 1);
1.3 转换为布尔型
代表空、否定的值会被转换为 false ,如 ‘’、0、NaN、null、undefined
console.log(Boolean('')); // falseconsole.log(Boolean(0)); // falseconsole.log(Boolean(NaN)); // falseconsole.log(Boolean(null)); // falseconsole.log(Boolean(undefined)); // falseconsole.log(Boolean('小白')); // trueconsole.log(Boolean(12)); // true
2. 递增运算符练习
var a = 10;++a;var b = ++a + 2;console.log(b); // b = 14var c = 10;c++;var d = c++ + 2;console.log(d); // b = 13var e = 10;var f = e++ + ++e;console.log(f); // b = 22
3. 短路运算(逻辑中断)
短路运算的原理:当有多个表达式(值)时,左边的表达式值可以确定结果时,就不再继续运算右边的表达式的值;
3.1 逻辑与
语法: 表达式1 && 表达式2
如果第一个表达式的值为真,则返回表达式2
如果第一个表达式的值为假,则返回表达式1
3.2 逻辑或
语法: 表达式1 || 表达式2
如果第一个表达式的值为真,则返回表达式1
如果第一个表达式的值为假,则返回表达式2
实例:
var num = 0;console.log(123 || num++); // 123console.log(num); // 0
4. 数组
案例1:筛选数组
要求:将数组 [2, 0, 6, 1, 77, 0, 52, 0, 25, 7] 中大于等于 10 的元素选出来,放入新数组。
案例分析:
1.声明一个新的数组用于存放新数据。
2.遍历原来的数组,找出大于等于 10 的元素。
3.依次追加给新数组 newArr。
实现代码1:
var arr = [2, 0, 6, 1, 77, 0, 52, 0, 25, 7];var newArr = [];// 定义一个变量 用来计算 新数组的索引号var j = 0;for (var i = 0; i < arr.length; i++) {if (arr[i] >= 10) {// 给新数组newArr[j] = arr[i];// 索引号 不断自加j++;}}console.log(newArr);
实现代码2:
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] >= 10) {// 给新数组newArr[newArr.length] = arr[i];}}console.log(newArr);
案例2:删除指定数组元素
要求:将数组[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 = []; // 空数组的默认的长度为 0// 定义一个变量 i 用来计算新数组的索引号for (var i = 0; i < arr.length; i++) {// 找出大于 10 的数if (arr[i] != 0) {// 给新数组// 每次存入一个值,newArr长度都会 +1newArr[newArr.length] = arr[i];}}console.log(newArr);
案例3:翻转数组
要求: 将数组 [‘red’, ‘green’, ‘blue’, ‘pink’, ‘purple’] 的内容反过来存放。
输出: [‘purple’, ‘pink’, ‘blue’, ‘green’, ‘red’]
实现代码1:
var arr = ['red', 'green', 'blue', 'pink', 'purple'];var newArr = [];for (var i = 0; i < arr.length; i++) {// newArr 是接收方,arr 是输送方newArr[i] = arr[arr.length - i - 1];}console.log(newArr);
实现代码2:
var arr = ['red', 'green', 'blue', 'pink', 'purple'];var newArr = [];for (var i = arr.length - 1; i >= 0; i--) {newArr[newArr.length] = arr[i];}console.log(newArr);
案例4:冒泡排序
冒泡排序:是一种算法,把一系列的数据按照一定的顺序进行排列显示(从小到大或从大到小)。
例如,我们可以将数组 [5, 4, 3, 2, 1]中的元素按照从小到大的顺序排序,输出: 1,2,3,4,5
var arr = [5, 4, 3, 2, 1];for (var i = 0; i < arr.length - 1; i++) {// 5个数据一共需要走四趟,长度就是数组长度减一for (var j = 0; j < arr.length - i - 1; j++) {// 第一趟交换四次,第二趟交换三次。。。长度就是数组长度减去次数再减一if (arr[j] > arr[j + 1]) {var temp = arr[j];arr[j] = arr[j + 1];arr[j + 1] = temp;}}}console.log(arr);
5. 函数
5.1 arguments的使用
当我们不确定有多少个参数传递的时候,可以用 arguments 来获取。在 JavaScript 中,arguments 实际上它是当前函数的一个内置对象。所有函数都内置了一个 arguments 对象,arguments 对象中存储了传递的所有实参。
arguments展示形式是一个伪数组,因此可以进行遍历。伪数组具有以下特点:
- 具有 length 属性
- 按索引方式储存数据
-
案例:利用函数求任意个数的最大值
function maxValue() {var max = arguments[0];for (var i = 0; i < arguments.length; i++) {if (max < arguments[i]) {max = arguments[i];}}return max;}console.log(maxValue(2, 4, 5, 9));console.log(maxValue(12, 4, 9));
5.2 函数的两种声明方式
1. 自定义函数方式(命名函数)
利用函数关键字 function 自定义函数方式。
// 声明定义方式function fn() {...}// 调用fn();
因为有名字,所以也被称为命名函数
调用函数的代码既可以放到声明函数的前面,也可以放在声明函数的后面
2. 函数表达式方式(匿名函数)
利用函数表达式方式的写法如下:
// 这是函数表达式写法,匿名函数后面跟分号结束var fn = function(){...};// 调用的方式,函数调用必须写到函数体下面fn();
因为函数没有名字,所以也被称为匿名函数
- 这个 fn 里面存储的是一个函数
- 函数表达式方式原理跟声明变量方式是一致的
-
6. 作用域
6.1 作用域概述
通常来说,一段程序代码中所用到的名字并不总是有效和可用的,而限定这个名字的可用性的代码范围就是这个名字的作用域。作用域的使用提高了程序逻辑的局部性,增强了程序的可靠性,减少了名字冲突。
JavaScript(es6前)中的作用域有两种: 全局作用域
作用于所有代码执行的环境(整个 script 标签内部)或者一个独立的 js 文件。
- 局部作用域(函数作用域)
作用于函数内的代码环境,就是局部作用域。 因为跟函数有关系,所以也称为函数作用域。
6.2 变量的作用域
6.2.1 变量作用域的分类
在JavaScript中,根据作用域的不同,变量可以分为两种:
- 全局变量
-
6.2.2 全局变量
在全局作用域下声明的变量叫做全局变量(在函数外部定义的变量)。
全局变量在代码的任何位置都可以使用
- 在全局作用域下 var 声明的变量是全局变量
特殊情况下,在函数内不使用 var 声明的变量也是全局变量(不建议使用)
6.2.3 局部变量
在局部作用域下声明的变量叫做局部变量(在函数内部定义的变量)
局部变量只能在该函数内部使用
- 在函数内部 var 声明的变量是局部变量
-
6.2.4 全局变量和局部变量的区别
全局变量:在任何一个地方都可以使用,只有在浏览器关闭时才会被销毁,因此比较占内存
局部变量:只在函数内部使用,当其所在的代码块被执行时,会被初始化;当代码块运行结束后,就会被销毁,因此更节省内存空间
6.3 作用域链
只要是代码,就至少有一个作用域
- 写在函数内部的局部作用域
- 如果函数中还有函数,那么在这个作用域中就又可以诞生一个作用域
- 根据在内部函数可以访问外部函数变量的这种机制,用链式查找决定哪些数据能被内部函数访问,就称作作用域链
-
7. 预解析(变量提升)
JavaScript 代码是由浏览器中的 JavaScript 解析器来执行的。JavaScript 解析器在运行 JavaScript 代码的时候分为两步:预解析和代码执行。
预解析:在当前作用域下, JS 代码执行之前,浏览器会默认把带有 var 和 function 声明的变量在内存中进行提前声明或者定义。
- 代码执行: 从上到下执行JS语句。
预解析只会发生在通过 var 定义的变量和 function 上。学习预解析能够让我们知道为什么在变量声明之前访问变量的值是 undefined,为什么在函数声明之前就可以调用函数
案例1:
var a = 25;function abc() {console.log(a);var a = 10;}abc(); // undefined
案例2:
console.log(a)function a() {console.log("aa");}var a = 1;console.log(a);// 以下输出ƒ a() {console.log("aa");}1
案例3:
var a = 18;f1();function f1 () {var b = 9;console.log(a);console.log(b);var a = 123;}// undefined// 9
案例4:
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);
8. 对象
8.1 创建对象的三种方式
在 JavaScript 中,现阶段我们可以采用三种方式创建对象(object):
- 利用字面量创建对象
- 利用 new Object 创建对象
-
8.1.1 利用字面量创建对象
对象字面量:就是花括号 { } 里面包含了表达这个具体事物(对象)的属性和方法。 { } 里面采取键值对的形式表示
键:相当于属性名
值:相当于属性值,可以是任意类型的值(数字类型、字符串类型、布尔类型,函数类型等)
var star = {name : 'pink',age : 18,sex : '男',sayHi : function(){alert('大家好啊~');}};
对象的调用
对象里面的属性调用 : 对象.属性名 ,这个小点 . 就理解为“ 的 ”
- 对象里面属性的另一种调用方式 : 对象[‘属性名’],注意方括号里面的属性必须加引号,我们后面会用
对象里面的方法调用:对象.方法名() ,注意这个方法名字后面一定加括号
console.log(star.name) // 调用名字属性console.log(star['name']) // 调用名字属性star.sayHi(); // 调用 sayHi 方法,注意,一定不要忘记带后面的括号
8.1.2 利用new Object创建对象
跟我们前面学的 new Array() 原理一致
var andy = new Object();andy.name = 'pink';andy.age = 18;andy.sex = '男';andy.sayHi = function(){alert('大家好啊~');}
Object() :第一个字母大写
- new Object() :需要 new 关键字
- 使用的格式:对象.属性 = 值;
8.1.3 利用构造函数创建对象
构造函数 :是一种特殊的函数,主要用来初始化对象,即为对象成员变量赋初始值,它总与 new 运算符一起使用。我们可以把对象中一些公共的属性和方法抽取出来,然后封装到这个函数里面。
在 js 中,使用构造函数要时要注意以下两点:
- 构造函数用于创建某一类对象,其首字母要大写
构造函数要和 new 一起使用才有意义
function Person(name, age, sex) {this.name = name;this.age = age;this.sex = sex;this.sayHi = function() {alert('我的名字叫:' + this.name + ',年龄:' + this.age + ',性别:' + this.sex);}}var bigbai = new Person('大白', 100, '男');var smallbai = new Person('小白', 21, '男');console.log(bigbai.name);console.log(smallbai.name);
注意
1. 构造函数约定首字母大写。
2. 函数内的属性和方法前面需要添加 this ,表示当前对象的属性和方法。
3. 构造函数中不需要 return 返回结果。
4. 当我们创建对象的时候,必须用 new 来调用构造函数。8.1.4 构造函数和对象
构造函数,如 Stars(),抽象了对象的公共部分,封装到了函数里面,它泛指某一大类(class)
- 创建对象,如 new Stars(),特指某一个,通过 new 关键字创建对象的过程我们也称为对象实例化
8.2 new关键字(重点)
new 在执行时会做四件事情:
1. 在内存中创建一个新的空对象。
2. 让 this 指向这个新的对象。
3. 执行构造函数里面的代码,给这个新对象添加属性和方法。
4. 返回这个新对象(所以构造函数里面不需要return)8.3 遍历对象属性
for…in 语句用于对数组或者对象的属性进行循环操作。
其语法如下:
语法中的变量是自定义的,它需要符合命名规范,通常我们会将这个变量写为 k 或者 key。for (变量 in 对象名字) {// 在此执行代码}
for (var k in obj) {console.log(k); // 这里的 k 是属性名console.log(obj[k]); // 这里的 obj[k] 是属性值}
8.4 小结
- 对象可以让代码结构更清晰
2. 对象复杂数据类型object。
3. 本质:对象就是一组无序的相关属性和方法的集合。
4. 构造函数泛指某一大类,比如苹果,不管是红色苹果还是绿色苹果,都统称为苹果。
5. 对象实例特指一个事物,比如这个苹果、正在给你们讲课的pink老师等。
6. for…in 语句用于对对象的属性进行循环操作。9. 内置对象
9.1 内置对象
- JavaScript 中的对象分为3种:自定义对象 、内置对象、 浏览器对象
- 前面两种对象是JS 基础 内容,属于 ECMAScript; 第三个浏览器对象属于我们JS 独有的, 我们JS API 讲解
- 内置对象就是指 JS 语言自带的一些对象,这些对象供开发者使用,并提供了一些常用的或是最基本而必要的功能(属性和方法)
- 内置对象最大的优点就是帮助我们快速开发
- JavaScript 提供了多个内置对象:Math、 Date 、Array、String等
9.2 Math对象
Math 对象不是构造函数,它具有数学常数和函数的属性和方法。跟数学相关的运算(求绝对值,取整、最大值等)可以使用 Math 中的成员。
注意:上面的方法必须带括号Math.PI // 圆周率Math.floor() // 向下取整Math.ceil() // 向上取整Math.round() // 四舍五入版 就近取整 注意 -3.5 结果是 -3Math.abs() // 绝对值Math.max()/Math.min() // 求最大和最小值
案例:封装自己的数学对象
利用对象封装自己的数学对象 里面有 PI 最大值和最小值
// 利用对象封装自己的数学对象 里面有 PI 最大值和最小值var myMath = {PI: 3.141592653,max: function() {var max = arguments[0];for (var i = 1; i < arguments.length; i++) {if (arguments[i] > max) {max = arguments[i];}}return max;},min: function() {var min = arguments[0];for (var i = 1; i < arguments.length; i++) {if (arguments[i] < min) {min = arguments[i];}}return min;}}console.log(myMath.PI);console.log(myMath.max(1, 5, 9));console.log(myMath.min(1, 5, 9));
9.3 日期对象
9.3.1 Date 概述
- Date 对象和 Math 对象不一样,他是一个构造函数,所以我们需要实例化后才能使用
-
9.3.2 Date()方法的使用
1. 获取当前时间必须实例化
var now = new Date();console.log(now); // Fri Jun 24 2022 20:41:30 GMT+0800 (中国标准时间)
2. 时间对象的方法
如果括号里面有时间,就返回参数里面的时间。例如日期格式字符串为‘2019-5-1’,可以写成new Date(‘2019-5-1’) 或者 new Date(‘2019/5/1’)
如果Date()不写参数,就返回当前时间
- 如果Date()里面写参数,就返回括号里面输入的时间

案例: 格式化日期年月日
// 格式化日期 年月日var date = new Date();console.log(date.getFullYear()); // 返回当前日期的年 2019console.log(date.getMonth() + 1); // 月份 返回的月份小1个月 记得月份+1 呦console.log(date.getDate()); // 返回的是 几号console.log(date.getDay()); // 3 周一返回的是 1 周六返回的是 6 但是 周日返回的是 0// 我们写一个 2019年 5月 1日 星期三var year = date.getFullYear();var month = date.getMonth() + 1;var dates = date.getDate();var arr = ['星期日', '星期一', '星期二', '星期三', '星期四', '星期五', '星期六'];var day = date.getDay();console.log('今天是:' + year + '年' + month + '月' + dates + '日 ' + arr[day]);
案例: 格式化日期时分秒
// 格式化日期 时分秒var date = new Date();console.log(date.getHours()); // 时console.log(date.getMinutes()); // 分console.log(date.getSeconds()); // 秒// 要求封装一个函数返回当前的时分秒 格式 08:08:08function getTimer() {var time = new Date();var h = time.getHours();h = h < 10 ? '0' + h : h;var m = time.getMinutes();m = m < 10 ? '0' + m : m;var s = time.getSeconds();s = s < 10 ? '0' + s : s;return h + ':' + m + ':' + s;}
新案例:页面显示事件
需求:将当前时间以:YYYY-MM-DD HH:mm 形式显示在页面
分析:
①:调用时间对象方法进行转换
②:字符串拼接后,通过 innerText 给 标签
<!DOCTYPE html><html lang="en"><head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title><style>div {width: 400px;height: 50px;background-color: pink;text-align: center;line-height: 50px;}</style></head><body><div></div><script>let arr = ['星期日', '星期一', '星期二', '星期三', '星期四', '星期五', '星期六']let div = document.querySelector('div')// 先调用,就省去了1秒的空白期getTime()setInterval(getTime, 1000)function getTime() {// 1. 实例化时间对象 一定写到定时器里面才可以let date = new Date()let year = date.getFullYear()let month = date.getMonth() + 1let date1 = date.getDate()let hour = date.getHours()let min = date.getMinutes()let sec = date.getSeconds()let day = date.getDay()div.innerHTML = `今天是: ${year}年${month}月${date1}日 ${hour < 10 ? '0' + hour : hour}:${min < 10 ? '0' + min : min}:${sec < 10 ? '0' + sec : sec} ${arr[day]}`}</script></body></html>
3.时间戳
- 什么是时间戳
- 是指1970年01月01日00时00分00秒起至现在的毫秒数,它是一种特殊的计量时间的方式
- 三种方式获取时间戳
- 使用 getTime() 和 valueOf() 方法
- 简写 +new Date()
- Date.now()
注意:
Date.now()无需实例化,但是只能得到当前的时间戳, 而前面两种可以返回指定时间的时间戳,比如 console.log(+new Date(‘2021-8-30 12:00:00’))
如果使用getTime() 和 valueOf() 方法获取指定时间的时间戳,那么具体时间放在Date()构造函数里面,不能放在方法的参数中
案例: 获得Date总的毫秒数(时间戳)
// 获得Date总的毫秒数(时间戳) 不是当前时间的毫秒数 而是距离1970年1月1号过了多少毫秒数// 1. 通过 valueOf() getTime()var date = new Date();console.log(date.valueOf()); // 就是 我们现在时间 距离1970.1.1 总的毫秒数console.log(date.getTime());// 2. 简单的写法 (最常用的写法)var date1 = +new Date(); // +new Date() 返回的就是总的毫秒数console.log(date1);// 3. H5 新增的 获得总的毫秒数console.log(Date.now());
案例:倒计时效果
// 倒计时效果// 1.核心算法:输入的时间减去现在的时间就是剩余的时间,即倒计时 ,但是不能拿着时分秒相减,比如 05 分减去25分,结果会是负数的。// 2.用时间戳来做。用户输入时间总的毫秒数减去现在时间的总的毫秒数,得到的就是剩余时间的毫秒数。// 3.把剩余时间总的毫秒数转换为天、时、分、秒 (时间戳转换为时分秒)// 转换公式如下:// d = parseInt(总秒数/ 60/60 /24); // 计算天数// h = parseInt(总秒数/ 60/60 %24) // 计算小时// m = parseInt(总秒数 /60 %60 ); // 计算分数// s = parseInt(总秒数%60); // 计算当前秒数function countDown(time) {var nowTime = +new Date(); // 返回的是当前时间总的毫秒数var inputTime = +new Date(time); // 返回的是用户输入时间总的毫秒数var times = (inputTime - nowTime) / 1000; // times是剩余时间总的秒数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('2019-5-1 18:00:00'));var date = new Date();console.log(date);
新案例:下课倒计时效果
分析:
①用将来时间减去现在时间就是剩余的时间
②核心: 使用将来的时间戳减去现在的时间戳
③最后把剩余的时间转换为 天 时 分 秒
注意:
1. 通过时间戳得到是毫秒,需要转换为 秒 再计算
2. 转换公式:
d = parseInt(总秒数/ 60/60 /24); // 计算天数
h = parseInt(总秒数/ 60/60 %24) // 计算小时
m = parseInt(总秒数 /60 %60 ); // 计算分数
s = parseInt(总秒数%60); // 计算当前秒数
<!DOCTYPE html><html lang="en"><head><meta charset="UTF-8" /><meta http-equiv="X-UA-Compatible" content="IE=edge" /><meta name="viewport" content="width=device-width, initial-scale=1.0" /><title>Document</title><style>.countdown {width: 240px;height: 305px;text-align: center;line-height: 1;color: #fff;background-color: brown;/* background-size: 240px; *//* float: left; */overflow: hidden;}.countdown .next {font-size: 16px;margin: 25px 0 14px;}.countdown .title {font-size: 33px;}.countdown .tips {margin-top: 80px;font-size: 23px;}.countdown small {font-size: 17px;}.countdown .clock {width: 142px;margin: 18px auto 0;overflow: hidden;}.countdown .clock span,.countdown .clock i {display: block;text-align: center;line-height: 34px;font-size: 23px;float: left;}.countdown .clock span {width: 34px;height: 34px;border-radius: 2px;background-color: #303430;}.countdown .clock i {width: 20px;font-style: normal;}</style></head><body><div class="countdown"><p class="next">今天是2021年8月28日</p><p class="title">下班倒计时</p><p class="clock"><span id="hour">00</span><i>:</i><span id="minutes">25</span><i>:</i><span id="scond">20</span></p><p class="tips">现在是18:30:00</p></div><script>let hour = document.querySelector('#hour')let minutes = document.querySelector('#minutes')let scond = document.querySelector('#scond')time()setInterval(time, 1000)function time() {// 1. 得到现在的时间戳let now = +new Date()// 2. 得到指定时间的时间戳let last = +new Date('2023-6-24 22:00:00')// 3. (计算剩余的毫秒数) / 1000 === 剩余的秒数let count = (last - now) / 1000// console.log(count)// 4. 转换为时分秒// h = parseInt(总秒数 / 60 / 60 % 24) // 计算小时let h = parseInt(count / 60 / 60 % 24)h = h < 10 ? '0' + h : h// m = parseInt(总秒数 / 60 % 60); // 计算分数let m = parseInt(count / 60 % 60)m = m < 10 ? '0' + m : m// s = parseInt(总秒数 % 60); // 计算当前秒数let s = parseInt(count % 60);s = s < 10 ? '0' + s : s// console.log(h, m, s)hour.innerHTML = hminutes.innerHTML = mscond.innerHTML = s}</script></body></html>
9.4 数组对象
9.4.1 数组对象的创建
创建数组对象的两种方式
- 字面量方式
- new Array() ```javascript // 创建数组的两种方式 // 1. 利用数组字面量 var arr = [1, 2, 3]; console.log(arr[0]);
// 2. 利用new Array() // var arr1 = new Array(); // 创建了一个空的数组 // var arr1 = new Array(2); // 这个2 表示 数组的长度为 2 里面有2个空的数组元素 var arr1 = new Array(2, 3); // 等价于 [2,3] 这样写表示 里面有2个数组元素 是 2和3 console.log(arr1);
<a name="77f4923a"></a>### 9.4.2 检测是否为数组- instanceof 运算符,可以判断一个对象是否属于某种类型- Array.isArray()用于判断一个对象是否为数组,isArray() 是 HTML5 中提供的方法```javascript// 翻转数组function reverse(arr) {// if (arr instanceof Array) {if (Array.isArray(arr)) {var newArr = [];for (var i = arr.length - 1; i >= 0; i--) {newArr[newArr.length] = arr[i];}return newArr;} else {return 'error 这个参数要求必须是数组格式 [1,2,3]'}}console.log(reverse([1, 2, 3]));console.log(reverse(1, 2, 3));// 检测是否为数组// (1) instanceof 运算符 它可以用来检测是否为数组var arr = [];var obj = {};console.log(arr instanceof Array);console.log(obj instanceof Array);// (2) Array.isArray(参数); H5新增的方法 ie9以上版本支持console.log(Array.isArray(arr));console.log(Array.isArray(obj));
9.4.3 添加删除数组元素的方法

// 添加删除数组元素方法// 1. push() 在我们数组的末尾 添加一个或者多个数组元素 push 推var arr = [1, 2, 3];// arr.push(4, 'pink');console.log(arr.push(4, 'pink'));console.log(arr);// (1) push 是可以给数组追加新的元素// (2) push() 参数直接写 数组元素就可以了// (3) push完毕之后,返回的结果是 新数组的长度// (4) 原数组也会发生变化// 2. unshift 在我们数组的开头 添加一个或者多个数组元素console.log(arr.unshift('red', 'purple'));console.log(arr);// (1) unshift是可以给数组前面追加新的元素// (2) unshift() 参数直接写 数组元素就可以了// (3) unshift完毕之后,返回的结果是 新数组的长度// (4) 原数组也会发生变化// 3. pop() 它可以删除数组的最后一个元素console.log(arr.pop());console.log(arr);// (1) pop是可以删除数组的最后一个元素 记住一次只能删除一个元素// (2) pop() 没有参数// (3) pop完毕之后,返回的结果是 删除的那个元素// (4) 原数组也会发生变化// 4. shift() 它可以删除数组的第一个元素console.log(arr.shift());console.log(arr);// (1) shift是可以删除数组的第一个元素 记住一次只能删除一个元素// (2) shift() 没有参数// (3) shift完毕之后,返回的结果是 删除的那个元素// (4) 原数组也会发生变化
案例:筛选数组
// 有一个包含工资的数组[1500, 1200, 2000, 2100, 1800],要求把数组中工资超过2000的删除,剩余的放到新数组里面var arr = [1500, 1200, 2000, 2100, 1800];var newArr = [];for (var i = 0; i < arr.length; i++) {if (arr[i] < 2000) {// newArr[newArr.length] = arr[i];newArr.push(arr[i]);}}console.log(newArr);
9.4.4 数组排序

// 数组排序// 1. 翻转数组var arr = ['pink', 'red', 'blue'];arr.reverse();console.log(arr);// 2. 数组排序(冒泡排序)var arr1 = [13, 4, 77, 1, 7];arr1.sort(function(a, b) {// return a - b; 升序的顺序排列return b - a; // 降序的顺序排列});// 如果不写function那么只能进行个位数的排序,而且只能升序console.log(arr1);
9.4.5 数组索引方法

// 返回数组元素索引号方法 indexOf(数组元素) 作用就是返回该数组元素的索引号 从前面开始查找// 它只返回第一个满足条件的索引号// 它如果在该数组里面找不到元素,则返回的是 -1// var arr = ['red', 'green', 'blue', 'pink', 'blue'];var arr = ['red', 'green', 'pink'];console.log(arr.indexOf('blue'));// 返回数组元素索引号方法 lastIndexOf(数组元素) 作用就是返回该数组元素的索引号 从后面开始查找var arr = ['red', 'green', 'blue', 'pink', 'blue'];console.log(arr.lastIndexOf('blue')); // 4
案例: 数组去重(重点案例)
// 数组去重 ['c', 'a', 'z', 'a', 'x', 'a', 'x', 'c', 'b'] 要求去除数组中重复的元素。// 1.目标:把旧数组里面不重复的元素选取出来放到新数组中,重复的元素只保留一个,放到新数组中去重。// 2.核心算法:我们遍历旧数组,然后拿着旧数组元素去查询新数组,如果该元素在新数组里面没有出现过,我们就添加,否则不添加。// 3.我们怎么知道该元素没有存在?利用新数组.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'])var demo = unique(['blue', 'green', 'blue'])console.log(demo);
9.4.6 数组转换为字符串

// 数组转换为字符串// 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,pinkconsole.log(arr1.join('-')); // green-blue-pinkconsole.log(arr1.join('&')); // green&blue&pink
9.4.7 其他数组对象
9.5 字符串对象
9.5.1 基本包装类型
为了方便操作基本数据类型,JavaScript 还提供了三个特殊的引用类型:String、Number和 Boolean。
基本包装类型就是把简单数据类型包装成为复杂数据类型,这样基本数据类型就有了属性和方法。
// 下面代码有什么问题?var str = 'andy';console.log(str.length);
按道理基本数据类型是没有属性和方法的,而对象才有属性和方法,但上面代码却可以执行,这是因为 js 会把基本数据类型包装为复杂数据类型,其执行过程如下 :
// 1. 生成临时变量,把简单类型包装为复杂数据类型var temp = new String('andy');// 2. 赋值给我们声明的字符变量str = temp;// 3. 销毁临时变量temp = null;
9.5.2 字符串的不可变
指的是里面的值不可变,虽然看上去可以改变内容,但其实是地址变了,内存中新开辟了一个内存空间。
var str = 'abc';str = 'hello';// 当重新给 str 赋值的时候,常量'abc'不会被修改,依然在内存中// 重新给字符串赋值,会重新在内存中开辟空间,这个特点就是字符串的不可变// 由于字符串的不可变,在大量拼接字符串的时候会有效率问题var str = '';for (var i = 0; i < 100000; i++) {str += i;}console.log(str); // 这个结果需要花费大量时间来显示,因为需要不断的开辟新的空间
9.5.3 根据字符返回位置
字符串所有的方法,都不会修改字符串本身(字符串是不可变的),操作完成会返回一个新的字符串。 
// 字符串对象 根据字符返回位置 str.indexOf('要查找的字符', [起始的位置])var str = '改革春风吹满地,春天来了';console.log(str.indexOf('春'));console.log(str.indexOf('春', 3)); // 从索引号是 3的位置开始往后查找
案例:返回字符位置(重点)
查找字符串”abcoefoxyozzopp”中所有o出现的位置以及次数
// 查找字符串"abcoefoxyozzopp"中所有o出现的位置以及次数// 核心算法:先查找第一个o出现的位置// 然后 只要indexOf 返回的结果不是 -1 就继续往后查找// 因为indexOf 只能查找到第一个,所以后面的查找,一定是当前索引加1,从而继续查找var str = "oabcoefoxyozzopp";var index = str.indexOf('o');var num = 0;// console.log(index);while (index !== -1) {console.log(index);num++;index = str.indexOf('o', index + 1);}console.log('o出现的次数是: ' + num);
课后作业 [‘red’, ‘blue’, ‘red’, ‘green’, ‘pink’,’red’], 求 red 出现的位置和次数
var arr = ['red', 'blue', 'red', 'green', 'pink','red'];var index = arr.indexOf('red');var num = 0;while (index !== -1) {console.log(index);num++;index = arr.indexOf('red', index + 1)}console.log('red出现的次数是: ' + num);
9.5.4 根据位置返回字符(重点)

// 根据位置返回字符// 1. charAt(index) 根据位置返回字符var str = 'andy';console.log(str.charAt(3));// 遍历所有的字符for (var i = 0; i < str.length; i++) {console.log(str.charAt(i));}// 2. charCodeAt(index) 返回相应索引号的字符ASCII值 目的: 判断用户按下了那个键console.log(str.charCodeAt(0)); // 97// 3. str[index] H5 新增的console.log(str[0]); // a
案例:判断出现次数最多的字符(重点)
判断一个字符串 ‘abcoefoxyozzopp’ 中出现次数最多的字符,并统计其次数。
// 有一个对象 来判断是否有该属性 对象['属性名']var o = {age: 18}if (o['sex']) {console.log('里面有该属性');} else {console.log('没有该属性');}// 判断一个字符串 'abcoefoxyozzopp' 中出现次数最多的字符,并统计其次数。// o.a = 1// o.b = 1// o.c = 1// o.o = 4// 核心算法:利用 charAt() 遍历这个字符串// 把每个字符都存储给对象, 如果对象没有该属性,就为1,如果存在了就 +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]++;} else {o[chars] = 1;}}console.log(o);// 2. 遍历对象var max = 0;var ch = '';for (var k in o) {// k 得到是 属性名// o[k] 得到的是属性值if (o[k] > max) {max = o[k];ch = k;}}console.log(max);console.log('最多的字符是' + ch);
9.5.5 字符串操作方法(重点)

// 字符串操作方法// 1. concat('字符串1','字符串2'....)var str = 'andy';console.log(str.concat('red'));// 2. substr('截取的起始位置', '截取几个字符');var str1 = '改革春风吹满地';console.log(str1.substr(2, 2)); // 第一个2 是索引号的2 从第几个开始 第二个2 是取几个字符
9.5.6 其他方法
- replace()方法
- split()方法
- toUpperCase() //转换大写
- toLowerCase() //转换小写 ```javascript // 1. 替换字符 replace(‘被替换的字符’, ‘替换为的字符’) 它只会替换第一个字符 var str = ‘andyandy’; console.log(str.replace(‘a’, ‘b’)); // 有一个字符串 ‘abcoefoxyozzopp’ 要求把里面所有的 o 替换为 var str1 = ‘abcoefoxyozzopp’; while (str1.indexOf(‘o’) !== -1) { str1 = str1.replace(‘o’, ‘‘); } console.log(str1);
// 2. 字符转换为数组 split(‘分隔符’) 前面我们学过 join 把数组转换为字符串 var str2 = ‘red, pink, blue’; console.log(str2.split(‘,’)); var str3 = ‘red&pink&blue’; console.log(str3.split(‘&’));
<a name="khxkL"></a># 10. 简单类型与复杂类型(理解)<a name="kWKFl"></a>## 10.1 简单类型与复杂类型简单类型又叫做基本数据类型或者值类型,复杂类型又叫做引用类型。- 值类型:简单数据类型/基本数据类型,在存储时变量中存储的是值本身,因此叫做值类型 string ,number,boolean,undefined,null- 引用类型:复杂数据类型,在存储时变量中存储的仅仅是地址(引用),因此叫做引用数据类型 通过 new 关键字创建的对象(系统对象、自定义对象),如 Object、Array、Date等<a name="G624R"></a>## 10.2 堆和栈堆栈空间分配区别: <br />1、栈(操作系统):由操作系统自动分配释放存放函数的参数值、局部变量的值等。其操作方式类似于数据结构中的栈; 简单数据类型存放到栈里面 <br />2、堆(操作系统):存储复杂类型(对象),一般由程序员分配释放,若程序员不释放,由垃圾回收机制回收。 复杂数据类型存放到堆里面 <br /><br />注意:JavaScript中没有堆栈的概念,通过堆栈的方式,可以让大家更容易理解代码的一些执行方式,便于将来学习其他语言。<a name="jdtLu"></a>## 10.3 简单类型的内存分配- 值类型(简单数据类型): string ,number,boolean,undefined,null- 值类型变量的数据直接存放在变量(栈空间)中<a name="jNvSH"></a>## 10.4 复杂类型的内存分配- 引用类型(复杂数据类型):通过 new 关键字创建的对象(系统对象、自定义对象),如 Object、Array、Date等- 引用类型变量(栈空间)里存放的是地址,真正的对象实例存放在堆空间中<a name="gi7Fw"></a>## 10.5 简单类型传参函数的形参也可以看做是一个变量,当我们把一个值类型变量作为参数传给函数的形参时,其实是把变量在栈空间里的值复制了一份给形参,那么在方法内部对形参做任何修改,都不会影响到的外部变量。```javascriptfunction fn(a) {a++;console.log(a);}var x = 10;fn(x);console.log(x)// 11// 10
10.6 复杂类型传参
函数的形参也可以看做是一个变量,当我们把引用类型变量传给形参时,其实是把变量在栈空间里保存的堆地址复制给了形参,形参和实参其实保存的是同一个堆地址,所以操作的是同一个对象。
function Person(name) {this.name = name;}function f1(x) { // x = pconsole.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. 这个输出什么 ?// 刘德华// 刘德华// 张学友// 张学友

