目录
一、声明变量的两种方式
1)、let 声明变量(与var 声明变量的对比)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>
<script>
// var 声明的变量往往会越域
// let 声明的变量有严格局部作用域
{
var a = 1;
let b = 2;
}
console.log(a); //
console.log(b); // ReferenceError: b is not defined
</script>
</body>
</html>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>
<script>
// var 可以声明多次
// let 只能声明一次
var m = 1
var m = 2
let n = 3
let n = 4
console.log(m) // 2
console.log(n) // Identifier 'n' has already been declared
</script>
</body>
</html>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>
<script>
// var 会变量提升
// let 不存在变量提升
console.log(x); // undefined
var x = 10;
console.log(y); //ReferenceError: y is not defined
let y = 20;
</script>
</body>
</html>
2)、const 声明常量(只读变量)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>
<script>
//const
//const 只能声明并赋值一次,否则会报错。
const a = 1;
a = 3; //Uncaught TypeError: Assignment to constant variable.
</script>
</body>
</html>
二、解构表达式
1)、数组解构
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>
<script>
// 数组解构
//题目一:打印arr数组元素
//原始打印方式
let arr = [1,2,3];
let a = arr[0];
let b = arr[1];
let c = arr[2];
console.log(a,b,c)
//使用解构表达式解构数组,并打印
let [a,b,c] = arr;
console.log(a,b,c)
</script>
</body>
</html>
2)、对象解构
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>
<script>
//题目二:声明一个对象person,里面有三个元素,要求打印person内部元素。
const person = {
name: "jack",
age: 21,
language: ['java', 'js', 'css']
}
//原始打印方式
const name = person.name;
const age = person.age;
const language = person.language;
console.log(name, age, language)
//使用解构表达式解构对象,并打印
const { name, age, language } = person;
console.log(name, age, language)
</script>
</body>
</html>
三、字符串处理
1)、字符串扩展
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>
<script>
//字符串扩展
//startsWith():返回布尔值,表示参数字符串是否在原字符串的头部
//endsWith():返回布尔值,表示参数字符串是否在原字符串的尾部。
//includes():返回布尔值,表示是否包含参数字符串。
let str = "hello.vue";
console.log(str.startsWith("hello"));//true
console.log(str.endsWith(".vue"));//true
console.log(str.includes("e"));//true
console.log(str.includes("hello"));//true
</script>
</body>
</html>
2)、字符串模板
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>
<script>
//字符串模板
//1、模板字符串相当于加强版的字符串,可以用反引号`定义多行字符串,且还可以在字符串中加入变量和表达式。示例:
let ss = `<div>
<span>hello world ${20*10}<span>
</div>`;
console.log(ss);
//2、字符串插入变量和表达式。变量名写在 ${} 中,${} 中可以放入 JavaScript 表达式。
function fun() {
return "这是一个函数"
}
let info = `我是${name},今年${age + 10}了, 我想说: ${fun()}`;
console.log(info);
</script>
</body>
</html>
浏览器控制台打印效果:
四、函数优化
1)、函数参数默认值
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>
<script>
//1)、函数参数默认值
//要求:编写一个函数计算“a + b”的和。
//在ES6以前,我们无法给一个函数参数设置默认值,只能采用变通写法:
function add(a, b) {
// 判断b是否为空,为空就给默认值1
b = b || 1;
return a + b;
}
// 传一个参数
console.log(add(10)); // 11
//现在可以这么写:直接给参数写上默认值,没传就会自动使用默认值
function add2(a, b = 1) {
return a + b;
}
console.log(add2(20)); // 21
</script>
</body>
</html>
2)、不定参数
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>
<script>
//2)、不定参数
//不定参数用来表示不确定参数个数,形如:...变量名,由...加上一个具名参数标识符组成。
//具名参数只能放在参数列表的最后,并且有且只有一个不定参数。
//要求:编写一个fun函数,功能如下:传入N个参数,输出传入的N个参数的数目。
function fun(...values) {
console.log(values.length)
}
fun(1, 2) //2
fun(1, 2, 3, 4) //4
</script>
</body>
</html>
3)、箭头函数
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>
<script>
//3)、箭头函数(ES6中定义的简写方式)
//① 一个参数时:
//要求:声明一个参数的函数“print1”,并打印入参。
//以前的方式:
var print1 = function (obj) {
console.log(obj);
}
print1("hello1");//hello1
//现在,使用ES6箭头函数的方式:
var print2 = obj => console.log(obj);
print2("hello2");//hello2
//② 多个参数时:
//计算:a+b的和。
//以前的方式:
var sum1 = function (a, b) {
return a + b;
}
console.log( sum1(11, 12) ); //23
//现在,使用ES6箭头函数的方式:
var sum2 = (a, b) => a + b;
console.log( sum2(11, 12) ); //23
//计算:2a+b 的和
//以前的方式:
var sum3 = function (a, b) {
c = a + b;
return a + c;
}
console.log( sum3(10,20) );// 40
var sum4 = (a, b) => {
c = a + b;
return a + c;
}
console.log( sum4(10, 20) ) // 40
</script>
</body>
</html>
4)、实战:箭头函数结合解构表达式
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>
<script>
//声明一个person对象,打印name
const person = {
name: "jack",
age: 21,
language: ['java', 'js', 'css']
}
//以前的写法:
function hello1(person) {
console.log("hello," + person.name)
}
hello1(person);//hello,jack
//现在,可以使用“箭头函数+解构”的方式简化:
var hello2 = ( {name} ) => console.log("hello," + name);
hello2(person); // hello,jack
</script>
</body>
</html>
五、对象优化
1)、新增的API
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>
<script>
//1)、新增的API(以下列举常用的)
const person = {
name: "jack",
age: 21,
language: ['java', 'js', 'css']
}
//- Object.keys:方法用于获取对象的所有key。
console.log(Object.keys(person));//["name", "age", "language"]
//- Object.values:方法用于获取对象的所有value。
console.log(Object.values(person));//["jack", 21, Array(3)]
//- Object.entries:方法用于获取对象的所有entites。
console.log(Object.entries(person));//[Array(2), Array(2), Array(2)]
//- Object.assign
// 方法用于将所有可枚举属性的值从一个或多个源对象复制到目标对象。它将返回目标对象。
const target = { a: 1 };
const source1 = { b: 2 };
const source2 = { c: 3 };
Object.assign(target, source1, source2);
console.log(target);//{a:1,b:2,c:3}
</script>
</body>
</html>
2)、声明对象简写
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>
<script>
//2)、声明对象简写
const age = 23
const name = "张三"
//说明:这里的第一个age是属性名,第二个age是属性值
const person1 = { age: age, name: name }
console.log(person1);//{age: 23, name: "张三"}
//如果属性名和属性值都一样,就可以简写。
const person2 = { age, name }
console.log(person2);//{age: 23, name: "张三"}
</script>
</body>
</html>
3)、对象的函数属性简写
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>
<script>
//3)、对象的函数属性简写
let person3 = {
name: "jack",
// 以前:
eat: function (food) {
console.log(this.name + "在吃" + food);
},
//现在可以这样:
eat2(food) {
console.log(this.name + "在吃" + food)
},
//甚至,可以使用箭头函数简写
eat3: food => console.log(person3.name + "在吃" + food),
//注意:箭头函数 this 不能使用,否则获取不到值,应该使用“对象.属性”的方式。
eat4: food => console.log(this.name + "在吃" + food)
}
person3.eat("香蕉");//jack在吃香蕉
person3.eat2("苹果")//jack在吃苹果
person3.eat3("橘子");//jack在吃橘子
person3.eat4("菠萝");//在吃菠萝
</script>
</body>
</html>
4)、对象拓展运算符
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>
<script>
//4)、对象拓展运算符
// 1、拷贝对象(深拷贝)
let p1 = { name: "Amy", age: 15 }
//使用扩展运算符,“{...对象}"的方式拷贝对象
let someone = { ...p1 }
console.log(someone) //{name: "Amy", age: 15}
// 2、合并对象
let age1 = { age: 15 }
let name1 = { name: "Amy" }
let p2 = { name: "zhangsan" }
p2 = { ...age1, ...name1 } //如果两个对象的字段名重复,后面对象字段值会覆盖前面对象的字段值
console.log(p2)//{age: 15, name: "Amy"}
</script>
</body>
</html>
六、map 和 reduce 的使用
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>
<script>
//数组中新增了map和reduce方法。
//map():接收一个函数,将原数组中的所有元素用这个函数处理后放入新数组返回。
let arr = ['1', '20', '-5', '3'];
//要求:将arr数组内部的每个元素都乘以2,并返回。
//第一种写法:
arr = arr.map((item) => {
return item * 2
});
console.log(arr);//[2, 40, -10, 6]
//更简便的写法:
arr = arr.map(item => item * 2);
console.log(arr);//[4, 80, -20, 12]
//reduce():为数组中的每一个元素依次执行回调函数,不包括数组中被删除或从未被赋值的元素,
//语法: arr.reduce(callback,[initialValue])
/**
callback(执行数组中每个值的函数,包括四个参数),如下;
1、previousValue (上一次调用回调返回的值,或者是提供的初始值(initialValue))
2、currentValue (数组中当前被处理的元素)
3、index (当前元素在数组中的索引)
4、array (调用 reduce 的数组)*/
let result = arr.reduce((a, b) => {
console.log("上一次处理后:" + a);
console.log("当前正在处理:" + b);
return a + b;
}, 100);
console.log(result) //176
</script>
</body>
</html>
控制台打印:
七、Promise 编排
1)、前言
在JavaScript的世界中,所有代码都是单线程执行的。由于这个"缺陷”,导致JavaScript的所有网络操作,浏览器事件,都必须是异步执行。异步执行可以用回调函数实现。一旦有一连串的ajax请求 a,bc,...后面的请求依赖前面的请求结果,就需要层层嵌套。这种缩进和层层嵌套的方式,非常容易造成上下文代码混乱,我们不得不非常小心翼翼处理内层函数与外层函数的数据,一旦内层函数使用了上层函数的变量,这种混乱程度就会加剧。总之,这种层叠上下文的层层嵌套方式,着实增加了神经的紧张程度。因此,ES6 推出了 “Promise”对象。
2)、案例
实现功能:用户登录,并展示该用户的各科成绩,在页面发送两次请求。
- 查询用户,查询成功说明可以登录;
- 查询用户成功,则根据用户id,查询科目信息;
- 查询科目成功,则根据科目id,获取成绩。
分析
此时后台应该提供三个接口,一个提供用户查询接口,一个提供科目查询接口,一个提供各科成绩查询接口,为了渲染方便,最好响应Json数据。在这里就不编写后台接口了,而是提供三个 json文件,直接提供json数据,模拟后台接口。
3)、Promise 创建
//要想创建一个 promise 对象、可以使用 new 来调用 Promise 的构造器来进行实例化。
var promise = new Promise(function(resolve, reject) {
// 异步处理
// 处理结束后、调用resolve 或 reject
});
//Promise 构造函数包含一个参数和一个带有 resolve(解析)和 reject(拒绝)两个参数的回调。在回调中执行一些操作(例如异步),如果一切都正常,则调用 resolve,否则调用 reject。
//对于已经实例化过的 promise 对象可以调用 promise.then() 方法,传递 resolve 和 reject 方法作为回调。
promise.then(onFulfilled, onRejected)
//promise简化了对error的处理,上面的代码我们也可以这样写:
promise.then(onFulfilled).catch(onRejected)
4)、Promise 改造以前嵌套方式
//1、查出当前用户信息
//2、按照当前用户的id查出他的课程
//3、按照当前课程id查出分数
/* Promise 改造以前嵌套方式 : */
$.ajax({
url: "mock/user.json",
success(data) {
console.log("查询用户:", data);
$.ajax({
url: `mock/user_corse_${data.id}.json`,
success(data) {
console.log("查询到课程:", data);
$.ajax({
url: `mock/corse_score_${data.id}.json`,
success(data) {
console.log("查询到分数:", data);
},
error(error) {
console.log("出现异常了:" + error);
}
});
},
error(error) {
console.log("出现异常了:" + error);
}
});
},
error(error) {
console.log("出现异常了:" + error);
}
});
5)、使用Promise后的嵌套方式
/* 使用Promise后的嵌套方式(Promise可以封装异步操作) */
let p = new Promise((resolve, reject) => {
//异步操作
$.ajax({
url: "mock/user.json",
success: function (data) {
console.log("查询用户成功:", data)
resolve(data);
},
error: function (err) {
reject(err);
}
});
});
p.then((obj) => {
return new Promise((resolve, reject) => {
$.ajax({
url: `mock/user_corse_${obj.id}.json`,
success: function (data) {
console.log("查询用户课程成功:", data)
resolve(data);
},
error: function (err) {
reject(err)
}
});
})
}).then((data) => {
console.log("上一步的结果", data)
$.ajax({
url: `mock/corse_score_${data.id}.json`,
success: function (data) {
console.log("查询课程得分成功:", data)
},
error: function (err) {
}
});
})
6)、使用函数封装请求,优化处理后的方式
/* 使用函数封装请求,优化处理后的方式: */
function get(url, data) {
return new Promise((resolve, reject) => {
$.ajax({
url: url,
data: data,
success: data => {
resolve(data);
},
error: err => {
reject(err)
}
})
});
}
get("mock/user.json")
.then((data) => {
console.log("用户查询成功~~~:", data)
return get(`mock/user_corse_${data.id}.json`);
})
.then((data) => {
console.log("课程查询成功~~~:", data)
return get(`mock/corse_score_${data.id}.json`);
})
.then((data)=>{
console.log("课程成绩查询成功~~~:", data)
})
.catch((err)=>{
console.log("出现异常",err)
});
控制台打印:
八、模块化
1)、什么是模块化?
模块化就是把代码进行拆分,方便重复利用,类似java中的导包,要使用一个包,必须先导包;
在 JS 中没有包的概念,随之而来的是 “模块”。
模块功能主要由两个命令构成:“export” 和“import”。
-
export 命令用于规定模块的对外接口。
-
import 命令用于导入其他模块提供的功能。
2)、export
新建 hello.js 文件
//`export`不仅可以导出对象,一切JS变量都可以导出。比如:基本类型变量、函数、数组、对象。
/* 第一种写法: */
//声明util常量
const util = {
sum(a, b) {
return a + b;
}
}
//导出 常量util
export { util }
/* 第二种写法: */
//导出常量util
export const util = {
sum(a, b) {
return a + b;
}
}
/* 第三种写法: */
//导出默认default,导入时可以任意定义名称,比如叫:'util'
export default {
sum(a, b) {
return a + b;
}
}
新建 user.js文件
//`export`不仅可以导出对象,一切JS变量都可以导出。比如:基本类型变量、函数、数组、对象。
var name = "jack"
var age = 21
function add(a,b){
return a + b;
}
export {name,age,add}
3)、import
新建 main.js 文件
//导入
import util from "./hello.js"
import {name,add} from "./user.js"
//使用导入其他js文件的函数、对象
util.sum(1,2);
console.log(name);
add(1,3);
参考资料:ES6 菜鸟教程