等号赋值三步
- 堆内存创建值
- 堆内存创建变量
- 让变量和值关联
const 类型变量与值的关联只能执行一次
//同一个值可与多个变量关联
var a = 10
var b = a
console.log(a,b) -> 10 20
//同一个变量只会与最后一次赋值的值关联
//10并没有改变,而是新建了一个值20与a变量关联了
var a = 10
a = 20
console.log(a) -> 20
const
- const是 ES6 新增的命令
- 声明后必须马上赋值
- 声明并赋值后,不能修改关联的值,也不能修改地址
- 可以去通过地址修改堆内存中引用对象的值
- 应用:常量、声明匿名函数、箭头函数的时候。
- 不允许重复声明变量
const a = { a1: 1}
a.a1 = 2
console.log(a) -> { a1: 2}
let
- let和 ES6 新增的命令
- 范围:块级作用域
- 作用:let常用以替代var,它是家能让变量的作用范围更精确,可以轻松自己添加大括号使代码分割成块了
- 应用:for循环的计数器,很合适使用let命令,只在循环内生效
- let声明的变量只在它所在的代码块有效
- 不允许重复声明变量
块级作用域是es6新增的,es5只有全局作用域和函数作用域 囊括while/for/if 这些具有大括号的块级,当然包括函数的大括号
- 避免变量提升
// var 的情况
console.log(foo); // 输出undefined
var foo = 2;
// let 的情况
console.log(bar); // 报错ReferenceError
let bar = 2;
JS内存机制
- 内存空间分为:栈内存、堆内存
- 栈内存(放基础数据类型、自动分配),
- 堆内存(放引用基本数据类型、动态分配)
变量提升
- 定义:将当前作用域的所有变量声明和函数声明提升到程序顶部
- 注意:变量提升之后提升变量的声明,而不是提升变量赋值
console.log(a);
var a = 2; => a is undefined
//上面代码等同于
var a
console.log(a);
a = 2;
关键词
- 词法环境: 用于定义特定变量和函数标识符在 ECMAScript 代码的词法嵌套结构上关联关系的规范类型
- EC( Execution Context):执行上下文
- ECS( Execution Context stack):执行上下文栈,简称执行栈
- VO(variable object):变量对象
- AO (active object):活动对象
- GO(global object)
基本数据类型:
- boolean,number,string,null,undefined
- 值放在栈内存中
- 数据大小确定,自动分配内存
- 数据类型值不可变,赋值是新值的引用替换,而不会修改旧值
var a = 10
var b = a
b = 20
console.log(a,b) -> 10 20
引用数据类型
- Object、Array、RegExp、Date、Function
- 保存在栈中的只是一个堆引用地址,值存放在堆内存中
- 值比较是比较堆内存地址,地址一样则相同
var a = { key: 1}
var b = { key: 1}
a === b -> false
首先区分数据类型的存放
浅拷贝
- 直接在堆中创建内存,拷贝前后对象数据类型不变
- 只拷贝第一层,对象中的引用对象拷贝的是其堆内存地址
- 如果修改引用对象内部的引用对象,也会同步到拷贝之后的变量中
function copy(obj){
let newObj = {}
for(let key in obj){
newObj[key] = obj[key]
}
return newObj
}
// 以下都是浅拷贝
const arr1 = ['a','b']
const arr2 = ['c']
const arr3 = ['d']
// es5合并数组
arr1.concat(arr2,arr3)
// es6合并数组
[...arr1, ...arr2, ...arr3]
// Object.assign()也是浅拷贝
深拷贝
- 对对象中的子对象进行递归拷贝
- 拷贝完后两个对象互不影响
var objects = [{ 'a': 1 }, { 'b': 2 }];
// 深拷贝方法1,子对象不能为function
var deep = JSON.parse(JSON.stringify(objects));
// 深拷贝方法2 ,用lodash库函数
var deep = _.cloneDeep(objects);
console.log(deep[0] === objects[0]);
// => false
# 递归拷贝
function deepCopy(source) {
var result = {};
for(var key in source) {
if(typeof source[key] === 'object') {
result[key] = deepCopy(source[key])
} else {
result[key] = source[key]
}
}
return result;
}
应用场景
- JS原生的方法中,map就很函数式,他会返回一个新的数组,不会改变原数组。
- 而pop这种方法就很不好,它在操作了数组之后,也改变数组本身。
- 当我们要使用那些有副作用的方法写纯函数的时候,记得做一次深拷贝:
const myPop = x => {
let [...y] = x; //假定x内部都是基本数据类型
return y.pop();
}
->>> 博客原文 <<<-