变量提升
js的函数定义有个特点,它会先扫描整个函数体的语句,把所有申明的变量"提升"到函数顶部:
function log(){
var x = 'hello,' + y;
console.log(x); // hello, undefined
var y = 'world'
}
log();
虽然是strict模式,但语句 var x = 'Hello, ' + y并不报错,原因是变量y在稍后声明了。但是console.log 显示hello, undefined, 说明变量y的值为undefined, 这正是因为js引擎自动提升了变量y的声明,但是不会提升变量y的赋值。
对于上述foo()函数, js引擎看到的代码相当于:
function foo() {
var y; // 提升变量y的声明,此时y为undefined
var x = 'Hello, ' + y;
console.log(x);
y = 'world'
}
全局作用域
不在任何函数内定义的变量就具有全局作用域,实际上,javaScript默认有一个全局对象window, 全局作用域的变量实际上被绑定到window的一个属性:
var xz = 'xiaohu'
console.log(xz); // xiaozhu
console.log(window.xz) // xiaozhu
函数定义有两种方式,以变量方式 var foo = function(){} 定义的函数实际上也是一个全局变量,因此,顶层函数的定义也被视为一个全局变量,并绑定到window对象:
javascript 实际上只有一个全局作用域。任何变量(函数也视为变量), 如果没有在当前函数作用域中找到,就会继续往上查找,最后如果再全局作用域中也没找到,则报ReferenceError 错误。
名字空间
全局变量会绑定到window上,不同的js文件如果使用了相同的全局变量,或者定义了相同名字的顶层函数,都会造成命名冲突。
减少冲突的一个方法是把自己的所有变量和函数全部绑定到一个全局变量中,例如:
// 唯一的全局变量xz
var xz = {};
// 其他变量
xz.name = 'xiaozhu';
xz.version = 1.0;
// 其他函数
xz.foo = function(){
return 'foo'
}
局部作用域
由于js的变量作用域实际上是函数内部,我们在for循环等语句块中无法定义具有局部作用域的变量。
function foo(){ for(var i = 0; i < 100; i++){ // } var b = i + 100; // 仍可以引用变量i console.log(b); // 200 } foo()
为了解决块级作用域,es6引入了新的关键字 let, 用 let 替代var 可以声明一个块级作用域的变量:
function foo() { var sum = 0; for(let i=0; i < 100; i++){ sum += i; } // SyntaxError: i += 1; }
解构赋值
'use strict';
// 解构赋值
let [xl,yl,zl] = ['Hello','Javascript','ES6']
console.log(`xl = ${xl} , yl = ${yl} , zl = ${zl}`); // xl = Hello , yl = Javascript , zl = ES6
对数组进行解构赋值时,多个变量要用[...] 括起来。
如果本身有嵌套,则
let [x,[y,z]] = ['Hello', ['Javascript', 'ES6']]; // hello Javascript ES6
如果需要从一个对象中取出若干属性,也可以使用解构赋值,便于快去获取对象的指定属性:
var person = {
name: 'xiaoming',
age: 20,
gender: 'male',
passport: 'G-12345678',
school: 'No.4'
}
var {name,age, school} = person;
console.log(`name: ${name} ,age: ${age}, school: ${school}`); // name: xiaoming ,age: 20, school: No.4
对一个对象进行解构赋值时,同样可以直接对嵌套的属性进行赋值,只要保证对应的层次是一致的:
var person1 = { name: 'xiaoming', age: 20, gender: 'male', passport: 'G-12345678', school: 'No.4', address: { city: 'Beijing', street: 'No.1 Road', zipcode: '10001' } } var {name ,address: {city, zip}} = person1; name; // xiaoming city; // beijing zip; // undefined , 因为属性名是zipcode而不是zip
// 注意: address 不是变量,而是为了让city和zip获得嵌套的address对象的属性
address; //Uncaught ReferenceError: address is not defined
使用结构赋值对对象属性进行赋值时,如果对应的竖向不逊在,变量将被赋值为undefined, 这和引用一个不存在的属性获得undefined是一致的。 如果要使用的变量名和属性名不一致,可以是使用下面的语法获取:
var person = {
name: '小明',
age: 20,
gender: 'male',
passport: 'G-12345678',
school: 'No.4 middle school'
};
// 把passport属性赋值给变量id:
let {name, passport:id} = person;
name; // '小明'
id; // 'G-12345678'
// 注意: passport不是变量,而是为了让变量id获得passport属性:
passport; // Uncaught ReferenceError: passport is not defined
解构赋值还可以使用默认值,这样就避免了不存在的属性返回undefined的问题:
let person2 = {
name: 'xiaozhu',
age: 20,
sex: '女',
// single: false
}
var {name, single= true} = person2;
console.log(name); // xiaozhu
console.log(single); // true
变量声明,再次赋值。正确的写法;(js引擎把{ 开头的语句当作了块处理,于是 = 不再合法)
// 变量已经声明
let i,o;
({i,o} = {i:'xiaozhu', o:'l', name: 'xx'})
console.log(i); // xiaozhu
console.log(o); // l
使用场景
解构赋值现在很多时间大大简化代码, 例如交换两个变量 x 和 y的值, 可以这么写:
var x = 1, y = 2;
[x,y] = [y,x]
快速获取当前页面的域名和路径:
var {hostname: domain, pathname: path} = location;
公司项目:
一般没有返回值或null的时候,需要处理为'--', 这种情况可以返回undefined,或干脆不返回字段
var person3 = {
name1: 'xiaozhu',
age: null,
sex: undefined
}
let {name1, age = '--', sex= '女'} = person3
console.log(name1); // xiaozhu
console.log(age); // null 一般需要处理没值的情况,这种还是会返回null,可以跟后台商量返回undefined,会不返回字段
console.log(sex); // 女
浙公网安备 33010602011771号