let用来声明变量:
案例1: 块级作用域
一对大括号就是一个程序块,在大括号之中声明的变量,出了大括号就不能用了
{
let a = 10;
console.log(a);
}
console.log(a); //报错: a is not defined
for (let i = 0; i < 5; i++) {}
console.log(i); //报错: i is not defined
案例2: 没有变量提升
a = 10;
console.log(a);
let a = 10; //报错: Cannot access 'a' before initialization
案例3: 不能重复声明
let a = 10;
let a = 'abc'; //报错: Identifier 'a' has already been declared
console.log(a);
案例4: 暂时性死区
//虽然在一个页面中声明了两个同名的变量,但是处于不同的作用域内,所以不会产生报错
let a = 10;
{
let a = 'abc';
console.log(a); //正常输出abc
}
console.log(a); //正常输出10
案例: 循环为按钮绑定点击事件,输出当前按钮的索引
循环中使用var 和 let 声明变量 i 结果差异
<button>btn1button>
<button>btn2button>
<button>btn3button>
<script>
var btns = document.querySelectorAll('button');
//核心原因: 为按钮绑定事件的操作很慢,是异步的
//使用var声明i, 则i是全局变量; 循环完成后 i 的值为 3
//此时点击任意按钮,输出的内容都是3
for (var i = 0; i < btns.length; i++) {
btns[i].onclick = function () {
console.log(i);
}
}
//使用let声明的 i 是有块级作用域的,即每进行一次循环,都在内存中开辟一块独立的空间来保存当前 i 的值
for (let i = 0; i < btns.length; i++) {
btns[i].onclick = function () {
console.log(i);
}
}
script>
解析: 每次循环都会产生一个独立的作用域,将当前的 i 进行保存
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-jrrhAalk-1596682576728)(assets/1569229914383.png)]
一旦赋值就不能改变的量就是常量, 常量也有块级作用域
特点:
//声明常量
const PI = 3.1415;
PI = 3.14; //报错: Assignment to constant variable.
//用块级作用域
{
const PI = 3.14;
console.log(PI);
}
console.log(PI); //报错: PI is not defined
//必须初始化
const PI; //报错: Missing initializer in const declaration
//使用const声明的复杂数据类型不能改变,但是能够改变其中的值
const obj = {
name: 'zs',
age : 20,
say : function () {
console.log('ok');
}
}
// obj = {}; //报错
obj.name = 'ls';
obj.say = function () {
console.log('okok');
}
const 锁定了 obj 只能指向 绿色的内存块; 而say是函数,属于复杂数据类型,会另外开辟一块空间来保存
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-neUPamsh-1596682576731)(assets/1569401235252.png)]
#2. 解构赋值
解构赋值就是将对象或者数组中的数据拆解出来分别赋值给某几个变量/常量
let [a, b, c] = ['迪里热巴', '古力娜扎', '马尔扎哈'];
console.log(a); //迪里热巴
console.log(b); //古力娜扎
console.log(c); //马尔扎哈
let [haha, hehe] = ['迪里热巴', '古力娜扎', '马尔扎哈']
console.log(haha); //迪里热巴
console.log(hehe); //古力娜扎
const [x, ,y] = ['迪里热巴', '古力娜扎', '马尔扎哈']
console.log(x); //迪里热巴
console.log(y); //马尔扎哈
const [a, b, ...c] = ['德玛西亚', '诺克萨斯', '艾欧尼亚', '皮尔特沃夫', '暗影岛'];
console.log(a); //德玛西亚
console.log(b); //诺克萨斯
console.log(c); //['艾欧尼亚', '皮尔特沃夫', '暗影岛']
const {name, position} = {name: '孙尚香', position: '射手', gender: '女'};
console.log(name); //孙尚香
console.log(position); //射手
const {position, gender} = {name: '凯', position: '战士', gender: '男'};
console.log(position); //战士
console.log(gender); //男
##2.3 别名
注意: 使用了别名之后,原名就不能使用了
const {name: username} = {name: '艾希', position: 'ADC', gender: '女'};
console.log(username); //艾希
console.log(name); //报错
声明函数时给形参设置默认值。在函数调用时,如果没有传入实参则使用形参默认值;如果传入了实参则使用实参的值。
//声明函数时,形参可以直接赋值就是形参默认值
function add (x = 10, y = 20) {
console.log(x + y);
}
//如果函数调用时传入了实参,则使用实参
add(1, 7); //8
//如果函数调用是没有纯如实参,则使用形参的默认值
add(); //30
函数调用时,实参会以数组形式保存在args变量中
// ...args 就叫做rest参数
// 作用是接收可变参数
function getData (...args) {
console.log(args)
}
getData(111, 'abc', 3.1415, 'haha', 'hehe');
//输出结果: [111, 'abc', 3.1415, 'haha', 'hehe']
// 输出的结果是数组形式,因为 ...args 将所有实参以数组形式保存起来
function show (name, ...info) {
console.log(name);
console.log(info);
}
show('瑞文', '战士', 20, '女');
箭头函数的定义方式
//匿名函数
function () {}
() => {}
//命名函数
let show = function () {}
let show = () => {}
箭头函数的特殊点
案例1: 箭头函数作为构造函数
let Person = () => {
this.name;
this.age;
}
var p = new Person(); //报错: Person is not a constructor
console.log(p);
案例2: 箭头函数中的this
<button>btnbutton>
<script>
//为button注册点击事件,弹出当前按钮上的文字
var btn = document.querySelector('button');
btn.onclick = function () {
alert(this.innerText); //成功弹出,普通函数中this指向调用者
}
btn.onclick = () => {
alert(this.innerText); //弹出undefined,因为this指向window,而window没有innerText属性
}
script>
案例3: 箭头函数没有 arguments
let show = () => {
console.log(arguments); //报错: arguments is not defined
}
show(1,2,3);
案例4: 如果函数体只有一句话,并且还有return返回,则 {} 和 return 都能省略
let add = (x = 1, y = 2) => x + y;
console.log(add(10, 20));
console.log(add());
案例5: 如果函数中只有一个形参,则 () 可以省略
//如果函数中只有一个形参,则 () 可以省略
//注意: 这种方式不能设置形参的默认值
let add = x => x + 5;
console.log(add(3));
<script type="text/javascript">
var age = 100;
var obj = {
age: 20,
say: () => {
alert(this.age)
}
}
obj.say();
script>
解析:因为箭头函数中没有this,所以在say方法中的this不能指向obj,只能指向obj外层的对象;而外层对象是window,而window对象上有age属性,保存了100,所以会输出100
扩展与算符: …
作用: 将数组拆解成以逗号分割的参数序列
示例:
let arr = ['a', 'b', 'c'];
console.log(...arr); //a b c
console.log(arr[0], arr[1], arr[2]);
用途: 需要将数组拆分成多个独立的值时
//1. 函数有若干形参,而实参是一个数组时
let arr = ['刘备', '关羽', '张飞'];
let show = (arg1, arg2, arg3) => {
console.log(arg1 + ': 我是刘知兵');
console.log(arg2 + ': 我是大胡子');
console.log(arg1 + ': 我是喳喳喳');
}
show(...arr)
//2. 将伪数组转为真实的数组,转为数组后可以使用数组对应的函数
<div>div1div>
<div>div2div>
<div>div3div>
<script>
let divs = document.querySelectorAll('div');
console.log(divs);
let arr = [...divs];
console.log(arr);
script>
/**
* 功能: 将伪数组转为真正的数组,并能对数组进行处理
* 参数1: 要转换的伪数组
* 参数2: 要对每个单元应用的函数 (可选参数)
* 参数1: 每个单元值
* 参数2: 每个单元下标
* 返回值: 返回的新数组
*/
let result = Array.from(伪数组, (item, index) => {
//代码块
})
案例1: 转换一般类型的伪数组
<div>div1div>
<div>div2div>
<div>div3div>
<script>
let divs = document.querySelectorAll('div');
let result = Array.from(divs)
console.log(result); // [div, div, div]
script>
案例2: 对象类型伪数组的转换
//属性的数字的对象就是对象类型的伪数组
var obj = {
0: 'zs',
1: 20,
length: 2 //注意: 此处必须设置数组长度
}
var result = Array.from(obj);
console.log(result); // ['zs', 20]
案例3: 对转换后的伪数组进行操作
// 将伪数组转为数组,并为每个单元增加 √
let obj = {
0: 'lol',
1: '吃鸡',
2: '云顶之弈',
length: 3
}
//item: 每个单元值
//index: 每个单元下标
let newArr = Array.from(obj, (item, index) => {
console.log(item);
console.log(index);
})
let result = Array.from(obj, item => item += '√');
console.log(result);
/**
* 功能: 返回满足条件的第一个单元值
* 参数1: 单元值
* 参数2: 单元下标
* 参数3: 原始数组
* 返回值: 满足条件的第一个单元值
*/
let result = arr.find((item, index, array) => {
//代码块
})
const arr = ['aaa', 20, 100, 'bbb', 200];
let result = arr.find(function (item, index) {
return item > 50
})
console.log(result); //100
/**
* 功能: 返回满足条件的第一个单元值
* 参数1: 单元值
* 参数2: 单元下标
* 参数3: 原始数组
* 返回值: 满足条件的第一个单元下标
*/
let result = arr.findIndex((item, index, array) => {
//代码块
})
const arr = ['aaa', 20, 100, 'bbb', 200];
let result = arr.findIndex(function (item, index) {
return item > 50
})
console.log(result); //2
/**
* 功能: 判断数组中是否包含指定值,如果包含返回true,否则返回false
* 参数: 要检测的值
* 返回值: arr如果包含value则返回true,否则返回false
*/
let result = arr.includes(value);
const arr = ['aaa', 20, 100, 'bbb', 200];
console.log(arr.includes(20)); //true
console.log(arr.includes('20')); //false
##7.1 模板字符串
案例1: 使用反引号定义字符串时,字符串中可以忽略单双引号的嵌套问题
let str1 = '百度';
let str2 = "百度";
//在反引号中单双引号可以随便使用
let str3 = `百度`;
案例2: 使用模板字符串拼接变量
let hero = {
name: '小炮',
country: '约德尔人',
type: '枪手',
price: 1
}
let str1 = `我叫${hero.name},是一个${hero.country},职业是${hero.type}`;
let str2 = '我叫' + hero.name +',是一个' + hero.country + ',职业是' + hero.type;
案例3: 将数组拼接成字符串填入tbody中
<table border="1" width="500">
<thead>
<tr>
<th>编号th>
<th>名称th>
<th>类型th>
tr>
thead>
<tbody>
<tr style="color:blueviolet">
<td style="text-align: center">1td>
<td style="text-align: center">loltd>
<td style="text-align: center">mobatd>
tr>
<tr style="color:blueviolet">
<td style="text-align: center">2td>
<td style="text-align: center">CFtd>
<td style="text-align: center">射击td>
tr>
tbody>
table>
<script>
let arr = [
{id: 1, name: 'lol', type: 'moba'},
{id: 2, name: '吃鸡', type: '射击'},
{id: 3, name: '云顶之弈', type: '自走棋'}
]
let str = '';
arr.forEach((item) => {
str += `
${item.id}
${item.name}
${item.type}
`;
})
document.querySelector('tbody').innerHTML = str;
script>
str.startsWith(char): 判断str是否以char开头,是则返回true,否返回false
str.endsWith(char): 判断str是否以char结尾,是则返回true,否返回false
let str = 'abcdefg';
console.log(str.startsWith('ab')); //true
console.log(str.startsWith('ac')); //false
console.log(str.endsWith('fg')); //true
console.log(str.endsWith('eg')); //false
##7.3 repeat 方法
功能: 将字符串重复多少次
console.log('a'.repeat(3)); //aaa
console.log('蛇精病'.repeat(2)); //蛇精病蛇精病
创建set有两种方式:
//创建一个空的set (注意new的时候 S 要大写)
const set = new Set();
//创建一个内部有数据的set
//如果创建时就有重复值,则会被自动过滤
const set = new Set(['a', 'b', 'c', 'a', 'd', 'c']);
console.log(set);
//size是内部属性,记录了数组长度
console.log(set.size);
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-MTuDU40b-1596682576735)(assets/1569344288907.png)]
##8.2 案例 – 去除重复电话号码
思路:
let telArr = [
'13912345678', '15712345678', '15812345678', '18512345678',
'17712345678', '18612345678', '15712345678', '18512345678',
'13912345678', '14712345678', '15112345678', '15812345678'
]
//利用Set去除数组中的重复值
let s = new Set(telArr);
console.log(s);
//使用扩展运算符将伪数组转为数组
let newArr2 = [...s];
console.log(newArr2);
//使用Array.from将伪数组转为数组
let newArr1 = Array.from(s);
console.log(newArr1);
##8.3 set的主要方法
//实例化一个空的set
let s = new Set();
//add: 向set中添加值
s.add('刘大').add('薛青麟').add('何五奇').add('赵永荣')
console.log(s); //Set(4) {"刘大", "薛青麟", "何五奇", "赵永荣"}
//delete: 从set中删除值
s.delete('薛青麟');
console.log(s); //Set(3) {"刘大", "何五奇", "赵永荣"}
//has: 判断一个值是否存在于set中,返回true/false
console.log(s.has('赵永荣')); //true
console.log(s.has('薛青麟')); //false
//clear: 清空set
s.clear();
console.log(s); //Set(0) {}
forEach可以用来遍历set
let s = new Set(["刘大", "薛青麟", "何五奇", "赵永荣"]);
//参数1: 单元值
//参数2: 单元索引 ---> set中的单元索引和单元值是一样的
//参数3: set实例对象(就是s)
s.forEach((item, index, o)=>{
console.log(item);
})
在声明对象时,值的变量名和属性名相同时, 可以只写属性而不写值
let name = '张三丰';
let age = 108;
let obj = {
//前面的name是属性
//后面的name是变量 (张三丰)
name: name,
age: age
}
//简写
let obj = {
name,
age
}
化一个空的set
let s = new Set();
//add: 向set中添加值
s.add(‘刘大’).add(‘薛青麟’).add(‘何五奇’).add(‘赵永荣’)
console.log(s); //Set(4) {“刘大”, “薛青麟”, “何五奇”, “赵永荣”}
//delete: 从set中删除值
s.delete(‘薛青麟’);
console.log(s); //Set(3) {“刘大”, “何五奇”, “赵永荣”}
//has: 判断一个值是否存在于set中,返回true/false
console.log(s.has(‘赵永荣’)); //true
console.log(s.has(‘薛青麟’)); //false
//clear: 清空set
s.clear();
console.log(s); //Set(0) {}
## 8.4 遍历set
forEach可以用来遍历set
```js
let s = new Set(["刘大", "薛青麟", "何五奇", "赵永荣"]);
//参数1: 单元值
//参数2: 单元索引 ---> set中的单元索引和单元值是一样的
//参数3: set实例对象(就是s)
s.forEach((item, index, o)=>{
console.log(item);
})
在声明对象时,值的变量名和属性名相同时, 可以只写属性而不写值
let name = '张三丰';
let age = 108;
let obj = {
//前面的name是属性
//后面的name是变量 (张三丰)
name: name,
age: age
}
//简写
let obj = {
name,
age
}