在e s6之前,前端js对变量的命名是没有严格的块级作用域的区分的,而在es6中,增加了这么个首要的基础特性,那么因此就不得不说一下首要的这个基础特性。
(一)作用域
作用域(scope),程序设计概念,通常来说,一段程序代码中所用到的名字并不总是有效/可用的,而限定这个名字的可用性的代码范围就是这个名字的作用域。
作用域的使用提高了程序逻辑的局部性,增强程序的可靠性,减少名字冲突。
对于对象而言(其他也是一样的),在main函数中,对象的作用域为他所在的最近的一对花括号内。在后花括号处析构函数被调用;全局的对象的作用域为声明之后的整个文件,析构函数在最后被调用。另外,临时产生的对象在使用完后立即会被析构。
上面这段内容摘自百度百科,从这段文字中即可看到,有些变量或者函数在其使用过程中,并不需要其永远存在,当我们需要使用它时,实例化将其定义,当使用完毕之后,将其舍弃,创建的过程叫做构造,舍弃的过程叫做析构。在构造和析构的这一过程中所存在的范围,即为其作用域。
举例说明:当我们需要做循环遍历处理时,通常会定义一个i变量,这个变量被for语句包围:
for(int i = 0 ;i <x ;i ++){}
这里的i的作用域即为所在的这一段代码区域。当程序运行完这一段之后i进行销毁处理。
在es6之前,在一段方法之后,才去定义某个特殊变量,而在定义这个变量之前,若函数已经执行,并且使用了该变量,但是函数不会报出错,就是因为没有变量作用域,其定义位置不影响使用,程序在执行之前进行编译时会将其定义位置提前,放到文件上下文最前进行定义声明,这种行为 叫做 作用域提升。
而没有块级作用域的话,在for执行完后 i变为x,仍可被调用使用,直到当前函数结束,javascript的作用域是相对函数而言的。
(二):作用域链
根据在内部函数可以访问外部函数变量的这种机制,用链式查找决定哪些数据能被内部函数访问。 每个函数运行时都会产生一个执行环境,而这个执行环境怎么表示呢?js为每一个执行环境关联了一个变量对象。环境中定义的所有变量和函数都保存在这个对象中。
全局执行环境是最外围的执行环境,全局执行环境被认为是window对象,因此所有的全局变量和函数都作为window对象的属性和方法创建的。
js的执行顺序是根据函数的调用来决定的,当一个函数被调用时,该函数环境的变量对象就被压入一个环境栈中。而在函数执行之后,栈将该函数的变量对象弹出,把控制权交给之前的执行环境变量对象。
函数在运行时,调用某一变量,若当前块内没找到,则到上级目录中再去寻找该变量,若在上级目录中找到则使用,若仍未查找到则报underfinded。
(三):this指向的作用域
例1: a作为方法,在全局调用
var scope = '0';
var a = function(){
var scope = '1';
console.log('3:'+scope);
console.log('4:'+this.scope);
return function b(){
console.log('5:'+scope);
}
};
console.log('1:'+this.scope);
a()();
console.log('2:'+this.scope);
上述代码打印是:
从运行结果可以看到在未调用a时,scope值为0不变,this指向window。在a中重新定义了scope设置值变为1,在a中直接打印scope发现变量起作用,变为1,此时打印this.scope值还是为0,说明这里的this指向并不是a,而是window,并且这里的scope无法 影响到外部。而通过结果5发现scope为1 说明受值改变影响,即a方法中定义的变量属性只能在a中起作用。
例2:a作为方法,在全局调用
var scope = '0';
var a = function(){
var scope = '1';
console.log('3:'+scope);
var c = function(){
scope = "2";
console.log('4:'+this.scope);
};
return function b(){
c();
console.log('5:'+scope);
}
};
console.log('1:'+this.scope);
a()();
console.log('2:'+this.scope);
打印结果为:
例3:a 作为对象调用其中的方法
var scope = '0';
var a = {
scope : '1',
c :function(){
scope = "2";
console.log('4:'+this.scope);
},
b : function(){
a.c();
console.log('5:'+scope);
}
};
console.log('1:'+this.scope);
a.c(); //a调用c,c中的this指向a,所以this.scope值不为2而为1
console.log('2:'+this.scope);
例4:a 作为对象调用其中的方法,并且演示作用域提升--4打印的值不为1,实际上为3
var scope = '0';
var a = {
scope : '1',
c :function(){
scope = "2";
console.log('4:'+this.scope);
},
scope : '3',
b : function(){
a.c();
console.log('5:'+scope);
}
};
console.log('1:'+this.scope);
a.c();
a.b();
console.log('2:'+this.scope);
//例5:a 作为对象调用其中的方法;并且演示作用域提升--4打印的值不为1,实际上为3;并且区分怎么获取局部变量的值
var scope = '0';
var a = {
scope : '1',
c :function(){
console.log('4:'+this.scope);
},
scope : '3',
b : function(){
console.log('5:'+scope);
}
};
console.log('1:'+this.scope);
a.c();
a.b();
console.log('2:'+this.scope);
this对象是在运行时基于函数的执行环境绑定的:在全局函数中,this等于window,而当函数被作为某个对象调用时,this等于那个对象,所以例5中的c可以打印出a的变量值3,b中打印的值是全局的值0。不过,匿名函数具有全局性,因此this对象同常指向window
总结:this的指向与其定义位置无关,而与调用位置有关,匿名函数的this指向window。
(四)es6,变量和常量
es6中,使用let代替var来定义变量,使用let定义的变量则会存在块级作用域,当函数运行完该块,则let定义的变量失效。
es6使用const 定义常量,常量定义之后不能再做更改,如。const a = 10;则 a在其作用域内永远都是10,不能对其进行重新赋值操作。
但是若定义const a = {name:'章三',sex:'男'},可以进行 a.name = '李四',这样的重新赋值操作,原因是,声明定义一个对象的时候,其变量名只是一个指向对象真实内部存储的地址,只要a这个地址不变,a中的实际内容如何变化a都没有改变,自然也不会违法设想。