一、this及this指向
1. 普通函数的this指向
函数的this指向遵循一个基本原则:谁调用的函数,函数的this就指向谁,否则指向全局
window.name = 'yuguang';
var getName = function(){
console.log(this.name);
};
getName(); // yuguang
2. 箭头函数的this指向
首先我们要知道,箭头函数本身是没有 this,箭头函数 this 是定义箭头函数时父级作用域的 this,也就是说使用箭头函数时,箭头函数内部的 this,我们只需要看定义该箭头函数时,该箭头函数父级的 this 即可
this.val = 2;
var obj = {
val: 1,
getVal: () => {
console.log(this.val);
}
}
obj.getVal(); // 2
3. call/apply/bind
call、apply、bind可以改变函数内部的this指向,但由于箭头函数自身没有this,所以call、apply、bind对箭头函数是不起作用的
var obj1 = {
name: 1,
getName: function (num = '') {
return this.name + num;
}
};
var obj2 = {
name: 2,
};
// 可以理解成在 obj2的作用域下调用了 obj1.getName()函数
console.log(obj1.getName()); // 1
console.log(obj1.getName.call(obj2, 2)); // 2 + 2 = 4
console.log(obj1.getName.apply(obj2, [2])); // 2 + 2 = 4
二、for…in和for…of的区别
for … of是作为ES6新增的遍历方式,允许遍历一个含有iterator接口的数据结构并且返回各项的值,和ES3中的for … in的区别如下
1、for … of遍历获取的是对象的键值,for … in 获取的是对象的键名
2、for … in会遍历对象的整个原型链,性能非常差不推荐使用,而for … of只遍历当前对象不会遍历原型链
3、对于数组的遍历,for … in会返回数组中所有可枚举的属性(包括原型链上可枚举的属性),for … of只返回数组的下标对应的属性值
4、如果要使用for…of遍历普通对象,需要配合Object.keys()一起使用。
var person={
name:'coco',
age:22,
locate:{
country:'China',
city:'beijing',
}
}
for(var key of Object.keys(person)){
//使用Object.keys()方法获取对象key的数组
console.log(key+": "+person[key]);//name: coco,age: 22,locate: [object Object]
}
三、事件委托
事件委托,又名事件代理。事件委托就是利用事件冒泡,就是把子元素的事件都绑定到父元素上。如果子元素阻止了事件冒泡,那么委托也就没法实现了。
好处:提高性能,减少了事件绑定,从而减少内存占用。
<!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>
.active{
color: red;
}
</style>
</head>
<body>
<ul>
<li>111</li>
<li>222</li>
<li>333</li>
<li>444</li>
<li>555</li>
</ul>
</body>
</html>
<script>
var ul = document.querySelector('ul');
var lis = document.querySelectorAll("li");
ul.onclick = function(e){
// console.log(e.target);
lis.className = ""
let i = e.target;
i.className = 'active'
lis = i;
}
</script>
四、数组去重
1. ES6-set方法
var arr = [1,2,3,4,1,2,3,4,5,6,7,true,{},{},true,false];
function getSet(arr){
return [...new Set(arr)];
//或者
//return Array.from(new Set(arr));
}
getSet(arr);
2.利用Map数据结构去重
创建一个空Map数据结构,遍历需要去重的数组,把数组的每一个元素作为key存到Map中。由于Map中不会出现相同的key值,所以最终得到的就是去重后的结果。
function getArr(arr) {
let map = new Map();
let array = new Array(); // 数组用于返回结果
for (let i = 0; i < arr.length; i++) {
if(map .has(arr[i])) { // 如果有该key值
map .set(arr[i], true);
} else {
map .set(arr[i], false); // 如果没有该key值
array .push(arr[i]);
}
}
return array ;
}
console.log(getArr(arr));
3. forEach + indexOf
function getArr(arr){
var res = [];
arr.forEach((val,index)=>{
if( res.indexOf(val) === -1 ){
res.push(val);
}
});
return res;
}
console.log(getArr(arr));
五、对象和面向对象
对象:属性和方法的集合叫做对象(万物皆对象)
面向对象:是一种编程思想,有类、封装、继承、多态的概念
封装:低耦合高内聚
多态:重载和重写
重载:js中是没有重载概念的(后端:方法名相同,但是形参个数不同或者类型不一样,挥着返回值不同(类型),根据传参不同,实现不同的效果
重写:在类的继承中,子类是可以重写父类的方法的
六、数组扁平化
概念:
数组扁平化就是将一个多维数组转换为一个一维数组
实现方式:
利用递归实现
let arr = [1, [2, [3, 4]]];
function flattern(arr) {
let result = [];
for(let i = 0; i < arr.length; i++) {
if(Array.isArray(arr[i])) {
flattern(arr[i])
} else {
result.push(arr[i])
}
}
return result;
}
ES6 增加了扩展运算符,用于取出参数对象的所有可遍历属性,拷贝到当前对象之中,所以也可以递归扁平化数组,代码如下:
let arr = [1, [2, [3, 4]]];
function flatten(arr) {
while (arr.some(item => Array.isArray(item))) {
arr = [].concat(...arr);
} //ES6新方法
return arr;
}
七、垃圾回收机制
概念:
浏览器的 Javascript 具有自动垃圾回收机制(GC:Garbage Collecation),也就是说,执行环境会负责管理代码执行过程中使用的内存。其原理是:垃圾收集器会定期(周期性)找出那些不在继续使用的变量,然后释放其内存。但是这个过程不是实时的,因为其开销比较大并且GC时停止响应其他操作,所以垃圾回收器会按照固定的时间间隔周期性的执行。
处在闭包中的变量是无法被回收的,容易造成内存堆积
实现原理
js中最常用的垃圾回收方式就是标记清除。当变量进入环境时,例如,在函数中声明一个变量,就将这个变量标记为“进入环境”。从逻辑上讲,永远不能释放进入环境的变量所占用的内存,因为只要执行流进入相应的环境,就可能会用到它们。而当变量离开环境时,则将其标记为“离开环境”。
八、iframe的优缺点有哪些
优点:
- iframe能够原封不动地把嵌入的网页展现出来。
- 如果有多个网页调用iframe,只需要修改iframe的内容,就可以实现对调用iframe的每一个页面内容的更改,方便快捷。
- 如果遇到加载缓慢的第三方内容,如图标和广告等,可以用iframe来解决。
- 模块分离,便于更改,如果有多个网页引用iframe,只需要修改iframe的内容,就可以实现调用的每一个页面内容的更改,方便快捷;
缺点:
-
样式和脚本需要额外链入,调用外部页面,需要额外调用css,增加页面额外的请求次数,增加服务器的http请求;
-
代码复杂,在网页中使用框架结构最大的弊病是搜索引擎的“蜘蛛”程序无法解读这种页面,会影响搜索引擎优化,不利于网站排名;
-
框架结构有时会让人感到迷惑,滚动条除了会挤占有限的页面空间外会使iframe布局混乱,还会分散访问者的注意力,影响用户体验;
-
链接导航疑问。运用框架结构时,必须保证正确配置所有的导航链接,否则,会给访问者带来很大的麻烦。比如被链接的页面出现在导航框架内,这种情况下访问者便被陷住了,因为此时他没有其他地点可去;
九、函数柯里化(卡瑞化、加里化)
概念:
”函数柯里化”是指将多变量函数拆解为单变量的多个函数的依次调用, 可以从高元函数动态地生成批量的低元的函数。简单讲:就是利用函数执行,可以形成一个不销毁的私有作用域,把预先处理的内容都存在这个不销毁的作用域里面,并且返回一个函数,以后要执行的就是这个函数。
// 常规的add函数
function add(a, b) {
return a + b
}
// Currying后
function curryingAdd(a) {
return function (b) {
return a + b
}
}
add(1, 2) // 3
curryingAdd(1)(2) // 3
十、window的onload事件
window.onload是一个事件,当文档加载完成之后就会触发该事件
window.onload = function () {
console.log('执行了1');
};
window.onload = function () {
console.log('执行2'); //被执行了
}
window.οnlοad=function(){}方法只能运行一个,后一个会覆盖前一个。