let和const命令
let命令 let命令用于声明变量,所声明的变量只在let命令所在的代码块有效
特性
不存在变量提升 var声明变量会发生变量提升,所以在声明变量之前,变量的值为undefined,但是let命令声明的变量只能在声明后使用,否则报错
暂时性死区 只要块级作用域内存在let命令,它所声明的变量就“绑定”这个区域,不再受外部的影响。
“暂时性死区”也意味着typeof不再是一个百分之百安全的操作,在变量声明之前使用会报错
var tmp = 'abs';
if(true){
tmp = 'wer';
let tmp;
}
不允许重复声明 let不允许在相同作用域内,重复声明同一个变量。
function func() {
let a = 10;
var a = 1;
}
function func() {
let a = 10;
let a = 1;
}
const命令 const用于声明一个只读的常量。一旦声明,常量的值就不能改变。 所以一旦声明变量,就必须立即初始化,不能留到以后赋值。
const和let类似,都有只在作用域块中起作用,暂时性死区,不可重复声明的特性
const本质 const实质上是保证了变量指向的那个内存地址所保存的数据不得改动。
对于简单数据类型变量 值就保存在变量指向的那个内存地址,因此等同于常量 对于复合类型变量 变量指向的内存地址,const保存的只是一个指向实际数据的指针,所以变量指向的数据结构是不是可变的,就完全不能控制了。
可以使用Object.freeze方法将变量冻结,即不能添加新的属性…
块级作用域
ES6 的块级作用域必须有大括号
块级作用域的好处
- 解决内层变量覆盖外层变量的问题
- 防止计数的循环变量泄露为全局变量
- 可以替代匿名立即执行函数
块级作用域与函数声明
ES6 允许在块级作用域之中声明函数,块级作用域之中,函数声明语句的行为类似于let,在块级作用域之外不可引用。
行为方式
为了使老代码不受块级作用域声明函数处理规则的影响,ES6规定浏览器的实现可以遵循以下的行为方式(只对 ES6 的浏览器实现有效)
- 允许在块级作用域内声明函数。
- 函数声明类似于var,即会提升到全局作用域或函数作用域的头部。
- 同时,函数声明还会提升到所在的块级作用域的头部。
例如:
function f() {
console.log("I'm outside!");
}
(function(){
if(false){
function f(){
console.log("I'm inside!");
}
}
f();
})()
扩展运算符
ECMAScript 6 新增了扩展操作符,使用它可以非常简洁地操作和组合集合数据。 扩展运算符( spread )是三个点 " … " 可以理解为将数组切分成一个个参数
扩展参数
在函数传参时,可以分别传入数组的值
let values = [1, 2, 3, 4];
function getSum() {
let sum = 0;
for (let i = 0; i < arguments.length; ++i) {
sum += arguments[i];
}
return sum;
}
console.log(getSum(...values));
应用
合并数组
var arr1 = ['a','b'];
var arr2 = [1,2,3,4];
var arr3 = ['d','e'];
var arr = [...arr1 , ...arr2, ...arr3];
console.log(arr+'数组');
与解构赋值结合
注意:扩展运算符只能放在参数最后一位,否则会报错
const [first,...rest] = [1,2,3,4,5];
console.log(first);
console.log(rest);
const [a,...b] = ['foo'];
console.log(a);
console.log(b);
const [...c,d] = [1,2,3,4];
const [e,...f,g] = [1,2,3,4,5];
console.log(c);
console.log(f);
字符串转换成数组
console.log([..."hello"]);
实现Iterator接口
任何 Iterator 接口的对象,都可以用扩展运算符转为真正的数组
var nodeList = document.querySelectorAll('div');
var divArr = [...nodeList];
console.log(divArr);
只要有Iterator接口的对象,都可以使用扩展运算符
箭头函数
箭头函数比函数表达式更简洁,并且没有自己的this,super,arguements,new.target,没有 prototype 属性 箭头函数适用于使用匿名函数的地方,且没有构造函数
语法
如果只有一个参数,那也可以不用括号。 不使用大括号,那么箭头后面就只能有一行代码,省略大括号会隐式返回这行代码的值 无参数,函数写成一对圆括号
(param1, param2, …, paramN) => { statements }
let b = a => {
return a*2;
}
console.log(b(4));
let c = (a,b) => a+b;
console.log(c(9,15));
let a = () => {
console.log(111);
}
a();
加括号,返回对象字面量表示 支持剩余参数和默认参数 支持参数列表解构
var param = ({foo: 'bar'});
console.log(param);
var List = ([a,b] = [1,2],{x:c}= {x:a+b}) => a+b+c;
console.log(List());
应用
箭头函数可以使函数更简洁,且不绑定this
简化函数
var ele = ['adoy','cin','grim','yeel','jo'];
var list = ele.map(function(e){
return e.length;
})
console.log(list);
var arrowlist = ele.map(e => e.length);
console.log(arrowlist);
箭头函数不会创建自己的this,它只会从自己的作用域链的上一层继承this
function Person(){
this.age = 0;
setInterval(() => {
this.age ++;
console.log(this.age);
}, 1000);
}
var p = new Person();
console.log(p.age);
p()
注:在严格模式下,与this相关的规则都会无效 通过 call() 或 apply() 方法调用一个函数时,只能传递参数(不能绑定this—译者注),他们的第一个参数会被忽略。
其它:
箭头函数在参数和箭头之间不能换行。 箭头函数不能用作构造器,和 new一起用会抛出错误 箭头函数没有prototype属性。
函数传参
在形参少的的情况下,可以通过在形参中设置默认参数的方式来处理,更加简洁易懂。在形参多的情况下,可以使用新的不定参数符号 … 来代表多出来的参数
默认参数 只有在未传递参数,或者参数为 undefined 时,才会使用默认参数,null 值被认为是有效的值传递。 注意:显式传入undefined(虽然不是null或其他falsy值),形参的值还是默认值。
在函数被调用时,参数默认值会被解析
默认值可以是被定义的函数,变量,该函数前面的形参
function foo(a,b=a,c = a +b){
console.log(a,b,c)
}
foo(4);
function foo(funcResult = bar()) {
console.log(funcResult)
}
let num = 0;
function bar() {
num += 1;
return num;
}
foo();
foo();
剩余参数 剩余参数允许我们将一个不定数量的参数表示为一个数组。
剩余参数特点
- 剩余参数只包含那些没有对应形参的实参
- 剩余参数是真正的 Array实例
- arguments对象还有一些附加的属性 (如callee属性)
function sum(a,b, ...c){
console.log(c);
}
sum(1,2,3,4,5);
变量的解构赋值
ES6 允许按照一定模式,从数组和对象中提取值,对变量进行赋值,这被称为解构
数组的解构赋值 可以从数组中提取值,按照对应位置,对变量赋值。
“模式匹配”:从数组中提取值,按照对应位置,对变量赋值。 如果解构不成功,foo的值都会等于undefined
默认赋值
解构赋值允许指定默认值。 当一个数组成员严格等于(===)undefined,默认值才会生效。
let [foo = true] = [];
console.log(foo);
let [x, y = 'b'] = ['a'];
console.log(x);
console.log(y);
let [x, y = 'b'] = ['a', undefined];
console.log(x);
console.log(y);
注意:
- 默认值可以引用解构赋值的其他变量,但该变量必须已经声明。
- 如果默认值是一个表达式,只有在用到的时候,才会求值。
对象解构赋值
与数组不同,对象的属性没有次序,变量必须与属性同名,才能取到正确的值。 解构也可以用于嵌套结构的对象
let { log, sin, cos } = Math;
console.log(log);
console.log(sin);
let obj = {
p: [
'Hello',
{ y: 'World' }
]
};
let { p: [x, { y }] } = obj;
console.log(x);
console.log(y);
默认赋值
和数组类似,默认值生效的条件是对象的属性值严格等于undefined
var { message: msg = 'Something went wrong' } = {};
console.log(msg);
var {x: y = 3} = {};
console.log(y)
注意
- 如果要将一个已经声明的变量用于解构赋值,保险起见加上圆括号
let x;
{x} = {x: 1};
let x;
({x} = {x: 1});
JavaScript 引擎会将{x}理解成一个代码块,从而发生语法错误。
- 由于数组本质是特殊的对象,因此可以对数组进行对象属性的解构
let arr = [1, 2, 3];
let {0 : first, [arr.length - 1] : last} = arr;
console.log(first);
console.log(last);
字符串的解构赋值 此时字符串被转换成了一个类似数组的对象
let [a, b, c, d, e] = 'hello';
console.log(a);
console.log(b);
类似数组的对象都有一个length属性,因此还可以对这个属性解构赋值
let {length:len} = 'hello';
console.log(len);
数值和布尔值的解构赋值
解构赋值时,如果等号右边是数值和布尔值,则会先转为对象 undefined和null无法转为对象,对它们进行解构赋值会报错。
函数参数的解构赋值 大同小异
let {toString: s} = true;
console.log(s);
console.log(s === Boolean.prototype.toString);
function add([x, y]){
return x + y;
}
console.log( add([1, 2]));
function move({x = 0, y = 0} = {}) {
return [x, y];
}
console.log(move({x: 3, y: 8}));
console.log( move({x: 3}));
console.log(move({}));
数组新特性
Array.of() 当数组构造器创建数组只传入一个参数时,可以传入一个
let normalArry = new Array(1,2);
console.log(normalArry);
let strangeArray = new Array(4);
console.log(strangeArray[0]);
let arrN = Array.of(4);
console.log(arrN[0]);
Array.from() 把数组对象转换成真的数组(必需符合数组特性)
let arrLike = {
0: 1,
1: 2,
length:2
}
console.log(arrLike);
find(),findindex()方法,fill()方法
详细
字符串新特性
模板字符串 模板字符串(template string)是增强版的字符串,用反引号(`)标识。它可以当作普通字符串使用,也可以用来定义多行字符串,或者在字符串中嵌入变量
var name = 'Jerry';
var age = '20';
console.log(`He is ${name},and he is ${age} years old`);
let str = `one line,
second line`
console.log(str);
let a = 1;
let b = 20;
var obj = {'name':'Joe'};
function fn(){
return 'loves the world';
}
var strA = `the boy,${obj.name} is ${a+b} years old, he ${fn()}`
console.log(strA);
标签模板 标签模板其实不是模板,而是函数调用的一种特殊形式。“标签”指的就是函数,紧跟在后面的模板字符串就是它的参数。 如果模板字符里面有变量,会将模板字符串先处理成多个参数,再调用函数。
第一个参数是一个数组,该数组的成员是模板字符串中那些没有变量替换的部分 其他参数,都是模板字符串各个变量被替换后的值。
示例:
var A = 5;
var B = 10;
tag `Hello ${A+B} world ${A*B}`;
function tag(data){
console.log(arguments);
}
"标签模板”的一个重要应用,就是过滤HTML字符串,防止用户输入恶意内容。
var sender = '123@Joe';
var message = SaferHTML `<p>${sender} has sent you a message </p>`;
function SaferHTML(templateData){
var msg = templateData[0];
for(var i=1;i<arguments.length;i++){
var arg = String(arguments[i]);
msg += arg.replace(/&/g,"&")
.replace(/</,"<")
.replace(/>/,">");
msg += templateData[i];
}
return msg;
}
console.log(message);
repeat函数 将目标函数重复n次,返回一个新的字符串
includes函数 判断字符串是否含有指定的字符串,true/false(含有/不含有)
startsWith函数 判断指定的子字符串是否出现在目标的开头位置
endsWith函数 判断指定的子字符串是否出现在目标的尾部位置 它是唯一一个内置的模板字符串标签函数
String.raw()函数 用来获取一个模板字符串的原始字符串 例如占位符会被处理为它所代表的其他字符串,转义字符(例如 \n)会原样输出
var name1 = 'abc';
var name2 = name1.repeat(3);
console.log(name2);
console.log(name1.includes('a'));
console.log(name1.includes('H'));
console.log(name1.startsWith('a'));
console.log(name1.startsWith('A'));
console.log(name1.endsWith('d'));
console.log(name1.endsWith('c'));
console.log(String.raw`'hello world\n`);
关于模块化开发和面向对象 @##@
参考资料:
ES6 入门教程
箭头函数
ES6:模板字符串
详解JavaScript ES6中的模板字符串
let和const命令
|