JavaScript(浏览器端)=ECMAScript(语法+API)+DOM+BOM
es6开始let代替var声明变量(初始化后可重新赋值),而const声明常量(初始化后不可重新赋值,否则会报错)
const注意事项
- 使用const声明常量,一旦声明,就必须立即初始化,不能留到以后赋值
- const声明的常量,允许在不重新赋值的情况下修改它的值(引用数据类型)
const person={username:'Alex'};
person.username='ZhangSan';
console.log(person); //{username:"ZhangSan"}
let、const和var区别
- 重复声明(已经存在的变量或常量,又声明了一遍)var允许重复声明 而let const不允许
function func(a){
let a=1;
}
func();
- 变量提升(var会提升变量的声明到当前作用域的顶部 而let和const不存在变量提升)
console.log(a);
var a=1;
console.log(a);
console.log(b);
let b=2;
- 暂时性死区(只要作用域内存在let、const,它们所声明的变量或常量就自动绑定这个区域,不再受到外部作用域的影响)
let a=2;
let b=1;
function func(){
console.log(b);
console.log(a);
let a=1;
}
func();
调用func函数,此时a b在函数作用域内,因为b没有在函数内继续声明,它就可以离开当前作用域(即函数作用域)到全局作用域寻找,寻找到全局变量b=1,所以输出,而a已经在函数内继续声明了,即使a在当前作用域找不到,它也不能离开当前作用域去寻找
- window对象的属性和方法(全局作用域中,var声明的变量,通过function声明的函数,会自动变成window对象的属性或方法,而let const不会)
let age=18;
const add=function (){};
console.log(window.age); //undefined
console.log(window.add===add); //false
- 块级作用域(let和const有块级作用域,var没有)
for (let i = 0; i < 3; i++) {}
console.log(i);
// 作用域链
function func(){
for (let i = 0; i < 3; i++) {
console.log(i);
}
}
func();
console.log(i);
作用域链:内层作用域->外层作用域->全局作用域
let和const的应用(点击按钮几控制台就显示几)
在没有学习es6之前,我们使用闭包处理
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<style>
body{
padding: 50px 0 0 150px;
}
.btn{
width: 100px;
height: 100px;
margin-right: 20px;
font-size: 80px;
cursor: pointer;
}
</style>
</head>
<body>
<button class="btn">0</button>
<button class="btn">1</button>
<button class="btn">2</button>
<script>
// 闭包
var btns=document.querySelectorAll('.btn');
for(var i=0;i<btns.length;i++){
(function (index){
btns[index].addEventListener('click',function(){
console.log(index);
})
})(i);
}
</script>
</body>
</html>
学习es6之后,学会利用块级作用域
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<style>
body{
padding: 50px 0 0 150px;
}
.btn{
width: 100px;
height: 100px;
margin-right: 20px;
font-size: 80px;
cursor: pointer;
}
</style>
</head>
<body>
<button class="btn">0</button>
<button class="btn">1</button>
<button class="btn">2</button>
<script>
let btns=document.querySelectorAll('.btn');
for(let i=0;i<btns.length;i++){
(function (index){
btns[index].addEventListener('click',function(){
console.log(index);
})
})(i);
}
</script>
</body>
</html>
模板字符串
模板字符串与一般字符串的区别:没什么区别,就是模板字符串与其他东西一起使用时,方便注入
const person={
username:'Alex',
age:18,
sex:'male'
};
//const info='我的名字是'+person.username+',性别:'+person.sex+',今年'+person.age+'岁了';
//console.log(info);
// 模板字符串
const info=`我的名字是${person.username},性别:${person.sex},今年${person.age}岁了`;
console.log(info);
模板字符串的注意事项
- 模板字符串中,所有的空格、换行或缩进都会被保留在输出之中
- 输出`和\等特殊字符需要在前面多加\
- 模板字符串的注入
const username='alex';
const person={age:18,sex:'male'};
const getSex=function (sex){
return sex==='male'?'男':'女';
}
const info=`${username},${person.age},${getSex(person.sex)}`;
console.log(info);
具体应用
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<style>
body {
padding: 50px 0 0 300px;
font-size: 22px;
}
ul {
padding: 0;
}
p {
margin-bottom: 10px;
}
</style>
</head>
<body>
<p>学生信息表</p>
<ul id="list">
<li style="list-style: none;">信息加载中</li>
</ul>
<script>
const students = [
{
username: 'Alex',
age: 18,
sex: 'male'
},
{
username: 'ZhangSan',
age: 28,
sex: 'male'
},
{
username: 'LiSi',
age: 20,
sex: 'female'
}
];
const list = document.getElementById('list');
let html = "";
for (let i = 0; i < students.length; i++) {
html += `<li>我的名字是:${students[i].username},${students[i].sex},${students[i].age}</li>`;
}
list.innerHTML = html;
</script>
</body>
</html>
箭头函数
箭头函数结构:const/let 函数名=参数 =>函数体
如何将一般函数改写为箭头函数
// 声明形式
function add(){};
// 声明形式 -> 函数表达式形式
const add=function(){};
// 函数表达式形式 -> 箭头函数
const add=()=>{};
箭头函数的注意事项
- 单个参数可以省略圆括号(特别地,无参数或多个参数不能省略圆括号)
// 单个参数
const add = x => {
return x + 1
};
console.log(add(1));
- 单行函数体可以同时省略{}和return
// 单行函数体
const add = (x, y) => x + y;
console.log(add(1, 1));
- 单行对象(需要在花括号外面加上(),让浏览器不再认为是函数体的花括号)
// 单行对象
/*const add=(x,y)=>{
return {
value:x+y
}
};*/
const add=(x,y)=>({
value:x+y
})
console.log(add(1,1));
this指向
- 全局作用域this指向window
- 一般函数(非箭头函数)中的this指向
function add(){
console.log(this);
}
add();//undefined->window
非严格模式下this指向由undefined转换为window,如果加上严格模式下,就为undefined
'use strict';
function add(){
console.log(this);
}
add();//undefined
//'use strict';
function add(){
console.log(this);
}
const calc={
add:add
}
calc.add();
const adder=calc.add; //没有()是赋值
adder(); //调用
function Person(username){
this.username=username;
console.log(this);
}
const p=new Person('晓君');
this指向对象p
箭头函数没有自己的this
const calc={
add:()=>{
console.log(this);
}
};
calc.add();//window
结合作用域来看,调用方法之后,执行语句(当前为箭头函数作用域),因为函数作用域无this,往外看 又无对象作用域 直接找到全局作用域就为window了
const calc = {
add: function () {
const adder = () => {
console.log(this);
};
adder();
}
};
calc.add();
箭头函数没有自己的this,这里的this是add方法的this,谁调用add方法,this就代表谁,显然是calc对象
不适用箭头函数的场景
- 作为构造函数
- 需要this指向调用对象的时候
- 需要使用arguments的时候
// 1.作为构造函数
// 箭头函数没有this
const Person=()=>{};
new Person();
//2.需要this指向调用对象的时候
document.addEventListener('click',()=>{
console.log(this);//window
});
//3.需要使用arguments的时候
// 箭头函数中没有arguments
const add=()=>console.log(arguments);
add();
箭头函数的应用
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>箭头函数的应用</title>
<style>
body {
padding: 50px 0 0 250px;
font-size: 30px;
}
#btn {
width: 100px;
height: 100px;
margin-right: 20px;
font-size: 30px;
cursor: pointer;
}
</style>
</head>
<body>
<button id="btn">开始</button>
<span id="result">0</span>
<script>
const btn = document.getElementById('btn');
const result = document.getElementById('result');
const timer = {
time: 0,
start: function () {
// this
var that = this;
// var self = this;
btn.addEventListener(
'click',
function () {
setInterval(function () {
console.log(this);//window
// this.time++;
// result.innerHTML = this.time;
that.time++;
result.innerHTML = that.time;
}, 1000);
},
false
);
}
};
timer.start();
</script>
</body>
</html>
const btn = document.getElementById('btn');
const result = document.getElementById('result');
const timer = {
time: 0,
start: function () {
// this就指向timer
btn.addEventListener(
'click',
() => {
setInterval(() => {
console.log(this);
this.time++;
result.innerHTML = this.time;
}, 1000);
},
false
);
}
};
timer.start();
解构赋值
解析某一数据的结构,将我们想要的东西提取出来,赋值给变量或常量
数组的解构赋值
- 模式(结构)匹配
- 索引值相同的完成赋值
// 不取的,可以直接用逗号跳过
const [a,[,,b],c]=[1,[2,4,5],3];
console.log(a,b,c); //1,5,3
- 默认值的基本用法
- 默认值的生效条件
- 默认值表达式
// 1.默认值的基本用法
const [a, b] = [];
const [a, b] = [undefined, undefined];
const [a = 1, b = 2] = [];
console.log(a, b); //1,2
// 2.默认值的生效条件
// 只有当一个数组成员严格等于(===)undefined 时,对应的默认值才会生效
// const [a = 1, b = 2] = [3, 0];
// const [a = 1, b = 2] = [3, null];
const [a = 1, b = 2] = [3];
console.log(a, b); //3,2
// 3.默认值表达式
// 如果默认值是表达式,默认值表达式是惰性求值的
const func = () => {
console.log('我被执行了');
return 2;
};
// // const [x = func()] = [1];
const [x = func()] = [];
console.log(x);
数组解构赋值的应用
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>箭头函数的应用</title>
</head>
<body>
<p>123</p>
<p>321</p>
<p>34567</p>
<script>
//1.常见的类数组的解构赋值
//arguments
function func() {
// console.log(arguments);
// console.log(arguments.push);
const [a, b] = arguments;
console.log(a, b);
}
func();
func(1, 2);
//NodeList
console.log(document.querySelectorAll('p'));
const [p1, p2, p3] = document.querySelectorAll('p');
console.log(p1, p2, p3);
//2.函数参数的解构赋值
const array = [1, 1];
// const add = arr => arr[0] + arr[1];
const add = ([x = 0, y = 0]) => x + y;
// console.log(add(array));
console.log(add([]));
// [x,y]=[1,1]
// 3.交换变量的值
let x = 1;
let y = 2;
// let tmp = x;
// x = y;
// y = tmp;
// console.log(x, y);
// [x, y] = [y, x];
[x, y] = [2, 1];
console.log(x, y);
</script>
</body>
</html>
对象解构赋值
- 模式(结构)匹配
- 属性名相同的完成赋值
对象解构赋值的注意事项
- 对象解构赋值的默认值
- 将一个已经声明的变量用于解构赋值
- 可以取到继承的属性
// 1.默认值的生效条件
// 对象的属性值严格等于 undefined 时,对应的默认值才会生效
const { username = 'ZhangSan', age = 0 } = { username: 'alex' };
console.log(username, age);
// 2.默认值表达式
// 如果默认值是表达式,默认值表达式是惰性求值的
// 3.将一个已经声明的变量用于解构赋值
// 如果将一个已经声明的变量用于对象的解构赋值,整个赋值需在圆括号中进行
// let { x } = { x: 1 };
// console.log(x);
let x = 2;
({ x } = { x: 1 });
// [x] = [1];
console.log(x);
// 4.可以取到继承的属性
// const { a = 1} = {};
const { toString } = {};
console.log(toString);
// Object.prototype
// console.log(Object.prototype);
console.log({});
对象解构赋值的应用
const logPersonInfo1 = user => {
console.log(user.username, user.age);
}
// 1.函数参数的解构赋值
const logPersonInfo2 = ({age = 20, username: uname}) => {
console.log(uname, age);
}
logPersonInfo1({username: '张三', age: 18});
logPersonInfo2({username: '李四', age: 18});
logPersonInfo2({username: '赵六'});
// 2.复杂的嵌套
const obj = {
x: 1,
y: [2, 3, 4],
z: {
a: 5,
b: 6
}
}
const {
//y: y, //这里的y:甚至可以不写 直接起别名y
y,
y: [, yy],
z,
z: {
b //起别名给6
}
} = obj;
// 第一个y:代表属性名匹配
// 第二个y:代表属性名匹配值[2,3,4]
console.log(yy, y);
console.log(b, z)
其他数据类型的解构赋值
- 字符串的解构赋值
- 数值和布尔值的解构赋值
// 1.字符串的解构赋值
// 方式一:数组形式的解构赋值
const [a,b,,,e]='hello';
console.log(a,b,e);
// 方式二:对象形式的解构赋值
const {0:m,1:n,length}='hello';
console.log(m,n,length);
// 2.数值和布尔值的解构赋值
// 先将等号右边的值转为对象
const {i=1,toString}=123;
console.log(i,toString);
//const {j=2,toString}=true;
//console.log(b,toString);
// 3.undefined和null的解构赋值
// 由于undefined和null无法转为对象,所以对他们进行解构赋值,都会报错
//const {toString}=undefined;
对象字面量
// 1.什么是对象字面量
// 实例化构造函数生成对象
/*const person=new Object();
person.age=18;
person.speak=function (){};*/
// 对象字面量 (常用)
/*var person={
age:18,
speak:function (){}
};*/
// 2.属性的简洁表示法
// 属性名(默认是字符串形式的,单引号可以省略)
// const age=18;
// const person={
// // 'age':age
// // 当键名和变量名或者常量名一样时,可以只写一个
// age
// }
// console.log(person);
// 3.方法的简洁表示法
const person={
// speak:function (){}
// 方法可以省略冒号和function关键字
speak(){}
};
console.log(person);
方括号语法
- 方括号语法可以写在对象字面量中
// 1.方括号语法用法
const prop='age';
// const person={};
// person[prop]=18;
const person={
[prop]:18
}
console.log(person);
- 方括号可以放什么[ 值或通过计算可以得到值的(表达式)]
// 2.方括号中可以放什么
// 值或通过计算可以得到值的表达式
const prop='age';
const func=()=>'name';
const person={
[prop]:18,
[func()]:'张三',
['sex']:'男',
['s'+'chool']:'广州大学'
};
console.log(person);
- 方括号和点语法区别(点语法是特殊形式,当属性名由数字、字母、下划线以及$构成,并且数字还不能开头时,可以使用点语法)
- 合法标识符可以用来作为变量或常量名
- 当你的属性或方法名为合法标识符时,可以使用点语法,其他情况使用方括号语法
函数参数的默认值
// 函数参数默认值基本用法
// const multiply=(x,y)=>{
// if (typeof y==='undefined'){
// y=1;
// }
// return x*y;
// }
// multiply(2);
const multiply = (x, y = 1) => x * y;
multiply(2); //2
函数参数默认值注意事项
- 默认值生效条件(不传参数或者明确传递undefined作为参数)
- 默认值是表达式,默认值表达式是惰性求值的
- 设置默认值小技巧(函数参数默认值,最好从参数右边开始设置)
函数参数默认值的应用
// 1.接收很多参数的时候
const logUser1=(username='zhangsan',age=0,sex='male')=>console.log(username,age,sex);
logUser1('jessica',18,'female');
logUser1();
// 2.接收一个对象作为参数
const logUser2=options=>console.log(options.username,options.age,options.sex);
logUser2({
username:'lisi',
age:20,
sex:'male'
});
// 3.解构赋值
const logUser3=({username='赵六',age=0,sex='女'})=>console.log(username,age,sex);
logUser3({
username:'wangwu',
age:20,
sex:'male'
});
logUser3({username:'karry'});
// 利用解构赋值默认值
// {username='赵六',age=0,sex='女'}={username:'karry'}
logUser3({});
logUser3();
logUser3()等同于logUser3(undefined)
// 利用解构赋值
{username='赵六',age=0,sex='女'}=undefined
// 利用函数参数默认值
// const logUser3=(options={})=>console.log(username,age,sex);
const logUser3=({username='赵六',age=0,sex='女'}={})=>console.log(username,age,sex);
logUser3();
解释说明:调用logUser3()方法无传参相当于传undefined参数,这时利用函数参数默认值条件,走默认值options={},即走{username='赵六',age=0,sex='女'}={},这时利用解构赋值就可以了