JS 范围链 与 提升 DAY49

范围链(Scope Chain)
Def:
当函式本身使用的变数不存在 就会向外层寻找
(这里的外层不一定是全域!!)

我们在前面有提到
当 函式fn1 没有 num 变数时
会向外层寻找
而寻找过程与执行环境毫无关系 (请牢记!!)
是依据函式文法本身来决定范围链

所以这里的 fn1 与 fn2 的范围链
皆指向 全域

var num = 1;
function fn1(){
    //请看这里
    console.log(num);
}
function fn2(){
    var num = 10;
    fn1();
}
fn2();

提升(Hoisting)

重要!!
在 JS基础篇 我们有提到

//这里其实是两个步骤
var name = '皮杰先生';

//宣告变数
var name;
//赋予值道变数上
name = '皮杰先生';

//这两个结果会是一样的

那到底是为什麽呢??
这里我们要先来提一下 我们上一篇提到的 执行环境
在建立一个执行环境的时候
其实是有两个阶段

  • 创造环境
  • 执行

我们刚刚都是着重在 执行
那创造阶段到底是做什事情??

创造阶段
先将变数配置一个 记忆体空间
(所以用console来看会是undefined)

执行
赋予值

在创造环境把记忆体空间准备好
就称为 提升(Hoisting)

比较不同的是
若是 函式陈述式(这里是函式陈述式 并非函式表达式)
在创造阶段就会优先载入(请牢记!!)
简单来说
创造阶段,函式已经可以执行
而变数要等到执行阶段才会赋予值

例:

var a = '1';
function fn(){
    //.....
}

创造阶段
https://ithelp.ithome.com.tw/upload/images/20201014/20123039KAfxFu4l1w.jpg

执行阶段
https://ithelp.ithome.com.tw/upload/images/20201014/201230393q0UKYOcrs.jpg

例 1

var name; //创造阶段
name = '皮杰先生'; // 执行

例 2

console.log(name); // undefined
var name = '皮杰先生';

例 3

function fn(){
    console.log('皮杰先生') //皮杰先生
}
fn();

例 4

fn();
function fn(){
    console.log('皮杰先生') //皮杰先生
}

例 5( 例3 , 例4拆解 )

//创造阶段
function fn(){
    console.log('皮杰先生') 
}
//执行
fn();

会发现 例3 , 例4 皆会执行
是因为创造阶段 函式就已经载入
而不会像 例2 呈现 undefined
因为变数是在执行阶段 才赋予值

例 6 (函式表达式)

fn();
var fn = function(){
    console.log('皮杰先生'); //undefined
}

例 7 ( 例6拆解 )

//创造阶段
var fn; //配置记忆体 但尚未赋予值
//执行

//若使用函式表达式 要等到函式赋予到变数上 才能运行函式
fn();

fn = function(){
    console.log('皮杰先生'); //undefined
}


这里要额外提一个重要观念
创造阶段的时候 函式优先(请牢记!!)
这里举个例子 方便厘清

例 8

var fn = function(){
    console.log('皮杰先生 2');
}
function fn(){
    console.log('皮杰先生 1');
}
fn(); //皮杰先生 2

例 9

// 两个函式位置互换
var fn = function(){
    console.log('皮杰先生 2');
}
function fn(){
    console.log('皮杰先生 1');
}
fn(); //皮杰先生 2

会发现 例8 , 例9
皆为 皮杰先生 2
为什麽!!!!
因为上面有提到
在创造阶段的时候函式优先

例 10 ( 例8 , 例9拆解 )

//创造阶段
//函式优先
function fn(){
    console.log('皮杰先生 1');
}
var fn;

//执行
fn = function(){
    console.log('皮杰先生 2');
}
fn();

例 11

fn();
function fn(){
    console.log(man); //undefined
}
var man = '皮杰先生';

//拆解
//创造阶段
function fn(){
    console.log(man); 
}
var man;


//执行
fn(); // 这里执行 fn 时 , man尚未赋予值 所以为undefined
man = '皮杰先生';

例12

function fn(){
    console.log('皮杰先生'); //小鸡公主
}
fn();
function fn(){
    console.log('小鸡公主'); //小鸡公主
}
fn();

//拆解

//创造阶段
function fn(){
    console.log('皮杰先生'); //小鸡公主
}
function fn(){
    console.log('小鸡公主'); //小鸡公主
}
//执行
fn();
fn();

//所以函式名称相同的话 後面的会覆盖前面的

那今天的介绍就到这里啦~~
内容很多 也很重要
务必多看几次/images/emoticon/emoticon07.gif
明天我们将介绍
执行绪与同步非同步
若有任何问题 或 内容有误
请别吝啬的跟我说唷~~


<<:  Day34 | WebView元件开发 - 使用Ant Design Mobile UI Library

>>:  Grid笔记

【Day22】隐写技术 ─ 工具实作篇(一)

哈罗~ 昨天我们聊到隐写技术(Steganography), 今天就来做一些实作吧! Steghid...

Day 13 懒得想变数吗? RSpec 有提供你啦

该文章同步发布於:我的部落格 还记得我们使用 let 方法来实作一个物件来让我们可以快速使用! 但...

Rust-资料型别-字元.字串

Rust的char型别是最基本的字母型别,用单引号包起来 例 let a = 'b'; Rust的字...

Day22:22 - 结帐服务(6) - 前端 - 结帐 X PayPal付款

Helló,我是Charlie! 在Day21当中我们完成了後端的paypal sdk,在今天我们将...

【把玩Azure DevOps】Day29 再次建立Release pipeline:多个不同Artifacts来源

前面的文章建立过了Release pipeline,但是那次并没有加入多个不同的Artifacts来...