# JS 进阶
# 一、函数
# 1、函数
函数:就是封装了一段可以被重复执行调用的代码块。
目的就是让大量代码重复使用。
function getSum(num1,num2) {
var sum = 0;
for (var i = num1; i <= num2; i++) {
sum += i;
}
console.log(sum);
}
getSum(1,100);
getSum(10,50);
# 2、声明函数和调用函数
函数使用分为两步:声明函数 和 调用函数
// 1. 声明函数
function sayHi() {
console.log('hi~~');
}
// 函数名一般用动词。 函数不调用 自己不执行
// 2. 调用函数
// 函数名();
sayHi();
// 3. 函数的封装:把一个或多个功能通过函数的方式封装起来,对外只提供一个简单的函数接口。 简单理解为:封装类似于将电脑配件整合组装到机箱中(类似快递打包)
# 3、函数的参数
- 形参 和 实参
function 函数名(形参1, 形参2...) {
// 在声明函数的小括号里是 形参(形式上的参数) 形参是接收实参的
}
函数名(实参1, 实参2...);
// 在调用函数的小括号里是 实参 (实际的参数)
- 函数形参 和 实参的匹配问题:
function getSum(num1, num2) {
console.log(num1 + num2);
}
// 1. 实参和形参个数一致 正常输出结果
getSum(1, 2);
// 1. 实参 > 形参个数 取形参的个数
getSum(1, 2, 3);
// 1. 实参 < 形参个数 多余的形参定义 undefined, 最终结果就是 NaN
getSum(1);
# 4、函数的返回值 return
function getSum(num1, num2) {
return num1 + num2; // return后面是需要返回的结果
}
console.log(getSum(1, 2));
# 5、arguments 的使用
arguments:只有函数才有的 arguments 对象, 而且是每个函数都内置好了这个 arguments
function fn() {
console.log(arguments);
console.log(arguments.length);
console.log(arguments[1]);
// 可以按照数组的方式遍历arguments
for (var i = 0; i < arguments.length; i++) {
console.log(arguments[i]);
}
}
fn(1, 2, 3);
// arguments 是伪数组 并不是真正意义上的组
// 1. 具有数组的 length 属性
// 2. 按照索引的方式进行存储的
// 3. 发没有真正数组的一些方法 pop() pus() 等等
# 6、函数的调用
function fn1() {
console.log(111); // 111
fn2();
console.log('fn1'); // 222
}
function fn2() {
console.log(222); // fn2
console.log('fn2'); // fn1
}
fn1();
# 7、函数的两种声明方式
- 利用函数关键字自定义函数(命名函数)
function fn() {
}
fn();
- 函数表达式(匿名函数)
// var 变量名 = function(){};
var fun = function() {
console.log('我是函数表达式');
}
fun();
# 二、JS 的作用域、预解析
# 1、JS 的作用域
- js的作用域:就是代码名字(变量)在某个范围内起作用和效果 目的就是为了提高程序的可靠性 更重要的是减少命名冲突。
- js的作用域(ES6)之前: 全局作用域、局部作用域。
- 全局作用域: 整个script标签 或者是个单独的js文件。
var num = 30;
console.log(num);
- 局部作用域(函数作用域):在函数内就是局部作用域 这个代码的名字只在函数内部起效果和作用。
function fn() {
// 局部作用域
var num = 20;
console.log(num);
}
fn();
# 2、全局变量和局部变量
变量的作用域:根据作用域的不同变量分为 全局变量 和 局部变量
- 局部变量:在全局作用域下的变量 在全局下都可以使用
注意:如果在函数内部 没有声明直接赋值的变量也是与全局变量
var num = 10; // num就是一个全局变量
console.log(num);
function fn() {
console.log(num);
}
fn();
// console.log(aru);
- 局部变量:在局部作用域下的变量 后者函数内部的变量就是局部变量
注意:函数的形参也可以看做是局部变量
function fun(aru) {
var num1 = 10; // num1就是局部变量 只能在函数内部使用
num2 = 20;
}
fun();
console.log(num2);
- 从执行效率来看全局变量和局部变量
(1)全局变量只有浏览器关闭的时候才会毁,比较占内存资源
(2)局部变量 程序执行完毕就会销毁,比节约内存资源
# 3、作用域链
作用域链:内部函数访问外部函数,采取链式查找的方式 来决定取哪个值的结构。
var num = 10;
function fn() { // 外部函数
var num = 20;
function fun() { // 内部函数
console.log(num); // 输出 20
}
fun();
}
fn();
# 4、预解析
js 引擎运行 js 分两步:预解析 代码执行
(1)预解析:js 引擎会把 js 里面所有的 var 还有 function 提升到当前作用域的最前面
(2)代码执行:按照代码书写的顺序从上往下执行预解析分为 变量预解析(变量提升) 和 函数预解析(函数提升)
(1)变量提升:把所有的变量声明提升到当前作用域的最前面 不提升赋值操作
(2)函数提升:把所有的函数声明提升到当前作用域的最前面 不调用函数。
// 1问
console.log(sum);
// 报错
// 2问
console.log(sum);
// undefined 坑1
var sum = 10;
// 相当于执行了以下代码
var sum;
console.log(num);
num = 10;
// 3问
fn();
function fn() {
console.log(11); // 11
}
// 4问
fun(); // 报错
var fun = function() {
console.log(22);
}
// 函数表达式 调用必须写在函数表达式的下面
// 相当于执行了以下代码
var fun;
fun();
fun = function() {
console.log(22);
}
# 三、对象
# 1、对象的概念
在 js 中,对象是一组无序的相关属性和方法的集合
对象由 属性 和 方法 组成。
属性:事物的特征,在对象中用属性来表示(如手机的颜色、大小、重量)。
方法:事物的行为,在对象中用方法来表示 (如手机可以打电话、发短信、玩游戏)。
# 2、利用对象字面量创建对象
var obj = {
uname: '安迪',
age: 18,
sex: '女',
sayHi: function() {
console.log('hi~');
}
}
(1) 里面的属性或者方法我们采取键值对的形式 键 属性名 : 值 属性值
(2) 多个属性或者方法中间用逗号(,)隔开
(3) 方法冒号后面跟的是一个匿名函数
- 使用对象
(1) 调用对象的属性 我们采取 对象名.属性名 .我们理解为 的
console.log(obj.uname);
console.log(obj.sex);
(2) 调用属性还有一种方法 对象名['属性名']
console.log(obj['age']);
(3) 调用对象的方法 sayHi 对象名.方法名() 千万不能忘了添加小括号
obj.sayHi();
# 3、变量、属性、函数、方法的区别
变量和属性相同点: 都是用来存储数据的。
变量: 单独声明并赋值 使用的时候直接写变量名 单独存在。 属性: 在对象里面的不需要声明的 使用的时候必须是 对象.属性。函数和方法的相同点:都是实现某种功能 做某件事。
函数: 单独声明的 并且调用的 函数名() 单独存在的。
方法: 在对象里面 调用的时候 对象.方法。
# 4、利用 new Object 创建对象
var obj = new Object(); // 创建了一个空的对象
obj.uname = '张三';
obj.age = 18;
obj.sex = '男';
obj.sayHi = function() {
console.log('hi~');
}
// (1) 利用等号 = 赋值的方法 添加对象的属性和方法
// (2) 每个属性和方法之间用分号;结束
console.log(obj.uname);
console.log(obj['sex']);
obj.sayHi();
# 5、构造函数
构造函数:可以利用函数的方法 重复相同的代码 里面封装的不是普通代码,而是 对象。
就是把对象里面一些相同的 属性 和 方法 抽象出来封装到函数里面。
# 6、构造函数创建对象
相同的对象: 名字、年龄、性别 相同的方法:唱歌
function 构造函数名() {
this.属性 = 值;
this.方法 = function() {}
}
new 构造函数名();
(一)构造函数: 类似于 java 的 类 (class)
function Star(uname, age, sex) { // 1.构造函数的名首字母大写 Star
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); // object
console.log(ldh.name);
ldh.sing('冰雨');
var zxy = new Star('张学友', 20, '男');
console.log(zxy.name);
ldh.sing('李香兰');
- 构造函数不需要 return 就可以返回结果
- 调用构造函数必须用 new
- 只要 new Star() 调用函数就创建一个对象 如:ldh
- 属性和方法前面必须添加 this
(三) 利用构造函数创建对象的过程称为 对象的实例化。
# 7、new 关键字
- 在内存中创建一个新的对象
- 让 this 指向新的对象
- 执行构造函数里的代码,给这个新对象添加属性和方法
- 返回这个新对象(所以构造函数里面不需要 return)
# 8、遍历对象
var obj = {
name: 'andy',
age: 18,
sex: '女'
}
console.log(obj.name);
console.log(obj.age);
console.log(obj.sex);
# 9、用 for in 遍历对象
for (变量 in 对象) {
}
for (var k in obj) {
console.log(k); // k 变量 输出得到的是 属性名
console.log(obj[k]); // obj[k] 得到的是 属性值
}
# 四、数学对象 Math
# 1. Math 数学对象
Math 数学对象 不是一个构造函数, 所以不需要 new 来调用 而是直接使用里面的属性和方法即可
console.log(Math.PI); // 一个属性 圆周率 3.141592653589793
console.log(Math.max(1, 99, 3)); // 99
console.log(Math.max(1, 'andy')); // NaN
console.log(Math.max()); // -Infinity
# 2. Math 绝对值和三个取整方法
⑴ 绝对值方法 | | Math.abs
console.log(Math.abs(-1)); // 1
console.log(Math.abs('-1')); // 隐式转换 会把字符串型'-1' 转换为字型 -1 所以结果是 1
console.log(Math.abs('pink')); // NaN
⑵ 三个取整方法
① Math.floor() floor(地板) 向下取整(往最小了取值)
console.log(Math.floor(1.1)); // 1
console.log(Math.floor(1.9)); // 1
② Math.ceil() ceil(天花板) 向上取整(往最大了取值)
console.log(Math.ceil(1.1)); // 2
console.log(Math.ceil(1.9)); // 2
③ Math.round() 四舍五入 其他数字都是四舍五入, .5特殊往大了取
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(取大的)
# 3. Math 随机数方法
①. Math随机数方法 random() 返回一个随机的小数 0 =< X < 1 [0,1)
②. 这个方法里面不跟参数
③. 代码验证
console.log(Math.random());
④. 想要得到两个数之间的随机整数 并且 包含这2个整数
// 公式: Math.floor(Math.random() * (max - min + 1)) + min;
function getRandom(min, max) {
return Math.floor(Math.random() * (max - min + 1)) + min;
}
console.log(getRandom(1, 10));
⑤. 随机点名
var arr = ['张三', '王红', '李四', '叶子', '妮妮'];
// console.log(arr[0]);
console.log(arr[getRandom(0, arr.length - 1)]);
# 五、日期对象 Date
Date( ) 日期对象 是一个构造函数 必须用 new 来调用创建日期对象
var arr = new Array(); // 创建了一个数组对象
var obj = new Object(); // 创建了一个对象实例
① 使用 Date 如果没有参数 返回当前系统的当前时间
var date = new Date();
console.log(date); // 系统当前时间
② 参数常用的写法:数字型 2021, 12, 12 或者是 字符串'2021-12-12 10:00:00'
var date1 = new Date(2021, 12, 12);
console.log(date1); // 2022年01月13日
var date2 = new Date('2021-12-12 10:00:00');
console.log(date2); // 2021年12月12日 10:00:00
⑴格式化年月日星期
var date = new Date();
console.log(date.getFullYear()); // 返回当前日期的年 2021
console.log(date.getMonth() + 1); // 月份 12 返回的月份小一个月 记得月份 + 1
console.log(date.getDate()); // 返回的是 几号 13号
console.log(date.getDay()); // 周一 周一返回的是 1, 周六 6, 周日 0
⑵格式化日期时分秒
console.log(date.getHours()); // 时
console.log(date.getMinutes()); // 分
console.log(date.getSeconds()); // 秒
⑶获得 Date 总的毫秒数(时间戳) 不是当前时间的毫秒数 而是距离1970年1月1日过了多少毫秒数
① 通过 valueOf() getTime()
var date = new Date();
console.log(date.valueOf()); // 就是现在的时间 距离1970.1.1 总的毫秒数
console.log(date.getTime());
② 简单的写法(最常用的写法)
var date1 = +new Date(); // +new Date() 返回的就是总的毫秒数
console.log(date1);
③ H5 新增的 获得总的毫秒数
console.log(Date.now());
⑷ 倒计时计算公式
d = parseInt(总秒数 / 60 / 60 / 24); // 计算天数
h = parseInt(总秒数 / 60 / 60 % 24); // 计算小时
m = parseInt(总秒数 / 60 % 60); // 计算分数
s = parseInt(总秒数 % 60); // 计算秒数
# 六、数组对象 Array

