1, let const var 区别
let
语句声明一个块级作用域的本地变量,并且可选的将其初始化一个值;
允许你声明一个作用域被限制在块级中的变量,语句或表达式
作用域规则
let声明的变量只在其声明的块或子块中可用;
function varTest() {
var x= 1;
{
var x = 2;
console.log(x); // 2
}
console.log(x); // 2
}
function letTest() {
let x= 1;
{
let x = 2;
console.log(x); // 2
}
console.log(x); // 1
}
全局创建变量let 和 var的区别
let 不会在全局对象里新建一个属性
var 创建变量,会在全局对象里新建一个属性
var x = 'global';
let y = 'global';
console.log(this.x); // global
console.log(this.y); // undefined
重复声明 let 和 var
let 不能重复创建相同的变量 (解析语法不合法)
var 可以重复创建
暂存死区
var 初始化前遇到声明的值会初始化为 undefined
let 初始化前遇到声明的值会报错ReferenceError
functio do_something(){
console.log(bar); // undefined
console.log(foo); // ReferenceError
var bar = 1;
let foo = 2;
}
暂时死区与typeof
console.log(bar); // undefined
console.log(foo); // ReferenceError
console.log(typeof bar); // undefined
console.log(typeof foo); // ReferenceError
var bar = 1;
let foo = 2;
暂时性死区和静态作用域
在同一行,这个if块中的foo已经在词法中被创建,但没有达到,或终止他的初始化
function test(){
var foo = 33;
if(foo){
let foo = (foo + 55); // ReferenceError
}
}
暂时性死区 在一种情况
let n of n.a 已经在for循环块的私有范围内,标识符n.a被解析为位于指令本身 let n中的对象属性a,在没有执行完他的初始化语句,仍旧存在暂时性死区
function test(n) {
console.log(n);
for(let n of n.a){ // n ReferenceError
console.log(n);
}
}
test({a:[1,2,3,4]})
正常
function test(n,a) {
console.log(n);
for(let n of a){
console.log(n);
}
}
test({a:[1,2,3,4]},[1,3,45,])
let 和 var 合并声明
var 会将变量提升至块的顶部,导致隐式的重复声明变量
let x = 1;
{
var x = 2; // SyntaxError
}
const
常量的块级范围,类似let,不能重新赋值,不能重新声明 暂时性死区
定义数组和对象
不能重新赋值,但是可以改变属性的值,属性值不受保护
const obj = {};
obj = {}; // 报错obj.a = 'p' // 正常
var
变量声明,无论在哪声明,都在执行任何代码之前进行处理,用var声明的变量的作用域是他当前执行上下文
声明的变量的作用域限制在其声明位置的上下文中,而非声明变量总是全局的
function x(){
y = 1; // 严格模式下会抛出异常
var z = 2;
}
x();
console.log(y); // 1
console.log(z); // ReferenceError z未在x外部声明
声明变量在任何代码执行前创建,而非声明变量只有在执行赋值操作的时候才被创建
console.log(a); // ReferenceError 没声明的变量只有在赋值时才被创建
console.log('still go .....'); // still go...
下段代码
var a;
console.log(a); // undefined;
console.log('still go....'); // still go..
声明变量是它所在上下文环境的不可配置属性,非声明变量是可配置的(如非声明变量可以被删除)
var a = 1;
b = 2;
delete this.a; // 在严格模式下 抛出 TypeError 其他情况下执行失败并无任何提示
delete this.b;
console.log(a,b); // 抛出ReferenceError
// b属性已经被删除
由于上面的几种情况,建议始终定义变量
变量提升
由于变量声明,总是在任意代码执行前处理,代码中任意位置声明变量总是等效于在代码开头声明,意味着变量可以在声明之前使用,hoisting
bla = 2;
var bla;
// 可以隐式的(implicitly)理解为
var bla;
bla = 2;
建议在作用域顶部声明变量
给两个变量赋值成字符串
var a = 'A';
var b = a;
等于
var a, b = a = 'A';
赋值的顺序
var x = y,y = 'A';
console.log(x + y); // undefinedA
2,eval
eval() 函数会将传入的字符串当作js代码进行执行
console.log(eval('2+2')); // 4
console.log(eval(new String('2+2'))); // 2+2
eval是一个危险函数,它是使用与调用者相同的权限执行代码,如果被恶意修改,您最终可能会在您的网页权限下,在用户计算机上运行恶意代码,更重要的是第三方代码可以看到某一个eval被调用的作用域,会导致一些不同方式 的攻击。
eval 通常会比其他替代方法更慢,因为他必须调用js解释器,其他的结构可被现代js引擎进行优化
eval的替代
eval
function looseJsonParse(obj){
return eval("("+obj+")")}console.log(looseJsonParse("{a:(4-1),b:function(){},c:new Date()}"))
非eval
function looseJsonParse(obj){ return Function('"use strict";return('+obj+')')();}console.log(looseJsonParse("{a:(4-1),b:function(){},c:new Date()}"))