var 声明的变量会挂载在 window 对象上(会污染),而 let 和 const 声明的变量不会
var a = '我是a';
let b = '我是b';
let c = '我是c';
console.log(window.a); // 打印结果:我是a
console.log(window.b); // 打印结果:undefined
console.log(window.); // 打印结果:undefined
var 声明的变量存在变量提升,let 和 const 声明的变量不存在变量提升,要先声明再使用
console.log(a); // 打印结果:undefined ==> a已经声明但没有赋值
var a = '我是a';
console.log(b); // 报错:Uncaught ReferenceError: Cannot access 'b' before initialization ==> 找不到b这个变量
let b = '我是b';
console.log(c); // 报错:Uncaught ReferenceError: Cannot access 'c' before initialization ==> 找不到c这个变量
const c = '我是c';
var 声明不存在块级作用域,let 和 const 声明存在块级作用域
{
var a = '我是a';
let b = '我是b';
const c = '我是c';
}
console.log(a); // 我是a
console.log(b); // 报错:Uncaught ReferenceError: b is not defined ==> 找不到b这个变量
console.log(c); // 报错:Uncaught ReferenceError: c is not defined ==> 找不到c这个变量
同一作用域下,var 可以重复声明变量,let 和 const 不能重复声明变量
var a = '我是a';
var a = 'qianguyihao';
console.log(a); // 打印结果:qianguyihao
let b = '我是b';
let b = 'qianguyihao';
console.log(b); //报错:Uncaught SyntaxError: Identifier 'b' has already been declared ==> 变量 b 已经被声明了
const c = '我是c';
const c = 'qianguyihao';
console.log(c); //报错:Uncaught SyntaxError: Identifier 'c' has already been declared ==> 变量 c 已经被声明了
let 和 const 存在暂时性死区(声明语句必须放在使用之前)
const name = 'qianguyihao';
function foo() {
console.log(name);
const name = 'hello';
}
foo(); // 执行函数后,控制台报错:Uncaught ReferenceError: Cannot access 'name' before initialization
Symbol 是一种新的原始数据类型,每一个 Symbol 值都是不相等的,主要用作对象属性名(作为标识符),可以保证不会与其他属性名产生冲突,Symbol 值通过 Symbol 函数生成,let s = Symbol();。
// Symbol函数可以接受一个字符串作为参数,表示对 Symbol 实例的描述,但不代表symbol的值,相同参数的Symbol函数的返回值是不相等的。
let s1 = Symbol('foo');
let s2 = Symbol('foo');
s1 === s2 // false
// Symbol 值可以显式转为字符串,也可以转为布尔值,但是不能转为数值。
let sym = Symbol('My symbol');
String(sym) // 'Symbol(My symbol)'
Boolean(sym) // true
Number(sym) // TypeError
// Symbol 值作为对象属性名时,不能用点运算符,也不需要加引号
let mySymbol = Symbol();
let a = {
[mySymbol]: 'Hello!'
};
a[mySymbol] // "Hello!"
Symbol 作为属性名,遍历对象的时候,该属性不会出现在for...in、for...of循环中,也不会被Object.keys()、Object.getOwnPropertyNames()、JSON.stringify()返回。但是Object.getOwnPropertySymbols()方法,可以获取指定对象的所有 Symbol 属性名,Reflect.ownKeys()方法可以返回所有类型的键名,包括常规键名和 Symbol 键名。
Symbol.for() 接受一个字符串作为参数,然后搜索有没有以该参数作为名称的 Symbol 值。如果有,就返回这个 Symbol 值,否则就新建一个以该字符串为名称的 Symbol 值,并将其注册到全局。symbol() 不会搜索是否存在给定key值的symbol,直接创建新的symbol值。
let s1 = Symbol.for('foo');
let s2 = Symbol.for('foo');
s1 === s2 // true
Symbol.keyFor()方法返回一个已登记的 Symbol 类型值的key,注意通过symbol()生成的不登记,因此不适用。
let s1 = Symbol.for('foo');
Symbol.keyFor(s1) // 'foo'
let s2 = Symbol("foo");
Symbol.keyFor(s2) // undefined
2.3 ES6 Set/Map
2.2.1 Set
Set 类似于数组,但是成员的值都是唯一的,没有重复的值。
常见应用:
数组去重
存储用户搜索记录不需要重复数据,可以用 Set 来存储用户的搜索记录
......
const set = new Set([1, 2, 3, 4, 4]);
[...set] // [1,2,3,4]
// 数组去重
[...new Set(array)];
Array.from(new Set(array));
// 字符串去重
[...new Set('ababbc')].join('');
// 并集,交集,差集
let a = new Set([1, 2, 3]);
let b = new Set([4, 3, 2]);
// 并集
let union = new Set([...a, ...b]);
// 交集
let intersect = new Set([...a].filter(x => b.has(x)));
// 差集
let difference = new Set([...a].filter(x => !b.has(x)));
// 遍历改变 set 结构
let set = new Set([1, 2, 3]);
set = new Set([...set].map(val => val * 2));
set = new Set(Array.from(set, val => val * 2));
var a = 5;
alert(a++); // 5
alert(a); // 6
var b = 6;
alert(++b); // 7
var c = 1;
alert(++c + c++); // 4:2+2
var d = 1;
alert(++d + ++d); // 5:2+3
var e = 1;
alert(e++ + ++e); // 4:1+3
var f = 1;
alert(f++ + f++); // 3:1+2
outerloop: // This is the label name
for (var i = 0; i< 5; i++){
console.log("Outerloop: " + i + "<br />");
innerloop:
for (var j = 0; j < 5; j++) {
if (j > 3 ) break ; // Quit the innermost loop
if (i == 2) break innerloop; // Do the same thing
if (i == 4) break outerloop; // Quit the outer loop
console.log("Innerloop: " + j + " <br />");
}
}
5. 函数
5.1 函数声明
函数的作用域在函数定义时,就已经确定了,查找时采用的是就近原则。
// 1、function 命令
function print(s) {
console.log(s);
}
// 2、函数表达式
var print = function(s) {
console.log(s);
};
// 3、函数对象 - 几乎不使用
// Function构造函数接受任意数量的参数,但只有最后一个参数会被当做函数体,如果只有一个参数,该参数就是函数体。
var add = new Function(
'x',
'y',
'return x + y'
);
for...in循环遍历对象自身的和继承的可枚举属性(不含 Symbol 属性) - 由于引入继承,不建议使用
Object.keys返回一个数组,包括对象自身的(不含继承的)所有可枚举属性(不含 Symbol 属性)的键名。
Object.getOwnPropertyNames返回一个数组,包含对象自身的所有属性(不含 Symbol 属性,但是包括不可枚举属性)的键名。
Object.getOwnPropertySymbols返回一个数组,包含对象自身的所有 Symbol 属性的键名。
6.3 自定义对象
// 方法一:自变量声明
// {}进行构造,里面的属性和方法采用键值对的方法
var objet = {};
var objet = {name:'shen', age:12, hanshu:function(){}};
// 方法二:实例化声明
var object = new Object();
object.name = 'shen';
// 方法三:自定义构造函数
function Fun(firstname,lastname){
this.firstname=firstname;
this.lastname=lastname;
function changeName(name){
this.lastname=name;
}
}
var f = new Fun("Shen","Wei");
// 数组
const arr = ['red', 'green', 'blue'];
for(let v of arr) {
console.log(v); // red green blue
}
// 注意原本的for...in循环只能获得键名,不能获得键值
for (let a in arr) {
console.log(a); // 0 1 2
}
// Set
const engines = new Set(["Gecko", "Trident", "Webkit", "Webkit"]);
for (let e of engines) {
console.log(e); // // Gecko Trident Webkit
}
// Map - 注意遍历得到的是一个数组
const es6 = new Map([["edition", 6], ["committee", "TC39"], ["standard", "ECMA-262"]]);
for (let [name, value] of es6) {
console.log(name + ": " + value); // edition: 6 committee: TC39 standard: ECMA-262
}
// 字符串
let str = "hello";
for (let s of str) {
console.log(s); // h e l l o
}
// DOM NodeList对象
let paras = document.querySelectorAll("p");
for (let p of paras) {
p.classList.add("test");
}
// arguments对象
function printArgs() {
for (let x of arguments) {
console.log(x); // 'a' 'b'
}
}
printArgs('a', 'b');
// 普通对象for...of循环会报错,使用Object.keys方法将对象的键名生成一个数组,然后遍历这个数组
let es6 = {
edition: 6,
committee: "TC39",
standard: "ECMA-262"
};
for (let key of Object.keys(es6)) {
console.log(key + ': ' + es6[key]);
}