JavaScript之作用域的认识
// obj['name']:获取成员为name的属性值
// obj[name]:把name变量存储的值作为成员获取其属性
/*
* 对象的属性名:
1、字符串
2、Symbol
3、数字/布尔/null/undefined等基本数据类型值(用这些值直接处理和基于他们的字符串格式处理结果是一样的)
obj[true] === obj['true'] === obj.true 是一样的
*/
// 对于普通对象来说,其属性名不能是引用数据类型,设置为对对象的话也会被转为字符串;但是ES6中新增的Map数据结构中允许属性名的一个对象
var obj = {};
obj[true] = 13;
obj[null] = 15;
obj[Symbol(111)] = 111;
console.log(obj.null, obj['Symbol(111)']) // 15 undefined Symbol作为属性名是没有被转为字符串的
var a = {n: 1};
var b = a;
a.x = a = {n: 2};
console.log(a.x); // unbdefined
console.log(b); // {n:1, x: {n: 2} }
/*
解析:
第一点:对于连等 a = b = 12;这种是从右往左进行赋值,即拆分开来就是 b = 12; a = b;
第二点:运算符运算优先级问题,成员访问.的优先级高于赋值=的优先级,即 a.x = b = 3;拆分开来就是 a.x = 3; b = 3
*/
/*
* GO(全局对象):浏览器最开始加载代码的时候,不仅提供了一个栈内存供代码执行,而且还默认开辟了一个堆内存,用来存储一些内置的属性和方法
!注意:全局对象GO跟全局变量对象VO(G)不是同一个东西
二者之间的关系:VO(G)中有一个叫做window的变量,变量值是GO
*/
/*
* 在 “全局上下文中”,基于 “var/function” 声明的全局变量,也会给GO(window)中新增一个对应的私有属性,并且和全局变量有“映射机制”,即其中一个修改,另一个也会跟着被修改
*/
var a = 10; // 1、声明一个全局变量a=10;1、给window新增一个私有属性 window.a = 10;
console.log(a); // 首先看看是不是全局变量,如果不是就去看看是不是window的属性,如果也不是那就报错: a is not defined
console.log(window.a); // 10
// 基于 “let/const” 声明的全局变量跟window(GO)没有关系
let a = 10; // 全局变量a
console.log(a); // 10
console.log(window.a); // undefined
// 在全局上下文中
a = 10; // a不是全局变量,而是 window的一个属性,相当于省略了window(前提:确定a没有被声明过)
console.log(a); // 10 是因为全局变量跟GO有映射机制
函数的存储和执行
/*
* 创建函数:
1、开辟新的堆内存(16进制地址)
2、把函数体中的代码当做字符串存储到开辟的堆内存中(当然也有键值对,函数也是对象)
3、把地址存到栈中,跟变量(函数名)进行关联
// => 创建函数的时候,就声明了函数的“作用域”,值是当前函数创建时所处的上下文
// => 如果创建了函数但是不执行(调用),那没有什么用,只是存储了一堆字符串
* 函数执行:
目的:是把之前创建函数的时候在函数体中存储的代码字符串进行执行
1、形成一个全新的私有上下文:
+ 有存储当前私有上下文中声明的私有变量的空间AO(AO是VO的一种,只是全局的叫VO,私有的叫AO)
+ 把上下文进栈执行
2、代码执行之前要做好多事
+ 初始化作用域链:作用域链(scope-chain)有两端,左端:当前上下文;右端:函数作用域(函数创建时所处的上下文)
+ 初始化this的指向
+ 初始化argments(参数对象)
+ 形参赋值:形参是私有变量
+ 变量提升
3、代码执行
4、一般情况下,浏览器在函数执行完之后,为了优化栈内存,会把形成的私有上下文进行出栈释放掉(GC浏览器垃圾回收机制)
作用域链:当前私有上下文代码执行,遇到一个变量,首先看是否为私有变量,如果是私有的,则接下来用到的都是私有的,和其他上下文中的变量没有任何直接关系;如果不是自己私有的变量,则按照作用域链向上级上下文中查找,如果上级也没有,继续往上级找......一直找到全局上下文;如果全局也没有,有两种情况:1、如果是设置值,那么相当于是给window设置属性;2、如果是获取值,那么就会报错
*/
// 题目:
var x = [12,32];
function fn(y) {
y[0] = 100;
y = [100];
y[1] = 200;
console.log(y); // [100, 200]
}
fn(x);
console.log(x); // [100, 32]
/*
fn(x)执行:
全新的执行上下文:EC(fn)
这里的私有变量有两种:形参和当前上下文中声明的变量
初始化作用域链:[[scope-chain]]: <EC(fn), EC(G)>
初始化this指向:this: window
初始化arguments:arguments: {0: AF0, length: 1}
形参赋值:y = AF0
变量提升:无
代码执行:
y[0] = 100: AF0[0] = 100
y = [100]; y = AF1
y[1] = 200; AF1[1] = 200
console.log(y); 输出 AF1,即[100, 200]
*/
// 函数执行,会形成一个私有的上下文,保护里面的私有变量不受外界干扰。这种保护机制称之为“闭包”