一、闭包

一个函数和对其周围状态(lexical environment,词法环境)的引用捆绑在一起(或者说函数被引用包围),这样的组合就是闭包(closure)。
https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Closures
但是我们需要的不只是字面意思,下面测试

1
2
3
4
5
6
7
8
9
function init() {
var name = "Mozilla"; // name 是一个被 init 创建的局部变量
function displayName() {
// displayName() 是内部函数,一个闭包
alert(name); // 使用了父函数中声明的变量
}
displayName();
}
init();

init() 创建了一个局部变量 name 和一个名为 displayName() 的函数。displayName() 是定义在 init() 里的内部函数,并且仅在 init() 函数体内可用。请注意,displayName() 没有自己的局部变量。然而,因为它可以访问到外部函数的变量,所以 displayName() 可以使用父函数 init() 中声明的变量 name 。
闭包有三个特性: 1.函数嵌套函数 2.函数内部可以引用外部的参数和变量 3.参数和变量不会被垃圾回收机制回收
闭包的优点
1、全局变量可能会造成命名冲突,使用闭包不用担心这个问题,因为它是私有化,加强了封装性,这样保护变量的安全
2、每个模块都可以调用,当程序越来越复杂之后,会带不可预测的危险
闭包的缺点
1、如果闭包使用不当,就会导致变量不会被垃圾回收机制回收,造成内存泄露

二、js 中自执行函数(function(){})()和(function(){}())区别

https://blog.csdn.net/stpice/article/details/80586444
这两种写法,都是一种立即执行函数的写法,这种函数在函数定义的地方就直接执行了。

内嵌套
(function(){}())
方式一,调用函数,得到返回值。强制函数直接量执行再返回一个引用,引用在去调用执行
外嵌套
(function(){})()
方式二,调用函数,得到返回值。强制运算符使函数调用执行

三、ES5 与 ES6 块级作用域

https://segmentfault.com/a/1190000011444396
es5:
es5 只有函数具备作用域
es5 模拟块级作用域
es5 弱类型语言,只有函数具备块级作用域
es6:
es6 let/const 看见{} 就会在离它最近的{}内形成自己的封闭作用域
注意: 在 ES6 中,{}就是一个块级作用域。

var 声明之函数作用域和全局作用域。

1
2
3
4
5
6
7
8
9
function getName() {
if (1 + 1 === 2) {
var name = "xixi";
}

console.log(name);
}

getName();

let

特点:重复声明会报错

1
2
3
4
5
6
7
8
9
function getName4ES6() {
if (1 + 1 === 2) {
let name = "xixi";
}

console.log(name);
}

getName4ES6(); // undefined

const

特点:值不可以改变

1
2
3
4
5
6
7
8
9
10
11
const arr = ["zhangsan", "lisi", "wanger"];

for (var c = 0; c < arr.length; c++) {
for (var j = 0; j < arr.length; j++) {
const filepath = path.join(__dirname, `${arr[j]}.txt`);
fs.readFile(filepath, (err, file) => {
if (err) return console.log(err);
console.log(file.toString());
});
}
}

临时性死区

1、let、const 不允许声明之前调用,调用了就会报错
2、声明之前调用变量,就会形成这个变量得暂时性死区
const 和 let 同样具有块级作用域,不能重复声明,临时性死区的概念。它还具有两个特有的特性:声明的同时必须初始化、变量引用不可以改变。
就是在调用之前使用,暂时性死区只能是 let 和 const 中出现

四、拷贝分类

https://www.jianshu.com/p/94dbef2de298
拷贝分为二种

1、浅拷贝
浅拷贝:只复制指向某个对象的指针,而不是复制对象本身,新对象旧对象还是共同享用同一块内存
浅拷贝的特点
(1) 对于基本数据类型的成员对象,因为基础数据类型是值传递的,所以是直接将属性值赋值给新的对象。基础类型的拷贝,其中一个对象修改该值,不会影响另外一个。
(2) 对于引用类型,比如数组或者类对象,因为引用类型是引用传递,所以浅拷贝只是把内存地址赋值给了成员变量,它们指向了同一内存空间。改变其中一个,会对另外一个也产生影响。

2、深拷贝
深拷贝:会另外创造一个一模一样的对象,新对象跟原来的对象不会共享一个内存,修改新对象也不会改到原对象上
(1) 对于基本数据类型的成员对象,因为基础数据类型是值传递的,所以是直接将属性值赋值给新的对象。基础类型的拷贝,其中一个对象修改该值,不会影响另外一个(和浅拷贝一样)。
(2) 对于引用类型,比如数组或者类对象,深拷贝会新建一个对象空间,然后拷贝里面的内容,所以它们指向了不同的内存空间。改变其中一个,不会对另外一个也产生影响。
(3) 对于有多层对象的,每个对象都需要实现 Cloneable 并重写 clone() 方法,进而实现了对象的串行层层拷贝。
(4) 深拷贝相比于浅拷贝速度较慢并且花销较大。