作用域 scope
函数作用域
一段程序代码中所用到的名字并不总是有效和可用的,而限定这个名字的可用性代码范围就是这个名字的作用域,作用域的使用提高程序逻辑的局限性,增强了程序的可靠性,减少了名字冲突。
//JavaScript作用域:代码名字(变量)在某个范围起作用和效果 目的是为了提高程序的可靠性,更重要的是减少命名冲突
//js的作用域(es6)之前,全局作用域 局部作用域
//全局作用域:整个script标签 或者是一个单独的js文件
var n = 1;
console.log(num);
//局部作用域(函数作用域) 在函数内部就是局部作用域 这个代码的名字只在函数内部起作用
function fn(){
//局部作用域
var n = 1;
console.log(n)
}
fn();
块级作用域 es6新增的,块级作用域{} if{} for{}
变量作用域(var)
在JavaScript中,根据作用域的不同,变量可以分为两种:全局变量;局部变量
全局变量
在全局作用域下声明的变量为 全局变量 (在函数外部定义的变量)。在代码中的任何位置都可以使用,特殊情况下,在函数内不使用var声明的变量也是全局变量(不建议使用)
局部变量
在局部作用域下声明的变量叫做局部变量(在函数内部定义的变量)。局部变量只能在该函数内部使用;函数的形参实际上就是局部变量。
二者区别
- 全局变量:在任何一个地方都可使用,只有在浏览器关闭时才会被销毁,因此比较占内存
- 局部变量:只在函数内部使用,当其所在代码块被执行时,会被初始化;当代码块运行结束后,就会被销毁,因此更节省空间。
//变量的作用域:根据作用域的不同我们变量分为全局变量和局部变量
//全局变量:在全局作用域下的变量 在全局都可以使用
//注意 如果在函数内部没有声明直接赋值的变量也属于全局变量
var n = 10;
console.log(n);
function fn(){
console.log(n);
}
fn();
//局部变量 在局部作用域下的变量 或者在函数内部的变量就是 局部变量
//注意 函数的形参也可以看做是局部变量
function fn(){
var n1 = 10;
n1 = 20;
}
fn();
console.log(n1);
// 从执行效率来看全局变量和局部变量
// 全局变量只有浏览器关闭的时候才会销毁 比较占用内存资源
// 局部变量 当程序执行完毕就会销毁 节约内存资源
js 两种作用域:全局作用域和局部作用域。
在函数定义之外声明的变量是全局变量 它的值可在整个程序中访问和修改。
在函数定义内声明的变量是局部变量,每当执行函数时,都会创建和销毁该变量,且无法通过函数之外的任何代码访问该变量。
js中 在函数体内 var 声明的变量是函数级作用域,是局部变量,在本函数体内可以访问,而且是在函数体内任意位置可以访问
function t(){
console.log(val);
var val = '我是输出 val';
console.log(val);
func();
function func(){
for(var i = 0;i < 5;i++){
}
console.log('i:',i);
console.log('func');
}
}
t();
//解析流程如下
function t(){
//变量提升
var val;
//函数声明提升
function func(){
// 变量提升
var i;
for(i=0;i<5;i++){
}
console.log('i:',i);
console.log('func');
}
console.log(val);
//变量提升
val = '我是输出 val';
console.log(val);
func();
}
首次 console.log(val) 不会抛异常,此时变量val是被声明过的,值是 undefined 。
作用域链
包含了执行环境有权访问的所有变量和访问顺序。作为单线程语言的js 初始化代码时会创建一个全局上下文,每一次函数调用都会创建一个执行上下文,执行上下文及包含关系;
- 只要是代码,就至少有一个作用域
- 写在函数内部的局部作用域
- 如果函数内部还有函数,那么在这个作用域中就又可以诞生一个作用域
- 内部函数可以访问外部函数变量的机制,用链式查找 来决定哪些数据能被内部函数访问,称之为作用域链。
- 变量对象 变量、函数声明、参数(arguments)
ES6 中的 let 和const
ES6的 let 和 const实现了块级作用域的变量声明方式,使用 let 和const 声明变量能有效避免由于变量提升导致的变量污染的问题。
大括号包着的区域 称之为代码块 块级作用域
注意:const的作用有必要正确理解,const 声明了一个指向变量的指针,并不是说 const声明的变量不可改变,而是 该指针指向的地址不可改变。
this
总是指向调用该函数的对象。
预解析
js代码是由浏览器中的js解析器来执行的。js解析器在运行js代码的时候分为两步:预解析和代码执行。
console.log(n)
var n = 10;
// 相当于执行了 以下代码
var n;
console.log(n);
n = 10;
fn();
function fn(){
console.log(22);
}
fun()
var fun = function(){
console.log(33);
}
//函数表达式 (调用) 必须写在函数表达式的下面
//相当与执行以下代码
var fun;
fun();
fun = function(){
console.log(33)
}
预解析案例
var n = 1;
fun();
function fun(){
console.log(n);
var n = 2;
}
// 执行顺序操作
var n;
function fun(){
var n;
console.log(n);
n = 2;
}
n = 1;
fun();
//案例2
f1();
console.log(c);
console.log(b);
console.log(a);
function f1(){
var a = b = c = 9;
console.log(a);
console.log(b);
console.log(c);
}
//执行过程
function f1(){
var a;
a = b = c = 9;
//var a = b = c = 9;
//相当于 var a = 9;b = 9;c = 9;后面的直接赋值 没有var 声明 作为全局变量
console.log(a);//9
console.log(b);//9
console.log(c);//9
}
f1();
console.log(c)//9
console.log(b)//9
console.log(a);// 报错
// 案例3 undefined,20
var n = 19;
function fn(){
console.log(n);
var n = 20;
console.log(n);
}
fn();
闭包 定义:指有权访问另一个函数作用域中变量的函数 (一个作用域可以访问另一个函数内部的局部变量)
作用:延伸了变量的作用范围;使变量的值始终保持在内存中 且不会污染全局作用域
变量作用域分为全局作用域和局部作用域。在js中(特指es5前的版本) 具有作用域的仅有函数 function。特点是:函数内部可以直接访问外部变量,但 在函数外部无法访问函数内部变量。特有的 ‘作用域链’ 结构。
function fn(){
var n = 1;
return function(){
console.log(n);
}
}
var f = fn();
f();
使用注意:
由于闭包会使得函数中的变量都被保存在内存中,内存消耗较大,故不能滥用闭包,性能问题,在IE 中可能导致内存泄漏。在退出函数之前,将不使用的局部变量全部删除。
闭包会在父函数外部,改变父函数内部变量的值。所以,如果把父函数当做对象使用,把闭包当做它的公用方法,把内部变量当做它的私有属性,不要随便改变父函数内部变量的值。
执行上下文
定义:指当前执行环境中的变量、函数声明、参数(arguments)、作用域链,this等信息。分为全局执行上下文、函数执行上下文、其区别在与全局执行上下文只有一个,函数执行上下文在每次调用函数时 会创建一个新的函数执行上下文。
const ExecutionContextObj = {
VO:window,
ScopeChain:{},
this:window
};
执行上下文生命周期
- 创建阶段
-
创建arguments
-
扫描函数声明
-
扫描变量声明
-
生成变量对象
-
建立作用域链
-
确定this的指向
- 执行阶段
-
变量赋值
-
函数的引用
-
执行其他代码
-
执行完毕出栈,等待回收
执行上下文栈
作用:用来跟踪代码,由于js是单线程的,每次只能做一件事情,其他的事情会放在指定的上下文栈中排队等待执行。
解释器在初始化代码时,先创建一个新的全局执行上下文到执行上下文栈顶,然后随着每次函数的调用都会创建一个新的执行上下文放入到栈顶中,随着函数执行完毕后被执行上下文栈顶弹出,直到回到全局的执行上下文中。(栈:一种数据结构,遵循后进先出的原则)。
function getClass(){
const year = getYear();
const name = 'ccs';
console.log(`${name}${year}`)
}
function getYear(){
return 18;
}
getClass();
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/163331.html