# 1. 创建数组的两种方式
⑴ 利用数组字面量
var arr = [2, 1, 5];
console.log(arr[0]);
⑵ 利用 new Array( )
var arr1 = new Array(); // 创建了了一个空的数组
var arr1 = new Array(2); // 这个2表示 数组的长度为2 里面有2个空的数组元素
var arr1 = new Array(2, 1); // 等价于[2, 1] 这么写表示 里面有2个数组元素 是2和1
console.log(arr1);
# 2. 检测是否为数组
⑴ instanceof 运算符 它可以用来检测是否为数组
var arr = [];
var obj = {};
console.log(arr instanceof Array); // true
console.log(obj instanceof Array); // false
⑵ Array.isArray(参数); H5新增的方法 ie9 以上版本支持
Array.isArray(参数) 的优先级比 instanceof 高
console.log(Array.isArray(arr)); // true
console.log(Array.isArray(obj)); // false
# 3. 添加数组元素
⑴ push() 在数组的末尾 添加一个或多个数组元素 push 推
① push 是可以给数组后面 追加新的元素
② push() 参数直接写 数组元素即可
③ push 完毕之后,返回的结果是 新数组的长度
④ 原数组也会发生变化
var arr = [2, 5 ,3];
// arr.push(7, 'andy');
console.log(arr.push(7, 'andy')); // 长度 5
console.log(arr); // [2, 5, 3, 7, 'andy']
⑵ unshift() 在数组的开头 添加一个或多个数组元素
① unshift 是可以给数组前面 追加新的元素
② unshift() 参数直接写 数组元素即可
③ unshift 完毕之后,返回的结果是 新数组的长度
④ 原数组也会发生变化
console.log(arr.unshift('red', 'purple')); // 长度 7
console.log(arr); // ['red', 'purple', 2, 5, 3, 7, 'andy']
# 4. 删除数组元素
⑴ pop( ) 在数组的末尾删除一个数组元素
① pop 是可以删除最后一个数组元素 一次只删一个
② pop() 没有参数
③ pop 完毕之后,返回的结果是 删除的元素
④ 原数组也会发生变化
console.log(arr.pop());
console.log(arr);
⑵ shift() 在数组的开头删除一个数组元素
① shift 是可以删除第一个数组元素 一次只删一个
② shift() 没有参数
③ shift 完毕之后,返回的结果是 删除的元素
④ 原数组也会发生变化
console.log(arr.shift());
console.log(arr);
# 5. 翻转数组
var arr = ['andy', 'red', 'blue'];
arr.reverse();
console.log(arr);
# 6. 数组排序(冒泡排序)★
var arr1 = [13, 5, 66, 54, 1, 6];
arr1.sort(function(a, b) {
// return a - b; 升序排列
return b - a; // 降序排列
});
console.log(arr1);
# 7. 获取数组元素的索引(下标)的方法
⑴ indexOf(数组元素) 作用就是返回该数组元素的索引号 (从前往后找)
var arr = ['red', 'green', 'blue'];
console.log(arr.indexOf('blue')); // 2
它只返回第一个满足条件的索引号
var arr1 = ['red', 'blue', 'green', 'blue'];
console.log(arr1.indexOf('blue')); // 1
它如果在该数组里面找不到元素,则返回的是 -1
var arr2 = ['blue', 'green', 'blue'];
console.log(arr2.indexOf('red')); // -1
⑵ lastIndexOf(数组元素) 作用就是返回该数组元素的索引号 (从后往前找)
var arr3 = ['red', 'blue', 'green', 'yellow'];
console.log(arr3.lastIndexOf('yellow')); // 3
# 8. 数组转换为字符串
⑴ toString() 将数组转换为字符串
var arr = [1, 2, 3];
console.log(arr.toString()); // 1, 2, 3
⑵ join(分隔符)
var arr1 = ['green', 'blue', 'pink'];
console.log(arr1.join()); // 默认用逗号分隔 green, blue, pink
console.log(arr1.join('-')); // green-blue-pink
console.log(arr1.join('&')); // green&blue&pink
⑶ concat() 连接两个或多个数组 不影响原数组, 返回一个新的数组 ⑷ slice() 数组截取slice(begin, end), 返回被截取项目的新数组 ⑸ splice() 数组删除splice(第几个开始,要删除个数) 返回被删除项目的数组,注意,这个会影响原数组
# 七、字符串对象 String
# 1. 基本包装类型
就是把简单数据类型 包装成了 复杂数据类型
var str = 'andy';
console.log(str.length); // 长度为 4
复杂数据类型才有 属性和方法
⑴ 把简单数据类型包装为复杂数据类型
var temp = new String('andy');
⑵ 把临时变量的值 给 str
str = temp;
⑶ 销毁临时变量
temp = null;
# 2. 字符串的不可变性
因为字符串不可变 所以不要大量的拼接字符串
var str = 'andy';
console.log(str);
str = 'red';
console.log(str);
指的是里面的值不可变, 虽然看上去可以改变内容, 但其实是地址变了, 内存中新开辟了一个内存空间。
var str = '';
for (var i = 1; i <= 100; i++) {
str += i;
}
console.log(str);
# 3. 根据字符返回位置
字符串对象 根据字符返回位置 str.indexOf('要查找的字符',[起始的位置])
var str = '改革春风吹满地,春天来了';
console.log(str.indexOf('春')); // 2
console.log(str.indexOf('春', 3)); // 8 从索引号是 3 的位置开始往后查找
console.log(str.lastIndexOf('春')); // 从后往前找,只找第一个匹配的
# 4. 根据位置返回字符
⑴ charAt(index) 根据位置返回字符
var str = 'andy';
console.log(str.charAt(3)); // y
// 遍历所有的字符
for (var i = 0; i < str.length; i++) {
console.log(str.charAt(i)); // a n d y
}
⑵ charCodeAt(index) 返回相应索引号的字符 ASCII 值 目的: 判断用户按下了那个键
console.log(str.charCodeAt(0)); // 97
⑶ str[index] H5 新增的
console.log(str[0]); // a
# 5. 拼接以及截取字符串
字符串的操作方法
⑴ concat('字符串1', '字符串2'....)
var str = 'andy';
console.log(str.concat('red')); // andyred
⑵ substr('截取的起始位置', '截取几个字符');
var str1 = '改革春风吹满地';
console.log(str1.substr(3, 2)); // 第一个是 索引号, 第二个是 取几个字符
# 6. 替换字符串以及转换为数组
⑴ 替换字符 replace('被替换的字符', '替换为的字符') 它只会替换第一个字符
var str = 'andyandy';
console.log(str.replace('a', 'b')); // bndyandy
⑵ 字符转换为数组 split('分隔符') 跟 join 相反
var str2 = 'red, blue, pink';
console.log(str2.split(','));
var str3 = 'red&blue&pink';
console.log(str3.split('&'));
# 八、简单数据类型
# 1、简单数据类型
简单数据类型:又叫做 基本数据类型或者值类型, 复杂数据类型又叫做引用类型
值类型:string、number、boolear、undefined、null
引用类型:通过new创建的对象(系统对象、自定义对象),如:Object、Array、Date等
简单数据类型 null 返回的是一个空的对象 object
如果有个变量以后打算存储为对象,暂时没想好放啥,这个时候就给 null
var timer = null;
console.log(typeof timer); // object
# 2、堆和栈空间分配区别
⑴ 栈:简单数据类型存放到栈里面。里面直接开辟一个空间存放值。
⑵ 堆:复杂数据类型存放到堆里面,首先在栈里存放地址 十六进制表示 然后这个地址指向堆里面的数据。
# 3、简单数据类型传参
function fn(a) {
a++;
console.log(a); // 11
}
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. 输出 张学友