高阶函数
高阶函数是对其他函数进行操作的函数,它接收函数作为参数或将函数作为返回值输出。
此时fn 就是一个高阶函数
函数也是一种数据类型,同样可以作为参数,传递给另外一个参数使用。 最典型的就是作为回调函数。同理函数也可以作为返回值传递回来
闭包
闭包(closure)指有权访问另一个函数作用域中变量的函数,一个作用域可以访问另外一个函数的局部变量。 变量所在的函数就是闭包函数。
闭包的主要作用: 延伸了变量的作用范围。
递归
如果一个函数在内部可以调用其本身,那么这个函数就是递归函数。
简单理解:函数内部自己调用自己, 这个函数就是递归函数
<script>
var num = 1;
function fn() {
console.log('我要打印8句话',num);
if (num == 8) {
return; // 递归里面必须加退出条件
}
num++;
fn();// 递归函数 : 函数内部自己调用自己, 这个函数就是递归函数
}
fn();
</script>
浅拷贝
浅拷贝只是拷贝一层, 更深层次对象级别的只拷贝引用.
ES6中Object.assign可以实现浅拷贝
var obj = {
id: 1,
name: 'lucy',
msg: {
age: 18
}
};
var o = {};
Object.assign(o, obj);
深拷贝
深拷贝拷贝多层, 每一级别的数据都会拷贝.
实现深拷贝的反式一:使用递归
function deepCopy(newobj, oldobj) {
for (var k in oldobj) {
// 判断我们的属性值属于那种数据类型
// 1. 获取属性值 oldobj[k]
var item = oldobj[k];
// 2. 判断这个值是否是数组
if (item instanceof Array) {
newobj[k] = [];
deepCopy(newobj[k], item)
} else if (item instanceof Object) {
// 3. 判断这个值是否是对象
newobj[k] = {};
deepCopy(newobj[k], item)
} else {
// 4. 属于简单数据类型
newobj[k] = item;
}
}
}
缺点:
1)无法保存引用
2)当数据层次很深,会栈溢出
实现深拷贝的反式二:JSON转换
let newObj = JSON.parse(JSON.stringify(oldobj));
缺点:
1)如果对象有函数,函数无法被拷贝下来
2)无法拷贝对象原型链上的属性和方法
3)当数据的层次很深,会栈溢出
浅拷贝和深拷贝最根本的区别就是存储区域是否指向同⼀个地址,当声明⼀个对象时,计算机会在内存上分配⼀个地址给它,当你把这个对象付给另外⼀个变量的时候,这时候就会出现浅拷贝和深拷贝的情况,指向同⼀内存为浅拷贝,不同内存为深拷贝
内存泄漏(Memory Leak)
是指程序中己动态分配的堆内存由于某种原因程序未释放或无法释放,造成系统内存的浪费,导致程序运行速度减慢甚至系统崩溃等严重后果。
简言之就是指由于疏忽或者错误造成程序未能释放已经不再使用的内存,不再用到的内存却没有及时释放,从而造成内存上的浪费。
常见的JS内存泄漏
1. 意外的全局变量
使用未声明的变量,会在全局对象中创建一个新的变量;在浏览器环境下,全局对象就是window
function fn() {
name = 'lucy'
}
// 上面的写法等价于
function fn() {
window.name = 'lucy'
}
function foo() {
this.a = 'test' // 函数自身发生调用,this指向全局对象window,导致内存泄漏
}
foo()
2. 计时器和回调函数timers
定时器setInterval或者setTimeout在不需要使用的时候,没有被clear,导致定时器的回调函数及其内部依赖的变量都不能被回收,这就会造成内存泄漏。
解决方式:当不需要interval或者timeout的时候,调用clearInterval或者clearTimeout
3. DOM元素的引用
var a = document.getElementById('id');
document.body.removeChild(a);//虽然移除了dom,但是这里还在引用变量a,所有内存还里还存着dom
解决方法:a=null
给DOM对象添加的属性是一个对象的引用,也会内存泄漏
var args = {};
document.getElementById('id').prop = args;
解决方法:在window.onload
事件中加上
document.getElementById('id').prop = null;
4. 事件的绑定没有移除
监听的时候addEventListener,在不监听的时候要使用remveEventListener;
5.闭包使用不当
内部函数引用外部函数变量,得不到释放
function bindEvent() {
var obj = document.createElement('XXX');
var unused = function () {
console.log(obj, '闭包内引用obj obj不会被释放');
};
obj = null; // 解决方法
}
6.console控制台输出
使用console时,引用对象不能被垃圾回收,导致内存泄漏
7. 使用Map、Set对象存储对象
Set/Map、对象、数组对象等都是强引用,如果存储对象建议使用WeakMap 和 WeakSet ,二者都为弱引用
内存溢出(Out of Memory)
指程序在申请内存时,没有足够的内存空间供其使用
函数是一等公民
在编程语言中,一等公民可以作为函数参数,可以作为函数返回值,也可以赋值给变量。
例如,字符串在几乎所有编程语言中都是一等公民,字符串可以做为函数参数,字符串可以作为函数返回值,字符串也可以赋值给变量。
对于JavaScript来说,函数可以赋值给变量,也可以作为函数参数,还可以作为函数返回值,因此JavaScript中函数是一等公民。