es6 常用知识点总结

感谢 阮一峰 老师的技术资料!!

let和const命令

1.let命令

 a. 只在代码块中生效
 b. 拒绝变量提升
 c. 暂时性死区
 d. 不允许重复申明

      在es6新增了 let 命令,用来声明变量。他的用法类似于 var ,但是所声明的代码只在 let 命令所在的代码块内部有效。

	function testlet(){
		let a = 10;
		var b = 1;	
	}
	console.log(a)// ReferenceError: a is not defined. a 只会在上部分代码块中生效 超出即无效
	console.log(b) //  1

      let 非常适合与 for 结合使用

	for(let i =0;i<5;i++){
	        //业务逻辑
	}

拒绝变量提升

    var 命令会发生"变量提升"现象,即变量可以在声明之前使用,脚本并不会报错,只是输出undefind;但是 let 禁止了此操作,强行输出,则报语法错.

	// var 情况
	console.log(foo);	//输出undefinded
	var foo = 2;
	
	//let
	console.log(foo);	// 语法报错  ReferenceError
	let foo = 2;

总结 : 对于var , 脚本开始运行时,变量foo已经存在,但没有值,因此会输出undefinded.
          对于let ,脚本开始运行时,变量 foo并不存在,此时调用 foo,就会报错

暂时性死区
      暂时性死区和拒绝变量提升有着一些关联,同样牵扯到使用 let 申明时,变量不允许在未申明完成之前使用.
      如下:

		var temp = 5;
		if(true){
			console.log(temp);  //ReferenceError
			let temp;
		}

      虽然在最外侧 temp已经被申明,但是一旦某个块代码中含有 let ,并且 let 也申明了此变量,那么这个块代码就被后者绑定,因此在 'let temp’之前输出 temp,会报引用错误----“即便 temp已经声明为全局变量”!

      在 let 面世之前,typeof是100%安全的操作:

	//nodecalertemp 是一个未被声明的变量
	typeof(nodecalertemp);		//undefinded  不报错	

      然而!

	typeof(nodecalertemp);	//ReferenceError  报引用错误!
	let  nodecalertemp;		//let申明变量 nodecalrtemp

          let 带来的“暂时性死区”也意味着, typeof不再100%安全

不允许重复声明
      let不允许在同一个区域内重复声明变量或者形参!

	// 报错
	function func() {
	  let a = 10;
	  var a = 1;
	}
	
	// 报错
	function func() {
	  let a = 10;
	  let a = 1;
	}
	
	function func1(arg) {
  		let arg;
	}
	func1() // 报错
	
	function func2(arg) {
	  {
	    let arg;
	  }
	}
	func2() // 不报错

2.块级作用域

    ❓:为什么需要块级作用域?
    在es5 时代,只存在着全局作用域和函数作用域,却没有块级作用域,这带来许多并不合理的场景。
第一种:内层变量可能会覆盖外层变量

	var tmp = new Date();
	
	function f() {
	  console.log(tmp);
	  if (false) {
	    var tmp = 'hello world';
	  }
	}
	
	f(); // undefined

第二种:用来计数的循环变量泄露为全局变量

	var s = 'hello';
	
	for (var i = 0; i < s.length; i++) {
	  console.log(s[i]);
	}
	
	console.log(i); // 5

当将 var 改换成 let 后,程序就会还原正常状态

3.const命令

const命令声明一个只读常量, const声明的标识符不可以被更改,这意味着, const一旦开始声明,就必须立即初始化,不允许留到以后赋值,否则报错

