一、forin
<body>
<div></div>
<div></div>
</body>
<script>
const aDiv1 = document.querySelectorAll('div');
const aDiv2 = document.getElementsByTagName('div');
const obj = {
name: 'mimi',
age: 32
}
// 当key存在时,就继续循环.
// in 是一个操作符.
// key in obj 是一个表达式,返回布尔值.返回true表示obj有key属性,false表示没有.
// 这里的key如果用let声明,是一个局部变量
// 这里的key如果用var声明,就是一个全局变量.
for (var key in obj) {
// 属性名
console.log(key);
// 属性值
console.log(obj[key]);
}
// key是全局变量,循环结束key是最后一个属性age
console.log('key',key);
// 如何知道某个对象能不能使用某个对象,或者属性.可以in检查.
// aDiv1可以使用forEach
// 'forEach' in aDiv1 => 判断aDiv1的原型链上有没有forEach这个方法或者属性.
console.log('forEach' in aDiv1);// true
// aDiv2不能使用forEach
console.log('forEach' in aDiv2);// false
</script>
二、forin循环数组
<script>
// 应用场景不多,所以不推荐用for in 循环数组。
let arr = [1,2,3];
// 给数组添加一个自定义属性
arr.index = 4;
let num = 0;
// 用for in循环数组,会循环数组的自定义属性.而不是只循环元素.
for (let i in arr) {
console.log(arr[i]);
num += arr[i];
}
</script>
三、json格式
JSON.parse可以把json字符串转换为json对象
json字符串有什么格式规定吗?
1:第一个字符串只能是{或者[.最后一个字符,只能是}或者].
2:属性名必须都是双引号.属性值如果是字符串也必须是双引号。
3:最后一个属性不能加,
4:不能有任何的注释.
参数只能是json字符串.
Unexpected token 小陈 in JSON at position 0 (参数的第一个字符"小陈"是错的)
能写进parse方法的参数的字符串,必须是复合json格式的字符串
const obj = JSON.parse('小陈');
// 对的
const obj = JSON.parse('[]');
const obj = JSON.parse('{}');
Uncaught SyntaxError: Unexpected token n in JSON at position 1
const obj = JSON.parse('{name: 小陈}');
SyntaxError: Unexpected token 小陈 in JSON at position 9
const obj = JSON.parse('{"name": 小陈}');
const obj = JSON.parse('{"name": "小陈"}');
SyntaxError: Unexpected token } in JSON at position 14
const obj = JSON.parse('{"name": "小陈",}');
// 一定返回符合json格式的json字符串。
let str = JSON.stringify({name: '小陈',});
console.log(str);
四、eval
<body>
<input type="text">
</body>
eval => 把字符串当成js代码来运行.
eval返回的是它的参数的返回值.
let obj = JSON.parse('{name: "小陈"}');
// eval可以转换不符合json格式的字符串为对象.
let obj = eval('({name: "小陈"})');
'alert(100)'
let num1 = eval('alert(20000)');
let num2 = eval('Math.random()');
// x没声明,直接访问x,会报错.
eval('x');
eval总数会把字符串当前js代码来运行,因此它不安全.
如果这个字符串内包含了恶意代码,eval也会执行这些恶意代码。(xss攻击,脚本注入攻击)
因此必须保证eval的内容是可信的.
eval的参数不应该由用户输入提供.
eval(oText.value);(不可取的).
五、ES6的新特性
ES6新特性:
- let 和 const
- 箭头函数
- 块级作用域
- ··模板字符串
- rest参数和参数默认值
- function (...arguts, x = 100) {}
六、对象扩展
ES6的对象在属性和方法上有写法更简便的扩展.
const obj = {
name: name,
age: age,
show: function() {
console.log('show');
}
}
这里的写法和上面的obj是一个意思
const oYm = { name, age };
// 这里的写法和上面的obj是一个意思
const oYm = { name, age };
const oYm = {
name,
age,
// 方法可以不写:function
show() {
console.log('show');
},
// 动态属性名
[x]: '女'
};
console.log(oYm.name);
console.log(oYm.age);
console.log(oYm[x]);
七、数值的扩展
- parseFloat,parseInt是window的方法,实际上是不标准的方法.
- window的方法就是浏览器的方法.(BOM的方法).BOM是没有标准.
- BOM的所有方法如果业内都在使用,大家都把这些方法当成标准方法.
- window.parseFloat => 把字符串转换为小数
- window.parseInt => 把字符串转换为正数
- ES6就把一些BOM的常用方法变成标准之内的方法.
- 例如数学上的parseFloat和parseInt,以及isNaN方法变成了Number类的标准方法.
let num1 = Number.parseFloat('44.5');
let num2 = Number.parseInt('44.8px');
// isNaN也变成了Number的标准方法
let flag = Number.isNaN(NaN);
// 非标准方法
window.isNaN('mimi');
true
window.isNaN('小陈');
true
window.isNaN({});
true
// 标准方法;
Number.isNaN('mimi');
false
Number.isNaN('小陈');
false
Number.isNaN({});
false
八、Math对象扩展
// 向下取整
let num1 = Math.floor(4.9);// 4
let num2 = Math.floor(-4.9);// -5
// 直接把小数部分删掉
let num3 = Math.trunc(4.9);// 4
let num4 = Math.trunc(-4.9);// -4
// flag返回1表示10是正数
let flag = Math.sign(10);
console.log(flag === 1);
// flag是-1表示-10是负数.
let flag = Math.sign(-10);
console.log(flag === -1);
九、箭头函数
语法:
- () => {}
- res => res.x
- res => ({name: mimi})
箭头函数的简写:
- 如果参数只有一个,可以省略形参的().
形参只有1个x,()可以省略掉.
- 没有参数不能省略();
- 多于1个参数不能省略();
- let fn = x => {console.log(x)};
- fn(1000);
如果函数内只有一个return 语句,则return和{}都可以省略.
// 函数内只有一个return语句
let fun = () => {
return 100
}
// 删掉{}和return.
let fun = () => 100;
// 形参是x,出参是100*x; (一眼看明白入参和出参各是什么)
let fun = x => 100 * x;
// 特别注意,函数对象的简写:
let func = () => {
return { name: '小陈' }
}
// 如果返回的是一个纯对象,简写后,应该有()包裹对象.
let func = () => ({ name: '小陈' });
// 这里的大括号是对象{}还是块级作用域的大括号?
// 给参数添加一个小括号,就可以让eval知道,这是一个对象的{}
let str = eval('({name: "小陈"})');
十、扩展运算符
... => 扩展运算符 => 单目运算符.
...只能用在()中,[]中,以及{}中
可以用于暂开数组,对象,甚至是字符串.
...的操作数除对象外,都是一些可以当成数组看待的数据.
let arr = [1,2,3];
let str = '我爱你';
let obj = {name: '小陈', age: 32};
console.log(arr[0], arr[1], arr[2]);
console.log(str[0], str[1], str[2]);
console.log(...arr);
console.log(...str);
// 如果展开的是一个纯对象,应该把...放到另一个{}内
console.log(...obj);
let oYm = {...obj}
let num = [arr[0], arr[1], arr[2]];
let num = [...arr];
console.log(...100);
十一、解构赋值
<script>
let obj = {
num:1,
a:{
num:2,
a:{
num:3,
a:{
num:4,
a:{
num:5
}
}
}
}
}
let num = fn(obj);
console.log(num); //15
// 利用解构赋值,把参数o,解构成了两个变量
// 这样可以直接通过num来代替o.num
// 用a来代替o.a;
function fn ({num, a}) {
if (a !== undefined) {
return num + fn(a)
} else {
return num
}
}
</script>
十二、数组解构赋值
// 数组解构赋值
let arr = [1, 2, 3];
// 分别用3个变量存储了数组的3个元素
let x = arr[0],
y = arr[1],
z = arr[2];
// 以上写法可以改写成下面的写法。
// 声明3个变量,分别获取数组的3个元素.
let [x, y, z] = arr;
console.log(x, y, z);
十三、对象解构赋值
let obj = {
exhusband: {
name: '小邓'
},
arr: [
{
name: '小赵'
}
]
};
let name = obj.exhusband.name;
let { exhusband: {name} } = obj;
console.log(name);// 小邓
let {arr: [{ name }]} = obj;
console.log(name); // 小赵
十四、解构赋值
let str = 'Hello';
// 可以把字符串当成数组解构.
let [x, y, z] = str;
console.log(x, y, z);
// 获取第一个div
let [oDiv] = document.querySelectorAll('div');
console.log(oDiv);
// oDiv是undefined
let {oDiv} = document.querySelectorAll('div');
let obj = {name:'小陈'};
// 报错
let [name] = obj;
=左边是写[]还是{}?
= 左边写了[],浏览器就把=右边当成数组来解构.不能当数组处理的,会报错
= 左边写了{},浏览器就把=右边当成对象来解构.除非右边是undefined或者null,其他情况都不会报错
let arr = [1,2];
// 数组也是对象,可以添加自定义属性.
arr.x = 10;
// 尝试解构[1,2]的自定义属性x.
let {x} = arr;
// undefined没有任何的x属性可以解构.
// undefined和null不能当成对象来解构
let {x} = undefined;
// x也是undefined.(万物皆对象)
// 基本类型的number,string,boolean都可以当成对象来解构
let {x} = 100;
let {y} = '你好';
let {z} = true;
// 尝试解构100的第一个元素.
// 100不能当成数组解构
let [x] = 100;
十五、iterator接口
- Array,Set,Map,String,nodeList (不包括纯对象)
- 这些数据类型都可以当成数组来解构.
- 能当成数组解构的数据类型是具有iterator接口的数据结构.
- js默认拥有iterator接口的数据类型是下面这些:
- Array => 数组
- Map => ES6新增的一种映射结构
- Set => ES6新增的一种不重复的数组结构
- String => 字符串
- TypedArray =>
- 函数的 arguments 对象 => arguments
- NodeList 对象 => 标签数组
- 注意: 纯对象没有iteraor接口.
- ...展开运算符,也可以展开所有具备iterator接口的数据类型.
十六、for of
for of => 循环具备iterator接口的数据结构
for in => 循环对象
let arr = [1,2,3];
// val是数组的元素.for of 中没办法获取下标.
// for (let val of arr) {
// console.log(val);
// }
// for (let val of 'Hello') {
// console.log(val);
// }
let aDiv = document.querySelectorAll('div');
for (let el of aDiv) {
// console.log(el);
el.onclick = function() {
console.log(el);
}
}
十七、数组去重
<script>
let arr = [1,1,2,2,3,3];
// [1,2,3];
// 算法 => 办法
// 先声明一个空数组A.循环当前数组,检查A数组中,有没有当前循环的元素,没有就push进A,有就不push.
// 面试题经常有这题.
let newArr = [];
for (let item of arr) {
// 判断newArr中是否有当前的元素.
if (!newArr.includes(item)) {
newArr.push(item)
}
}
</script>
<script>
let arr = [1,1,2,2,3,3];
// 去重的函数封装.
let newArr = fn(arr);
function fn(arr) {
let newArr = [];
for (let item of arr) {
// 判断newArr中是否有当前的元素.
if (!newArr.includes(item)) {
newArr.push(item)
}
}
return newArr
}
</script>
十八、Set结构
<script>
let arr = [1,1,2,2,3,3];
// 利用Set结构来进行去重操作.
let newArr = [...new Set(arr)];
// Set => ES6新增的一种数据结构
// js常用的数据结构: 数组,纯对象.
// ES6新增了两种:Set,Map.
// Set就是不重复的数组.
// Map就是更"神经"的纯对象.
// Set数据结构没有直接量的写法,只有构造的写法.
// 参数必须是具备iterator接口的数据结构
// let aS = new Set(1,2,3);
// 可以接收数组作为参数.
// Set的成员,绝对是不重复的.
let aS = new Set([1,2,3,3]);
// console.log(aS);
// size相当于是数组的length.
// console.log(aS.size);
// 遍历访问Set的成员.
for (let item of aS) {
console.log(item);
}
// 添加一个成员
aS.add(4);
// 判断有没有指定元素.
if (aS.has(5)) {
alert('有5')
} else {
alert('没有5')
}
</script>
十九、Map
<body>
<div id='wrap'></div>
</body>
const obj = {
name: '小陈',
age: 32,
isMan: false
};
// const obj = {
// "name": '小陈',
// "age": 32,
// "isMan": false
// };
// 普通的纯对象的"键"的数据类型都是字符串."值"可以是任意数据类型.
for (let key in obj) {
console.log(typeof key)
}
const oDiv = document.getElementById('wrap');
const data = {};
// 这个name的数据类型必须是字符串.
let name = 'name';
// 这时,name的数据类型是对象.
let name = oDiv;
data.name = '空对象';
data[name] = '空对象';
const oDiv = document.getElementById('wrap');
// 只有构造的写法.(相当于是一个空对象)
let m = new Map();
m.set('name', '小陈');
m.set(oDiv, '这时一个div');
// m.get('name') => 访问name映射的值.(name属性值)
// m.get(oDiv) => 访问oDiv映射的值.(name属性值)
二十、数组缓存
- 随机取1-10的随机数10个.放入一个数组.要求不重复.
- 可以用递归.但是性能不好.
- 先创建一个1-10作为元素的数组.
- 写一个10次循环,每次循环都随机从这个数组内获取一个元素.获取完成后删掉改元素.
- 这样最终获取的10个数字就是不重复的.
let oBtn = document.querySelectorAll('button')[0];
let arr = [1,2,3,4,5,6,7,8,9,10];
// 不能这样缓存
// let cloneArr = arr;
oBtn.onclick = function() {
// 缓存数组arr.
// let cloneArr = [...arr];
// let cloneArr = arr.concat([]);
// 数组缓存的最优写法.
let cloneArr = arr.slice();
// 新数组,用于防止随机数.
let newArr = [];
for (let i = 0; i < 10; i++) {
// 获取随机下标
let index = Math.floor(Math.random() * cloneArr.length);
// 把随机获取的元素放入新数组
newArr.push(cloneArr[index]);
// 把随机选中的元素删掉,防止下次再随到
cloneArr.splice(index, 1);
}
console.log(newArr);
}
二十一、参数是对象的解构
<script>
// 哪里可以用解构赋值?
// 如果一个函数的参数是对象或者数组时,用得最多。
let oYm = {
name: '小陈',
age: 32
}
// 函数调用时,形参会自动被实参赋值.
// 如果我们的形参写成{}或者[]的形式,则程序会自动进行解构赋值.
// obj = oYm
// {name,age} = oYm
function fn({name,age}) {
console.log(name);
console.log(age);
}
fn(oYm);
</script>