1 .
console.log(a, b, c)
var a = 12,
b = 13,
c = 14;
function fn(a) {
console.log(a, b, c) // 10,13,14
a = 100 // 私有变量a= 100
c = 200 // 全局c = 200
console.log(a, b, c) // 100, 13,200
}
b = fn(10) // 函数执行没有返回结果(EWTURN),默认为undefined
console.log(a, b, c) // 12 undefined 200
解析:
/*
* EC(G)
* 1.变量提升:
VO(G)
a:12
b:13 undefined
c:14 / 200
fn=>堆内存0x000000([[scope]]:EC(G))
2.代码执行:
(1):console.log(a,b,c)=> 只声明,没定义,所以输出undefined * 3
(2):a = 12,b=13,c=14
(3)b = fn(10)=>0x000000(10)
*/
console.log(a, b, c)
var a = 12,
b = 13,
c = 14;
function fn(a) {
/**
* EC(FN)
* AO(FN):
a = 10 / 100
作用域链:<EC(FN),EC(G)>
形参赋值:a = 10
变量提升:--
*/
// a是自己私有的,值是10;b和c不是私有的,沿着作用域链向上级找,知道到全局存在,值范围内比为13,14
console.log(a, b, c) // 10,13,14
a = 100 // 私有变量a= 100
c = 200 // 全局c = 200
console.log(a, b, c) // 100, 13,200
}
b = fn(10) // 函数执行没有返回结果(EWTURN),默认为undefined
console.log(a, b, c) // 12 undefined 200
var i = 10
function A() {
var i = 10
function x() {
console.log(i)
}
return x
}
var y = A()
y()
function B() {
var i = 20
y()
}
B()
var a = 1
var obj = {
name: 'tom'
}
function fn() {
var a2 = a
obj2 = obj
a2 = a
obj2.name = 'jack'
}
fn()
console.log(a)
console.log(obj)
/**
* EC(G)
* VO(G)
* a
* obj
* fn => 0x000000
* 代码执行过程中,变量赋值:
* a = 1
* obj = 0x000001
*
* 变量提升:var a;var obj; function fn(){...}
* 代码执行:
* var = 1
* var obj = {name: "tom"}
* fn()
*/
var a = 1
var obj = {
name: 'tom'
}
function fn() {
/**
* EC(FN)
* AO(FN)
* a2 = 全局a的值:1
* 代码执行
* var a2 = a
* obj2 = obj // obj2既不是私有的,也不是全局的,此处相当于window.obj2 = 0x000001(全局的obj)
* a2 = a // window.a2 = a = 1
* obj2.name = "jack" // 把window.obj2中的name修改(obj2和obj指向的同一个堆内存0x000001)
*
*/
var a2 = a
obj2 = obj
a2 = a
obj2.name = 'jack'
}
fn()
console.log(a) // 全局a = 1
console.log(obj) // {name: 'jack'}
var a = 1
function fn(a) {
console.log(a)
var a = 2
function a() {}
}
fn(a)
/**
* EC(G)
* VO(G)
* a = 1
* fn = 0x000000 [[scope]]:EC(G)
*
* 变量提升:var a; function fn(){...}
* 代码执行:
* var a = 1
* fn(a)
*/
var a = 1
function fn(a) {
/**
* EC(FN)
* AO(FN)
* a = 1
* 0x000001
* 2
* 作用域链:<EC(FN),EC(G)>
* 形参赋值:a=1
* 变量赋值:
* a = 1
* function a() {};不需要声明,但是需要重新赋值。 创建一个函数堆内存:0x000000. 将a指向改地址
* 代码执行:
* console.log(a) // 函数0x000000 => function a() {}
*
*/
console.log(a)
var a = 2 // 私有变量a重新赋值为2
function a() {} // 不需要处理了,变量提升阶段都处理过了
console.log(a) // 2
}
fn(a)
// console.log(a) // 全局的a = 1
(1)
console.log(a) // undefined
var a = 12
function fn() {
console.log(a) // undefined
var a = 13 // 私有变量a 赋值为13
}
fn()
console.log(a) //12
/**
* EC(G)
* VO(G)
* a
* 代码执行后,a = 12
* fn
* 变量提升:
* var a; function fn(){...} => 0x000000
* 代码执行:
* console.log(a) => undefined
* var a = 12
* function fn(){} // 变量提升阶段已经处理过,不在处理
* fn() // fn执行,会形成全新的上下文EC(FN)
*/
console.log(a) // undefined
var a = 12
function fn() {
/**
* EC(FN)
* AO(FN)
* a
* 代码执行后:a = 13
* 代码执行:
*/
console.log(a) // 此时私有变量a = undefined
var a = 13 // 私有变量a 赋值为13
}
fn()
console.log(a) // 全局变量a的值还是12
(2)
console.log(a)
var a = 12
function fn() {
console.log(a)
a = 13
}
fn()
console.log(a)
/**
* 和(1)几乎一样,差别就在与fn执行的时候
*/
console.log(a)
var a = 12
function fn() {
/**
* fn执行,形成新的私有上下文,这里没有变量提升,没有声明变量
*/
console.log(a) // 所以,输出的还是全局a的值,12
a = 13 // 全局变量a的值改为13
}
fn()
console.log(a) // 输出全局变量a => 13
(3).
/**
* EC(G)
* fn => 0x000000 [[scope]]:EC(G)
* 变量提升:function fn() {...}
*/
console.log(a) // 首先看是否为全局变量,不是的话再看是否为window的一个属性,
//如果不是,则报错 mst练习.html:930 Uncaught ReferenceError: a is not defined(这行代码一旦报错,下面的代码都不处理了)
a = 12
function fn() {
console.log(a)
a = 13
}
fn()
console.log(a)
var foo = 'hello';
(function (foo) {
console.log(foo); // hello
var foo = foo || 'world';
console.log(foo); // hello
})(foo);
console.log(foo); // hello
/**
* EC(G)
* VO(G)
* foo
* foo = 'hello'
* 变量提升:var foo
* 代码执行:var foo = 'hello'
*/
var foo = 'hello';
(function (foo) {
// 自执行函数,执行时形成全新的私有上下文
/**
* EC(ANY)
* AO(ANY)
* 作用域链:<EC(ANY),EC(G)>
* 形参赋值:foo = 'hello'
* 变量提升:var foo(已经声明过foo,不再声明)
* 代码执行:
*/
console.log(foo); // 私有foo => 'hello'
// A || B A的值是真,返回A的值,否则返回B的值
// A && B A的值是真,返回B的值,否则返回A的值
// 同时出现,&& 优先级高于 ||
var foo = foo || 'world'; // foo = 'hello'
console.log(foo); // 'hello'
})(foo);
console.log(foo); // 全局foo => 'hello'
知识点:
A || B A的值是真,返回A的值,否则返回B的值
A && B A的值是真,返回B的值,否则返回A的值
同时出现,&& 优先级高于 ||
(1)
{
function foo() {}
foo = 1
}
console.log(foo) // function foo() {}
(2).
{
function foo() {}
foo = 1
function foo() {}
}
console.log(foo) // 1
/**
* EC(G)
* VO(G)
* foo undefined
* 0x000001
* 1
*
* 变量提升:function xxx() {} 不出现在{}中是声明+定义
* 出现在{}中(对象/函数除外)只声明不定义
* 代码执行:{}中出现let/const/function会形成私有块级上下文
*/
{
/**
* 私有块级上下文EC(BLCOK)
* EC(BLOCK)
* AO(BLOCK)
* foo => 0x000000
* 0x000001
* 1
*
* 作用域链:<EC(BLOCK),EC(G)>
* 变量提升:function foo() {} (声明+定义)
* 第二次:function foo() {}
* (foo已经声明过,所以这次只定义,foo的值以第二次定义的为准:0x000001)
*/
function foo() {} // 因为全局声明过foo,块级私有上下文也声明过foo,所以会把这行代码之前对foo的操作映射给全局一份
foo = 1 // 私有foo值变为1
function foo() {} // 又遇到这行代码,还是会把这行代码之前的操作给全局一份,所以全局foo的值是1
}
console.log(foo) // 1
(3).
{
function foo() {}
foo = 1
function foo() {}
foo = 2 // 私有foo变为2
console.log(foo) // 2
}
console.log(foo) // 全局foo变为1
- (1)
var x = 1
function func(x,y=function anonymous1(){x=2}) {
x = 3
y()
console.log(x)
}
func(5)
console.log(x)
(2).
var x = 1
function func(x,y=function anonymous1(){x=2}) {
var x = 3
y()
console.log(x)
}
func(5)
console.log(x)
总结:
函数执行如果满足以下两个条件
- 形参有赋值默认值(不管有没有传实参,不管默认值是什么类型)
- 函数中有变量声明(必须是基于let/const/var, 注意的是let/const声明的变量不能和形参的变量名一致)
满足以上两个条件会形成一个新的块级私有上下文EC(BLOCK)
- 私有快及上下文中要执行的代码就是 函数{}中的代码
- 函数{}中的代码如果有声明的变量(带var/let/const)才是块级私有上下文的私有变量,和函数私有上下文没有关系了
- EC(BLOCK)的上级上下文就是函数私有上下文EC(FUNC)
- 函数私有上下文EC(FUNC)形参赋值结束后,会把赋值结果映射给EC(BLOCK)中相同变名字的变量
注意:形成EC(BLCOK)后,要执行的是EC(BLOCK),私有函数上下文EC(FUNC)不再执行(拿此例来说,到变量提升就结束了)
(3).
var x = 1
function func(x,y=function anonymous1(){x=2}) {
var x = 3
var y = function anonymous2(){
x=4
}
y()
console.log(x) // 4
}
func(5)
console.log(x) // 全局x:1
/**
* EC(G)
* VO(G)
* x undefined
* 1
* func => 0x000000 [[scope]]:EC(G)
* 变量提升:var x; function func(...){...}
* 代码执行:var x = 1;function func(x,y...){...}(变量提升时声明+定义,此时不再处理);func(5)
*/
var x = 1
function func(x,y=function anonymous1(){x=2}) {
/**
* func(5)执行,形成函数私有上下文EC(FUNC)
*
* EC(FUNC)
* AO(FUNC)
* x 5
* y 0x000001 anonymous1 [[scope]]:EC(FUNC)
* 作用域链:<EC(FUNC),EC(G)>
* 形参赋值:x = 5
* y = function anonymous1(){...}
* 变量提升:var x;(func这个函数,形参有默认值,且函数里有var声明变量,所以会形成一个全新的块级私有上下文EC(BLOCK))
*/
/**
* EC(BLOCK)
* A0(BLOCK)
* x 5(初始时是5,EC(FUNC)中会把形参赋值结束后的值映射给EC(BLOCK)中相同的变量名)
* 3
* 4(EC(Y)执行时将值改为4)
* y anonymous1(初始值是anonymous1,理由同上)
* anonymous2 0x0000001 [[scope]]:EC(FUNC)
* 作用域链:<EC(BLOCK),EC(FUNC)>
* 形参赋值:--
* 变量提升:var x;var y = function anonymous2....
* 代码执行:var x = 3
*/
var x = 3 // 私有变量x改为3
var y = function anonymous2(){
/**
* EC(Y)
* 作用域链:<EC(Y), EC(BLOCK)>
* 形参赋值:--
* 变量提升:--
* 代码执行:
*/
x=4 // 不存在私有变量x,沿着作用域链想上找,找到上级上下文EC(BLOCK)
}
y() // y执行,形成全新的私有上下文。EC(Y)
console.log(x) // 4
}
func(5)
console.log(x) // 全局x:1