const实际上保证的,并不是变量的值不得改动,而是变量指向的那个内存地址所保存的数据不得改动。对于简单类型的数据(数值、字符串、布尔值),值就保存在变量指向的那个内存地址,因此等同于常量。但对于复合类型的数据(主要是对象和数组),变量指向的内存地址,保存的只是一个指向实际数据的指针,const只能保证这个指针是固定的(即总是指向另一个固定的地址),至于它指向的数据结构是不是可变的,就完全不能控制了。因此,将一个对象声明为常量必须非常小心

	const arr = [];//使用const 定义 数组 arr
				   //虽然const用于定义常量,但针对于一个对象来说
				   //我们依然可以改变它的属性值 或者 它的索引项
	arr[0] = "hello";
	console.log(arr);		//["hello"]
	
	const obj = {};
	obj.a = "hello";
	console.log(obj);	//{"a":"hello"}

我们可以为 const定义的对象中的属性或索引项执行更改操作,但 不能 直接对该对象更改!

	arr = [];		//报错  此操作是直接对数组根地址进行操作!
	obj = {};		//报错  此操作是直接对对象根地址进行操作!

如果我们真的希望将对象冻结下来,应当使用 Object.freeze 方法。

	const constantsize = (obj) =>{
	  Object.freeze(obj);
	  Object.keys(obj).forEach( (key, i) => {
	    if ( typeof obj[key] === 'object' ) {
	      constantize( obj[key] );
	    }
	  });
	}

解构赋值

变量的解构赋值
基本用法:es6允许按照一定模式,从数组和对象中提取值,对变量进行赋值,这被称为解构。
来看一下 es6之前与之后的变量赋值:

之前:	
	let a = 1;
	let b = 2;
	let c = 3;
之后:
	let [a,b,c] = [1,2,3];

上述代码的本质是“模式匹配”,只需要等号两边的模式相同,左边的变量就会被赋予相应的值。
下面是一些使用嵌套数组进行解构的列子:

	let [foo, [[bar], baz]] = [1, [[2], 3]];
	foo // 1   
	bar // 2
	baz // 3
	
	let [ , , third] = ["foo", "bar", "baz"];
	third // "baz"
	
	let [x, , y] = [1, 2, 3];
	x // 1
	y // 3
	
	let [head, ...tail] = [1, 2, 3, 4];
	head // 1
	tail // [2, 3, 4]
	
	let [x, y, ...z] = ['a'];
	x // "a"
	y // undefined
	z // []

结构不成功,变量的值就等于undefinded;
不完全解构,即等号左边的模式,只匹配一部分的等号右边的数组。这种情况下,解构依然可以成功。但是不能全部成功匹配并改变变量的值

	结构失败:
	let [foo] = [];		// foo: undefinded
	let [bar, foo] = [1]; // bar :1; foo: undefinded 
	 
	不完全解构:
	let [a, [b], d] = [1, [2, 3], 4];
	a // 1
	b // 2
	d // 4

如果等号的右边不是数组(或者严格地说,不是可遍历的结构,参见《Iterator》一章),那么将会报错。

	// 报错
	let [foo] = 1;
	let [foo] = false;
	let [foo] = NaN;
	let [foo] = undefined;
	let [foo] = null;
	let [foo] = {};

2.对象的解构赋值

解构赋值不仅存在于数组,也可使用与对象。
但数组是以索引进行解构,而对象的属性没有次序,变量必须与属性同名,才能取到正确的值。
	let { bar, foo } = { foo: 'aaa', bar: 'bbb' };
	foo // "aaa"
	bar // "bbb"
	
	let { baz } = { foo: 'aaa', bar: 'bbb' };
	baz // undefined

… … …

用途:

(1).交换变量的值		
	let x =1;
	let y =2;
	[x,y] = [y,x]
(2) 从函数中返回多个值
	//返回的是一个数组
	function example(){
		return [1,2,3];
	}
	let [a,b,c] = example();
	//返回的是一个对象
	function example(){
		return {
			foo:1,
			bar:2
		};
	}
	let { foo, bar } = example();
(3).函数参数的定义
	//参数是一组有次序的值
	function f([x,y,z]){ ... }
	f([1,2,3]);
	//参数是一组无次序的值
	function f({x,y,z}){ ... }
	f({z:3,y:2,x:1});
