知识点
var和let/const区别和联系
- var:
- 可以重复声明;
- 作用域:全局作用域和函数作用域;
- 会进行预解析;
- let、const:
- 同一作用域下不能重复定义;
- 作用域:全局作用域和块级作用域{};
- 不会进行预解析.
if(true) { var a = 'aaa'; let b = 'bbbb'; } console.log(a); // aaa console.log(b); // ReferenceError: b is not defined
作用域
-
页面中有三个 li
const lis = document.querySelectorAll('li'); for(var i=0; i<lis.length; i++){ lis[i].onclick = function() { console.log('点击:', i); } } // 点击: 3
const lis = document.querySelectorAll('li'); for(let i=0; i<lis.length; i++){ lis[i].onclick = function() { console.log('点击:', i); } } // 点击: 0 // 点击: 1 // 点击: 2
解构赋值
- 快速交换a和b的值:[a,b] = [b,a];
展开运算符
let a = [1, 2];
let b = [3, 4, 5]
let c = [3, 4, ...a, 5]; // [3, 4, 1, 2, 5];
let [x, y, ...z] = c; //3 4 [1, 2, 5]
// 对象也类似
// 对象的拷贝,修改obj2中的内容,不影响obj1中的内容
let obj2 = {...obj1};
Set
- 对象的数据结构;
- 属性:size;
- 方法:clear()、delete()、has()、add();
- 可用于数组去重。
let arr = [2,3,4,5,5]; // 构造函数:用来构建某一类型的对象--对象的实例化 let s = new Set(arr) // 接受一个数组或者类数组作为参数 console.log(s, s.size); // Set(4) { 2, 3, 4, 5 } 4 // console.log(s.clear()); // undefined // console.log(s.delete(2)); // true // console.log(s.has(5)); // true console.log(s.add(9)); // 返回新的 Set,可以进行链式调用 console.log(s);
Map
- 对象的数据结构;
- 属性:size;
- 方法:clear()、delete()、get()、has()、set ();
let arr = [ ['a', 1], ['b', 2], ['c', 3], ['d', 4] ]; let m = new Map(arr); console.log(m, m.size); // Map(4) { 'a' => 1, 'b' => 2, 'c' => 3, 'd' => 4 } 4 // console.log(m.clear()); // undefined // console.log(m.delete('a')); // true // console.log(m.has('a')); // true // console.log(m.get('a')); // 1 console.log(m.set('f', 8)); // 返回一个新的 Map,可以进行链式调用 console.log(m, m.size); // Map(5) { 'a' => 1, 'b' => 2, 'c' => 3, 'd' => 4, 'f' => 8 } 5
箭头函数
- 注:箭头函数中的 this 会穿透,如果包含在多个嵌套的箭头函数中,会一直穿透;
- 箭头函数没有不定参数(arguments)
function fn1() {
console.log(arguments);
}
fn1(1,2,3,4,5); // [1,2,3,4,5]
const fn2 = (a,b,...rest) => {
console.log(a,b,rest);
};
fn2(3,4,5,6,7); // 3 4 [5, 6, 7]
- this 指向问题:箭头函数本身没有 this,调用箭头函数的 this 时,指向的是其声明时所在的作用域的 this:
document.onclick = function() { console.log(this); // #document }
document.onclick = () => { console.log(this); // Window }
document.onclick = function() { function fn1() { console.log(this) } fn1(); // Window const fn2 = () => { console.log(this); } fn2(); // #document }
let fn1; function fn2() { console.log(this); fn1 = () => { console.log(this) } // fn1 = function() { // console.log(this) //Window // } } fn2(); // Window fn1(); // Window
let fn1; function fn2() { console.log(this); fn1 = () => { console.log(this); } // f1 = function() { // console.log(this); //Window // } } fn2 = fn2.bind(document); fn2(); // #document fn1(); // #document
- 默认值:
fn1 = (a=8) => { console.log(a) } fn1()
数组
- Array.from(list):把一个类数组转换成真正的数组。类数组:有下标有length。另一个方法:[...list]。
- Array.of(1,2,3,'A'),将参数组成一个数组;
- Array.isArray(data):检测一个数是否是数组(类数组返回false)
- arr.find(callback):返回满足条件的第一个值,如果没有满足条件的就返回undefined。
- flat:数组扁平化处理:
let arr = [[1,2,3],[2,3,[2,3,[4,5]]],[3,4,5]]; // // [1, 2, 3, 2, 3, 2, 3, 4, 5, 3, 4, 5] console.log(arr.flat(Infinity))
- fill:arr.fill(value,startIdx,endIdx);
- includes:arr.includes(value,fromIdx)。
字符串
- startsWith('aa',position):判断第position开始是否以'aa'开始;
- endsWith('aa',position):判断前position位是否以'aa'结束;
- repeat: str.repeat(count),将str重复count次.
模板字符串
- 比较简单,这里不做过多赘述:
${a}
.
对象
- 简洁表示法:
let a = 1; let b = 2; let obj1 = { a: a, b: b, c: function() {} } // es6表示法 let obj2 = { a, b, c() {} }
- 属性名表示法:
let name = 'yijiang'; let obj = { [name]: 18 } // obj = {yijiang: 18}
- 对象合并:
let obj1 = { a: 1, b: 2 }; let obj2 = { c: 3, d: 4 }; let obj = Object.assign({}, obj1, obj2); // Object.assign(obj1, obj2); // 把 后面的 obj2 合并到第一个 obj1 中
let obj1 = { a: 2, b: 3, c: {d: 4} }; let obj2 = { x: 5, y: 6, z: {m: 8} }; let object = Object.assign(obj1, obj2); // console.log(object); // { // a: 2 // b: 3 // c: {d: 4} // x: 5 // y: 6 // z: {m: 8} // } obj2.x = 88; obj1.z.m = 100; console.log(object); // { // a: 2 // b: 3 // c: {d: 4} // x: 5 // y: 6 // z: {m: 100} // } // assign 第一层是深拷贝,第二层是浅拷贝 // 合并也可以通过展开运算符
- Object.is(a, b):判断两个值是否相等,以下的值都为true:
- 两个值都是 undefined;
- 两个值都是 null;
- 两个值都是 true,或者都是 false;
- 两个值是由相同个数的字符按照相同的顺序组成的字符串;
- 两个值指向同一个对象;
- 两个值都是数字,并且都是 +0;都是 -0;都是 NaN.[这里和 === 结果不一样].
- 对象冻结
// 对象冻结 let obj = { a: 1, b: { name: 'yjwtt' } }; function deepFreeze(obj) { Object.freeze(obj); for (const key in obj) { if (obj.hasOwnProperty(key)) { const ele = obj[key]; if (typeof ele === 'object') { deepFreeze(ele); } } } } deepFreeze(obj); obj.a = 2; obj.b.name = 'wyj'; console.log(obj);
- 深拷贝
// 深拷贝 let obj = { age: 18, name: 'yjw', play() { console.log('王者荣耀'); }, friend: '', house: undefined, books: ['Math', "Science"], } let obj2 = {...obj}; obj2.age = 20; console.log(obj, obj2); // 解除引用的深拷贝 // 1.通过序列化实现,缺点:值为undefined和函数会丢失 let obj_1 = JSON.parse(JSON.stringify(obj)); obj_1.age = 20; console.log(obj, obj_1); // 2.深拷贝函数 let deepCopy = obj => { let newObj = Array.isArray(obj) ? [] : {}; for(let key in obj ) { if(obj.hasOwnProperty(key)){ if(typeof obj[key] === 'object') { newObj[key] = deepCopy(obj[key]); } else { newObj[key] = obj[key]; } } } return newObj; } let obj_1 = deepCopy(obj); obj_1.age = 20; console.log(obj, obj_1);
arguments 和 ...arg 的区别
function test(...arg) {
console.log(arguments); // [1, 2, callee:(), length: 2, ...]
console.log(arg); // [1, 2]
}
test(1,2);
面试题
// 面试题
// 1、var、let以及const区别
/**
1.var 没有块级作用域,只能是全局或者整个函数块
2.var 有变量提升
3.var 声明的变量会挂载到window上
4.let和const,不会被预解析,let可以改变值但不能重复声明,const值不能改变。
*/
// 2、说一下ES6对Object类型做了那些优化更新
/**
优化部分
1.简写:
let obj = {a:a, b:b, fn: function(){}} => let obj = {a, b, fn(){}};
2.解构赋值;
3.扩展运算符;
更新部分:
4.Object.is()、Object.assign({obj1, obj2)、Object.getOwnPropertyDescriptors(obj)
5.Object.getPrototypeOf()、Object.setPrototypeOf()
6.Object.keys()、Object.values()、Object.entries()
*/
// let obj = {a: 1, name: {first:'yj', last: 'w'}};
// console.log(Object.getOwnPropertyDescriptors(obj));
// console.log(Object.getPrototypeOf(obj));
// console.log(Object.keys(obj));
// console.log(Object.values(obj));
// console.log(Object.entries(obj));
案例
案例一员工列表
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
* {
margin: 0;
padding: 0;
}
body a {
text-decoration: none;
color: #0d3a4b;
}
.active {
color: #4cbfe5;
}
.wrap {
width: 700px;
height: 500px;
background-image: url(./images/bg.png);
background-repeat: no-repeat;
margin: 0 auto;
position: relative;
}
.wrap #table {
width: 460px;
border-radius: 12px;
position: absolute;
left: 50%;
top: 160px;
transform: translateX(-50%);
box-sizing: border-box;
overflow: hidden;
}
.wrap #table thead {
width: 100%;
height: 30px;
line-height: 30px;
text-align: center;
border-top-left-radius: 12px;
border-top-right-radius: 12px;
color: #fff;
background: #4cbfe5;
}
.wrap #table thead a {
color: #fff;
}
.wrap #table tbody {
color: #19c2ff;
}
.wrap #table tbody a {
color: #19c2ff;
}
.wrap #table tbody tr {
background: #fff;
}
.ctrl {
position: absolute;
left: 200px;
top: 100px;
}
.ctrl div {
width: 300px;
line-height: 30px;
display: flex;
flex-direction: row;
justify-content: space-around;
}
</style>
</head>
<body>
<div class="wrap">
<div class="ctrl">
<div class="age_sort nu">
<a href="javascript:;">年龄从小到大</a>
<a href="javascript:;">年龄从大到小</a>
<a href="javascript:;" class="active">默认排序</a>
</div>
<div class="gender_show">
<a href="javascript:;">只显示男性</a>
<a href="javascript:;">只显示女性</a>
<a href="javascript:;" class="active">默认</a>
</div>
</div>
<table id="table">
<thead>
<tr>
<th>id</th>
<th>姓名</th>
<th>年龄</th>
<th>性别</th>
</tr>
</thead>
<tbody>
</tbody>
</table>
</div>
</body>
<script>
// 员工列表
// 数据优先 ,数据驱动 :先考虑数据,然后在渲染视图;
let data = [
{
id: 1,
name: '小明',
age: 24,
gender: '男'
},
{
id: 2,
name: '小芳',
age: 30,
gender: '女'
},
{
id: 3,
name: '小美',
age: 31,
gender: '女'
},
{
id: 4,
name: '小刚',
age: 21,
gender: '男'
},
{
id: 5,
name: '小琪',
age: 18,
gender: '女'
}
];
// 根据数据渲染视图
const render = (data) => {
let tbody = document.querySelector('tbody');
tbody.innerHTML = '';
data.forEach(ele => {
let tr = document.createElement('tr');
tr.innerHTML = `
<th>${ele.id}</th>
<th>${ele.name}</th>
<th>${ele.age}</th>
<th>${ele.gender}</th>`;
tbody.appendChild(tr);
})
};
// 初始化
render(data);
// 给各排序的种类赋初始排序默认值
let ageIndex = 2;
let genderIndex = 2;
// 按照年龄排序的数据
const ageData = [data => data.map(val=>val).sort((v1,v2)=>v1.age-v2.age), data => data.map(val=>val).sort((v1, v2)=>v2.age-v1.age), data=>data];
// 获取年龄相关按钮
const ageBtns = document.querySelectorAll('.age_sort a');
// 绑定年龄相关按钮事件
ageBtns.forEach((btn, index) => {
btn.onclick = () => {
// 去除所有年龄相关按钮激活样式
ageBtns.forEach(btn => {
btn.classList.remove('active');
})
// 给当前按钮绑定激活样式
btn.classList.add('active');
// 记录排序值
ageIndex = index;
// 根据各排序值计算排序后的数据
const genderD = genderData[genderIndex](data);
const ageD = ageData[ageIndex](genderD);
render(ageD);
}
})
const genderData = [data => data.filter(ele=>ele.gender==='男'), data => data.filter(ele=>ele.gender==='女'), data=>data];
const genderBtns = document.querySelectorAll('.gender_show a');
genderBtns.forEach((btn, index) => {
btn.addEventListener('click', ()=> {
genderBtns.forEach(btn => {
btn.classList.remove('active');
})
btn.classList.add('active');
genderIndex = index;
const ageD = ageData[ageIndex](data);
const genderD = genderData[genderIndex](ageD);
render(genderD);
})
});
</script>
</html>
案例二百度音乐
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
ul {
margin: 0;
padding: 0;
list-style: none;
}
h2 {
margin: 0;
}
#wrap {
margin: 30px auto;
width: 482px;
padding: 5px;
position: relative;
border: 1px solid #000;
background: #eee;
}
.title {
font: bold 18px/40px "宋体";
text-align: center;
border-bottom: 1px solid #000;
}
#list {
padding-left: 2px;
}
#list li {
opacity: 0.8;
font: 14px/36px "宋体";
border-bottom: 1px solid #000;
}
#list li:hover {
opacity: 1;
}
#list label input {
margin: 0 20px 0 30px;
}
input[type="chekbox"] {
width: 20px;
height: 20px;
}
.footer {
font: 16px/36px "宋体";
}
</style>
</head>
<body>
<section id="wrap">
<h2 class="title">百度音乐榜单</h2>
<ul id="list">
<li>
<input type="checkbox" class="check" />
<span>第一条信息</span>
<a href="javascript:;" class="collect">收藏</a>
<a href="javascript:;" class="cancelCollect">取消收藏</a>
<a href="javascript:;" class="remove">删除</a>
</li>
</ul>
<footer class="footer">
<label><input type="checkbox" id="checkAll" />全选/全不选</label>
<a href="javascript:;" id="remove">删除</a>
<input type="text" id="newInfo" />
<a href="javascript:;" id="add">添加</a>
</footer>
</section>
</body>
<script>
// 数据驱动视图
// 模拟数据
let data = [
{
id: 1,
title: "残酷月光 - 费启鸣",
checked: false,
collect: true
}, {
id: 2,
title: "兄弟 - 艾热",
checked: false,
collect: false
}, {
id: 3,
title: "毕生 - 夏增祥",
checked: true,
collect: true
}, {
id: 4,
title: "公子向北去 - 李春花",
checked: false,
collect: false
}, {
id: 5,
title: "战场 - 沙漠五子",
checked: true,
collect: false //是否收藏 true 收藏 false 没有收藏
}
];
// 渲染视图
render = (data) => {
let list = document.querySelector('#list');
list.innerHTML = ''
data.forEach((val, index) => {
let li = document.createElement('li');
li.innerHTML = `
<input type="checkbox" class="check" ${val.checked ? 'checked' : ''}/>
<span>${val.title}</span>
${val.collect ?
'<a href="javascript:;" class="collect">收藏</a>' :
'<a href="javascript:;" class="cancelCollect">取消收藏</a>'
}
<a href="javascript:;" class="remove">删除</a>
`;
list.appendChild(li);
});
// 判断是否已全选
let checkAll = data.every(val => val.checked === true);
document.querySelector('#checkAll').checked = checkAll;
// 渲染视图之后,给对应元素绑定事件
addEvent();
}
// 绑定事件
addEvent = () => {
const lis = document.querySelectorAll('#list li');
lis.forEach((li, index) => {
// 给li里面的元素添加点击事件
li.onclick = (e) => {
// 通过className来区分li中的各元素
switch(e.target.className) {
case 'check':
console.log(e);
data[index].checked = e.target.checked;
break;
case 'collect':
console.log('收藏');
data[index].collect = false;
break;
case 'cancelCollect':
data[index].collect = true;
console.log('取消收藏');
break;
case 'remove':
console.log('删除');
data.splice(index,1);
break;
}
// 处理完事件之后会获得对应的数据,然后进行渲染
render(data);
}
});
};
// 处理底部按钮事件
let footer = document.querySelector('.footer');
footer.onclick = e => {
switch(e.target.id) {
case 'checkAll':
const checked = e.target.checked;
data.forEach(val => {
val.checked = checked;
})
break;
case 'remove':
data = data.filter(val => val.checked !== true);
break;
case 'add':
let newInfo = document.querySelector('#newInfo');
newInfo.value.trim() && data.push({
title: newInfo.value,
id: data.length,
checked: false,
collect: true
});
newInfo.value = '';
break;
}
render(data);
}
// 首次进行视图渲染
render(data)
</script>
</html>
网友评论