关于闭包 RHS 与 LHS

发布于 2022-09-06 01:47:05 字数 672 浏览 17 评论 0

看一个闭包代码

function  wait(message)
{
    setTimeout(function timer()
    {
        console.log(message);
    },1000);
}

wait("hello");

根据 you dont know js所说
闭包 一 可以访问外层变量 二 在外部作用域下执行

我试着用RDS 与 LHS理解遇到问题了

先明确下词法作用域
全局作用域下
wait setTimeout函数
wait 作用域下
message形参 timer函数
setTimeout 作用域下
fn 因为没有列出这个函数,但是一定有这个形参

第一步
RDS wait 全局作用域下成功 因为是在全局作用域下执行的
隐式的 message = 'hello' LHS message 这个可以理解成是在wait作用域下执行的吗?所以LHS成功
RDS setTimeout 在wait作用域里执行,wait失败,到全局找到执行
隐式的 fn = function timer() 可以理解成在setTimeout作用域下执行的吗?所以 LHS 成功
然后 RDS timer 这个怎么理解啊!作用域是哪个呢? 这个部分我很迷惑啊!!求人帮我解答下?最好能指明我思路的错误!!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

病女 2022-09-13 01:47:05
function wait(message){
    setTimeout(function timer()
    {
     console.log(message);
    },1000);
}
wait("hello");

最近在学习C语言,加深了理解
涉及到的知识点
1 什么是作用域?调用变量时候,变量的可用(生效)范围!
2 确认作用域,(JS C PHP 都是使用的静态作用域,代码在书写(未执行)的时候就已经知道作用域了!)
作用域有全局作用域和块作用域(C语言中{}就是一个作用域)(js中声明一个函数才会有作用域)。凡是在作用域中声明的变量都是属于此作用域!!!
4 RHS(变量执行时候查找其值)和LHS(变量查找其空间)实际上就是变量作用域的查找
5 代码执行时候的就开始进行变量的查找(最简单的一点,变量只可能书写在代码中,而只要是代码,就会有作用域!),我们暂称为执行域(变量在哪个域中({}或全局)执行的)。
6 执行域会形成一个链条(我喜欢称执行域链,大多书里称为作用域链),执行域链的确认(链条的终端必须是全局!!)!
一个简单的实例 在B函数中调用一个变量,执行域是B,B执行后,作用域是全局,执行域链条是(B->全局),如果B中没有这个变量,就会去全局中查找!如果我只是在B中执行一个变量,而我B并没有执行,那么执行域链是断掉的!!那么代码就有错了!!
eg A函数在B函数中执行,B函数在C函数中执行,C函数在全局中执行!(看到没,必须这样执行才会形成一个链条 A->B->C->全局)!最最重要的,在这个链条上必须有一个和作用域相匹配!(我在C中声明一个变量,但是我在A中执行,且执行链条形成,那么我找到的会是C的那个!)
6 JS闭包(内部函数)需要满足两个条件,闭包访问外部变量,并且在外部作用域中执行!

我们根据上面提到的六点来说下
1作用域的确定
全局作用域 wait(), setTimeout()
wait作用域 timer(),message (这涉及到了形参和实参),实参和形参的RHS执行域链是不一样的,实参是内部的!
setTimeout fn();//这是一个形参被 timer进行传值
2 嵌套关系的查看,根据执行域,和作用域链(调用栈)

wait("hello");
RHS wait 执行域全局 作用域全局 RHS成功匹配
RHS settimeout 作用域全局 执行域链wait -> 全局(settimeout在wait下执行,wait在全局下执行) RHS成功匹配
RHS timer 作用域 wait 执行域链 settimeout -》 wait -》全局 RHS成功

RHS message 作用域 wait 执行域链timer -》settimeout -》wait-》全局 RHS成功

3 为什么说timer是闭包,他在外部作用域执行(原本属于作用域wait,结果在settimeout作用域下执行)

4 timer的message获取的是外部的变量,

5所以是闭包,至于闭包有什么用,请参考其余。

往昔成烟 2022-09-13 01:47:05

You Don't Know JS 是本好书,但是很多问题讲得太复杂了。

第一 闭包其实就是怎样读取变量的问题,首先看三种情况:

var bar = 'goodbye';
function foo(){
  var bar = 'hello';
  console.log(bar); // 'hello', 因为`foo`内部已有定义,就近读取
}
foo();
var bar = 'goodbye';
function foo(bar){
  console.log(bar); // undefined, 因为`foo`参数已有定义,就近读取
}
foo();
var bar = 'goodbye';
function foo(){
  console.log(bar); // 'goodbye', 因为`foo`未定义`bar`,外部读取
}
foo();

第二 明白函数(方法)的定义执行的区别:

// 这是`foo`的定义
function foo(){ }

// 这是`foo`的执行:
foo();
function foo(){
  // 这是`bar`的定义
  var bar = function(){ };

  // 这是`bar`的执行
  bar();
}
foo();
function foo(){
  var bar = function(){
    // 这是`bar`的递归执行
    bar(); // 注意:**不**要执行这段死循环代码
  };
  bar();
}
foo();
// 这是`setTimeout`的执行,同时也定义了`timer`,
// 但是`timer`没有马上执行,而是大概 1s 后在`setTimeout`内部执行
setTimeout(function timer(){
  console.log('hello');
}, 1000);

第三 明白函数(方法)的何时执行以及调用栈

// 在这段代码中...
function foo(){
  setTimeout(function timer(){
    console.log('hello');
  }, 1000);
}
// 问:`setTimeout`执行了吗?`timer`呢?`console.log`呢?

// 答:都没有执行,因为它们在`foo`内部由`foo`调用才能得到执行,
// 但是`foo`本身都没有被调用执行,所以它们都不会被调用执行。
// 一旦调用`foo`,`foo`就会调用`setTimeout`,`setTimeout`就会调用`timer`,
// `timer`就会调用`console.log`...
// 像这样的调用关系可以变得任意复杂或由线性变成网状,
// 但是它们严格按照一个顺序,于是就形成了调用栈。

第四 明白函数(方法)作为第一等公民:

// 函数第一等公民:作为参数传入其他函数
function setTimeout(timer, time){
  // `setTimeout`在`time`时间后调用`timer`,
  // 但是`setTimeout`不需要知道`timer`是怎样定义的,
  // 不需要知道`timer`能做什么,
  // 也不需要知道`timer`是怎样做的。

  // `setTimeout`仅仅是调用`timer`,
  // 至于怎样执行,完全由`timer`自行决定
  timer();
  // 就是在这里,请你停下来想想,
  // 执行`timer`会有什么结果?
  // 答案是,会有无限可能的结果。
  // 因为你不知道`timer`来自哪里,
  // 你也不知道`timer`里面包含了什么。
  // 这个`timer`就好像是一个快递,即闭包,
  // 而调用`timer`就好像是打开快递,即接收闭包。
}

// 函数第一等公民:作为作为表达式从其他函数返回
var foo = 0; // foo1
function outer(){

  var inner = function(){
    // 在`inner`定义的时候,
    // 完全不关心`foo`的值是什么,
    // 只关心`foo`的地址是什么。
    
    // 至于`foo`的值是什么,
    // 要等到`inner`执行时去查找,
    // 一旦找到,`inner`不仅能读取`foo`,
    // 还能写入`foo`
    foo += 1;
    console.log(foo); 
  }
  // 此时不要执行`inner`,
  // 但是硬要执行,`foo`为设置[foo2 = NaN],
  // 而不是[foo1 = 0],也不是[foo2 = 1],
  // 这好像很怪异,都怪你在这里怪异地调动`inner`,
  // 也就是说,在这里调动`inner`很怪异,不要这样做
  // inner(); 

  var foo = 1; // foo2
  
  inner(); // 改变了[foo2 = 2],打印 2

  
  // 将`inner`返回,
  // 但是无论`inner`被返回到哪里,
  // 无论`inner`被传输到哪里,
  // 无论`inner`在哪里被调动执行,
  // 它所产生的效果都是一样的,
  // 也就是,改变[foo2]的值
  return inner;
}

outer();

以上答案没有完全回答你的问题,但是希望可以给你一点思考的灵感,然后再进行讨论。我迟点可能会写篇文章详细讲述我的理解。当然,我也是初学者。

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文