(4).提取JSON数据
	解构赋值对提取JSON对象中的数据,尤其有用。
	let jsondata = {
		id:42,
		status:"ok",
		data:[867,5309]
	}
	let {id,status,data:number} = jsondata;
	console.log(id,status,number);
(5) 函数参数的默认值
	jQuery.ajax = function (url, {
	  async = true,
	  beforeSend = function () {},
	  cache = true,
	  complete = function () {},
	  crossDomain = false,
	  global = true,
	  // ... more config
	} = {}) {
	  // ... do stuff
	};
(6)遍历 Map 结构

任何部署了 Iterator 接口的对象,都可以用for…of循环遍历。Map 结构原生支持 Iterator 接口,配合变量的解构赋值,获取键名和键值就非常方便。

	const map = new Map();
	map.set('first', 'hello');
	map.set('second', 'world');
	
	for (let [key, value] of map) {
	  console.log(key + " is " + value);
	}
	// first is hello
	// second is world
	
//如果只想获取键名,或者只想获取键值,可以写成下面这样。
	// 获取键名
	for (let [key] of map) {
	  // ...
	}
	
	// 获取键值
	for (let [,value] of map) {
	  // ...
	}
(7)输入模块的指定方法
	加载模块时,往往需要指定输入哪些方法。解构赋值使得输入语句非常清晰。
	const { SourceMapConsumer, SourceNode } = require("source-map");

数值的扩展(部分)

1.Number.isFinite(), Number.isNaN()

Number.isFinite()用来检查一个数值是否为有限的(finite),即不是Infinity。
Number.isNaN()用来检查一个值是否为NaN。

	//注意 : 如果参数类型不是数值,Number.isFinite()一律返回false。
	Number.isFinite(15); // true
	Number.isFinite(0.8); // true
	Number.isFinite(NaN); // false
	Number.isFinite(Infinity); // false
	Number.isFinite(-Infinity); // false
	Number.isFinite('foo'); // false
	Number.isFinite('15'); // false
	Number.isFinite(true); // false	
	//注意 : 如果参数类型不是NaN,Number.isNaN一律返回false
	Number.isNaN(NaN) // true
	Number.isNaN(15) // false
	Number.isNaN('15') // false
	Number.isNaN(true) // false
	Number.isNaN(9/NaN) // true
	Number.isNaN('true' / 0) // true
	Number.isNaN('true' / 'true') // true

(2).Number.parseInt(), Number.parseFloat()

ES6 将全局方法parseInt()和parseFloat(),移植到Number对象上面,行为完全保持不变

	// ES5的写法
	parseInt('12.34') // 12
	parseFloat('123.45#') // 123.45
	
	// ES6的写法
	Number.parseInt('12.34') // 12
	Number.parseFloat('123.45#') // 123.45

这样做的目的,是逐步减少全局性方法,使得语言逐步模块化。

	Number.parseInt === parseInt // true
	Number.parseFloat === parseFloat // true

(3). Math.trunc()
Math.trunc方法用于去除一个数的小数部分,返回整数部分。

	Math.trunc(4.1) // 4
	Math.trunc(4.9) // 4
	Math.trunc(-4.1) // -4
	Math.trunc(-4.9) // -4
	Math.trunc(-0.1234) // -0
//	如果传入的参数非数值,那么Math.trunc()内部会显示用Number方法将其转换为数值,再运算
	Math.trunc('123.456') // 123
	Math.trunc(true) //1
	Math.trunc(false) // 0
	Math.trunc(null) // 0

函数的扩展

设置形参

在es6之前,如果想为函数的形参设定默认值,需要使用变通的方法:

	function log(x,y){
		y = y || "world";	//设置形参的默认值
		console.log(x,y);
	}
	log("hello");	//hello world 
	log("hello","china")	//Hello China
	log("hello",'')		//hello world

