当前位置: 首页 > Web前端 > JavaScript

【JS基础复习】作用域、this、闭包

时间:2023-03-27 16:37:32 JavaScript

Scope作用域是变量、函数、对象在运行时代码的某些特定部分的可访问性。换句话说,范围决定了代码块中变量和其他资源的可见性。functionfoo(){vara=1}foo()console.log(a)//UncaughtReferenceError:inVariableisnotdefined会有冲突。在JavaScript中,作用域可以分为全局作用域和函数作用域。在ES6之前,JavaScript没有块级作用域,只有全局作用域和函数作用域。ES6的到来为我们提供了“块级范围”,这可以通过添加命令let和const来体现。块级作用域块级作用域可以通过新的命令let和const来声明,声明的变量不能在指定块作用域外访问。块级作用域在以下情况下被创建:函数内部,代码块内部(由一对花括号包裹)内部作用域链1.自由变量首先,让我们了解什么是自由变量。在下面的代码中,console.log(a)需要获取一个变量,但是a在当前范围内没有定义(比较b)。当前范围内未定义的变量,this成为自由变量。如何获取自由变量的值——从父作用域中寻找(注意:这种说法并不严谨,下面会解释)。2.如果没有父级,什么是作用域链?然后一层层往上找,直到全局作用域都找到或者没有找到,然后放弃。这种逐层关系就是作用域链。leta='global';console.log(a);functioncourse(){letb='zhaowa';控制台日志(b);会议();functionsession(){让c='this';.log(c);老师();函数教师(){让d='yy';控制台日志(d);console.log('test1',b);}}}console.log('test2',b);course();if(true){让e=111;console.log(e);}console.log('test3',e)ExecutionContext很多开发者经常混淆scope和executioncontext的概念,误认为它们是同一个概念,其实不然。JavaScript是一种解释型语言。JavaScript的执行分为解释和执行两个阶段。这两个阶段做的事情不一样:解释阶段:词法分析语法分析作用域规则确定执行阶段:创建执行上下文执行函数作用域规则是在代码垃圾回收的JavaScript解释阶段确定的,所以作用域是在函数执行时确定的定义,不是在调用函数时,而是在执行函数之前创建执行上下文。关于执行上下文最明显的一点是,this的要点是在执行时确定的。作用域访问的变量由编写代码的结构决定。作用域和执行上下文最大的区别是:执行上下文是在运行时确定的,随时可能发生变化;范围在定义的时候就确定了,不会改变。thisthis的绑定其实就是调用函数时发生的绑定,也就是this指向什么取决于你怎么调用函数。this是通过在执行期间动态读取上下文来确定的,而不是this创建时的绑定规则。默认绑定函数foo(){console.log(this.a);}vara=2;富();//2defaultbinding:bindtheglobalobjecttothis注意:在严格模式(strictmode)下,全局对象将无法使用默认绑定,即执行会报undefinederror。上下文对象。functionfoo(){console.log(this.a);}vara=2;varobj={a:3,foo:foo};obj.foo();//3隐式丢失(回调函数)functionfoo(){console.log(this.a);}vara=2;varobj={a:3,foo:foo};setTimeout(obj.foo,100);//2也是一样,虽然看到传递的是obj.foo,因为是引用关系,所以实际传递的是foo对象本身的引用。对于setTimeout的调用,依然是setTimeout->获取参数中foo的引用参数->执行foo的函数,中间没有obj的参与。这里仍然是默认绑定。显示绑定调用或应用或绑定函数foo(){console.log(this.a);}vara=2;varobj1={a:3,};varobj2={a:4,};foo.call(obj1);//3foo.call(obj2);//4call、apply、bind的区别call和apply的用法几乎是一样的,唯一的区别就是传递的参数不同,call只能传入一个参数和一个参数。apply只支持传入一个数组,而且连一个参数都必须是数组的形式。当最终调用该函数时,数组将被拆分为参数并分别传入。至于bind方法,直接改变了这个函数的this指向,返回一个新的函数,然后再次调用这个函数时,this指向bind绑定的第一个参数。bind方法与call方法相同。手写bindFunction.prototype.myBind=function(){const_this=this//复制参数constargs=Array.prototype.slice.call(arguments);constnewThis=args.shift();返回函数(){返回_this。apply(newThis,args)}}手写applyFunction.prototype.myApply=function(context){//参数检测context=context||窗户;//指向挂载函数context.fn=this;//}bindingrulestakeprecedence级别是在new(新绑定)中调用的吗?如果是这样,这是否绑定到新创建的对象?是通过调用、应用(显式绑定)还是硬绑定来调用?如果是这样,这将绑定到指定的对象。它是在上下文对象中调用的(隐式绑定)吗?如果是这样,则this将绑定到该上下文对象。如果两者都不是,则使用默认绑定。如果在严格模式下,绑定到undefined,否则绑定到全局对象。规则异常函数foo(){console.log(this.a);}foo.call(null);//2foo.call(undefined);//2个箭头函数varfoo=()=>{console.log(this.a);}vara=2;varobj={a:3,foo:foo};obj.foo();//2foo.call(obj);//2、绑定没有显示在箭头函数中会生效functionfoo(){return()=>{console.log(this.a);}}vara=2;varobj={a:3,foo:foo};varbar=obj.foo();bar();//3闭包什么是闭包?一个函数与其周围状态(lexicalenvironment,词法环境)的引用捆绑在一起(或者函数被引用包围),这样的组合就是一个闭包(closure)。也就是说,闭包允许您从内部函数内部访问外部函数的范围。在JavaScript中,无论何时创建一个函数,都会在创建该函数的同时创建一个闭包。闭包场景函数作为返回值场景函数mail(){letcontent='letter';返回函数(){console.log(内容);}}constenvelop=mail();envelop();functionasparameter//单一职责letcontent;//通用存储函数envelope(fn){content=1;fn();}//业务逻辑函数mail(){console.log(content);}envelop(mail);函数嵌套letcounter=0;functionouterFn(){functioninnerFn(){counter++;控制台日志(计数器);//...}返回innerFn;}outerFn()();事件执行letlis=document.getElementsByTagName('li');for(vari=0;i