es6写法

	function log(x,y="world"){
		//....
	}
	function  Point(x=0,y=2,z=3){
		console.log(x,y,z)
	}
	Point();  //0 2 3	

箭头函数

箭头函数的作用域与外界是保持一致的,其本身并没有产生作用域
	var f = v =>v;
	//	等价于
	var f = function(v){
		return v;
	};

如果箭头函数不需要参数或需要多个参数,就使用一个圆括号代表参数部分。

	var f = () => 5;
	// 等同于
	var f = function () { return 5 };
	
	var sum = (num1, num2) => num1 + num2;
	// 等同于
	var sum = function(num1, num2) {
	  return num1 + num2;
	};

如果箭头函数的代码块部分多于一条语句,就需要用大括号将他们括起来,必须在对象外面加上大括号,否则会报错。

	//报错
	let getTemp = (item1,item2)=>{id:item1;name:item2}
	
	//不报
	let getTemp = (item1,item2)=>({id:item1;name:item2})

数组扩展

  • 扩展运算符

1.扩展运算符
扩展运算符(spread)是三个点(…). 好比rest参数的逆运算,将一个数组转为用逗号分隔的参数序列。

	console.log(1,2,[3,4,5],6)	// 1,2,[3,4,5],6
	console.log(1,2,...[3,4,5],6)	// 1,2,3,4,5,6
	[...document.querySelectorAll('div')]  // [<div>, <div>, <div>]

该运算符主要用于函数调用

	function push(array,...items){
		array.push(...items)
	}
	function add(x,y){
		return x + y;
	}
	const numbers = [4,40]
	add(...numbers)	//44

上述代码中,array.push(…items)和add(…numbers)这两行,都是函数的调用,他们的使用了扩展运算符。该运算符将一个数组,变为参数序列。

扩展运算符与正常的函数参数可以结合使用,非常灵活

	function fun(v,w,x,y,z){}
	const args = [0,1];
	fun(-1,...args,2,...[3]);
	
	//扩展运算符后面还可以放置表达式。
	const arr = [
		...(x>0?['a']:[]),
		'b'
	]
	//注意,只有函数调用时,扩展运算符才可以放在圆括号中,否则会报错
	(...[1,2])	//报错
	console.log((...[1,2]))	//报错
	
	console.log(...[1,2])	//1 2
	上述三种情况,前两种都会报错,因为扩展运算符所在的括号不是函数调用

未完待更


再次感谢 阮一峰 老师的学习资料!

本文记录了一些es6的零碎知识点,由于每一个点都比较分散,因此做了一个汇总。
才疏学浅,不足之处还请批评指正!

startwith 与 endwith

除了 “模板字符串” 伴随着es6的到来,这两个api也一并来到。
先说说他们的用法:

	//startwith
	let mystr = "Today is Thuseday";
	console.log(mystr.startwith("Today "))		//true
	console.log(mystr.startwith("today "))		//false
	console.log(mystr.endwith("Thuseday"))		//true
	console.log(mystr.endwith("thuseday"))		//false
显而易见,这两个函数有点正则匹配的意思,看起来有点鸡肋。
但实际情况中有时候是个好帮手。
EG:我们需要判断某个网址的协议时候:
	let myweb = "http://www.mycom.com"
	if(myweb.startsWith('http')){
    	console.log('this is http');
	}else if(myweb.startsWith('https')){
	    console.log('this is https');
	}else if(myweb.startsWith('ws')){
	    console.log('this is websocket');
	}  
在我们需要判断文件后缀的时候	
		const filename = "upload.jpg";
		if(filename.endsWith('.jpg')){
		    console.log('this is jpg file');
		}else if(filename.endsWith('.png')){
		    console.log('this is png file');
		}else if(filename.endsWith('.webp')){
		    console.log('this is webp file');
		}   //this is jpg file

待更

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值