前端学习笔记 --ES6新特性

前言

这篇博客是我在b站进行学习es6课程时的笔记总结与补充。
此处贴出up主的教程视频地址:深入解读ES6系列(全18讲)

1、ES6学习之路

1.1 ES6新特性

1. 变量
2. 函数
3. 数组
4. 字符串
5. 面向对象
6. Promise
7. generator	//类似于Promise
8. 模块化

1.2 变量

1.2.1 let、var、const和作用域

知识点:
1. ES6之前的JS只有函数作用域和全局作用域,ES6引入了let后新增了块级作用域,还引入const。
2. 所有window对象内置属性都拥有全局作用域。

var
1. 可以重复声明
2. 无法限制修改
3. 函数作用域(在函数体内可访问)

let
1. 不能重复声明
2. 变量(可以修改)
3. 块级作用域(在大括号{}内可访问)

<!--注意:var和let都存在变量提升,但是let在变量声明和初始化前的区间存在暂时性死区,无法调用-->

const
1. 不能重复声明
2. 常量(不能修改)
3. 块级作用域

[块级作用域]
说明:因为var是全局变量,js是单线程运行,而for循环是同步执行,onclick()是异步执行,所以for循环执行完成后,全局变量i为3,再执行onclick()就得到了3
var btn=document.getElementsByTagName('input');	//有三个input组件
for(var i=0;i<btn.length;i++){
	btn[i].onclick=function(){
		alert(i);	//一直弹出3,因为var没有块级作用域
	};
}

解决方法:
1.用函数封装一层(用立即执行函数),传递i
var btn=document.getElementsByTagName('input');	//有三个input组件
for(var i=0;i<btn.length;i++){
	(function (i){
		btn[i].onclick=function(){
			alert(i);	//分别弹出1,2,3
		};
	})(i);
}

2.把var改成let声明
var btn=document.getElementsByTagName('input');	//有三个input组件
for(let i=0;i<btn.length;i++){
	btn[i].onclick=function(){
		alert(i);	//弹出0,1,2
	};h
}

1.2.2 立即执行函数(IIFE / Immediately Invoked Function Expression)

此处引用自stpice的博客

知识点:
function foo(){}	//这是定义(Declaration),让解释器知道其存在,并不会立即执行
foo();	//这是语句,(Statement),解释器遇到它会执行

IIFE调用方式:
(function foo(){}());
(function foo(){})();
!function foo() {}();
+function foo() {}();
-function foo() {}();
~function foo() {}();

在需要表达式的场景下,就不需要用括号了:
void function(){}();
var foo = function(){}(); 
true && function () {}();
0, function () {}();

$(function(){})的用法:
$(document).ready(function(){
	console.log("ready");
});
等同于
$(function(){
	console.log("ready");
});

1.3 箭头函数

1.3.1 箭头函数基本用法

知识点:
箭头函数 ()=>{} 等价于 function(){}
当只有一个参数的时候,可以省略(),如 (res)=>{} 等价 res=>{}
当只有一个返回值时,可以省略{},如 ()=>{return 0;} 等价 ()=>return 0;

1.3.2 调用位置和调用栈

此处引用自博主越努力越幸运_952c

知识点:
调用栈:调用栈主要是存放返回地址
调用位置:当前函数在代码中被调用的位置

function baz(){
	//当前调用栈是baz
	//当前调用位置是全局作用域
	bar();	//<--bar的调用位置
}

function bar(){
	//当前调用栈是baz->bar
	//当前调用位置在baz中
	foo();	//<--foo的调用位置
}

function foo(){
	//当前调用栈是baz->bar->foo
	//当前调用位置是在bar中
}

baz();	//<--baz的调用位置

1.3.3 ES5和ES6的this指向(箭头函数)

此处引用自博主蔡香满屋

ES5:
函数的调用位置决定了this的绑定
全局环境下,this始终指向全局对象(window)
普通函数内部的this分为两种情况:严格模式和非严格模式

非严格模式:this默认指向全局对象window
function f2(){
	return this;
}
f2()===window;	//true

严格模式:this为undefined
function f2(){
	"use strict";	//使用严格模式
	return this;
}
f2()===undefined;	//true

ES6:
箭头函数的定义位置决定了this的绑定
所以call()/apply()/bind()方法对于箭头函数来说只是传入参数,不会影响this值

var Animal=function(){
	this.name="Animal";	//下面那一行的this指向的时这外面的this
	this.speak=(name,words)=>{
		console.log(this.name+'is saying'+words+'.');
	}
}

var cat=new Animal();
cat.speak("cat","miao~");	//Animal is saying miao~

1.4 函数的参数扩展

知识点:
...可以用于展开/收集参数

[收集参数]
function show(a,b,...args){	//...args必须是最后一个形参
	alert(a);
	alert(b);
	alert(args);	//输出3,4,5,6
}
show(1,2,3,4,5,6);

[展开参数]
let arr1=[1,2,3];
let arr2=[4,5,6];
let arr=[...arr1,...arr2];	//等价于arr=[1,2,3,4,5,6]

1.5 解构赋值

知识点:
1. 左右两边结构必须一样
2. 右边的格式必须是合法的
3. 声明和赋值不能分开

let [a,b,c]=[1,2,3];	//把1,2,3分别赋值给a,b,c
let [{a,b,c},[d,e,f],g,e]=[{a:1,b:2,c:3},[1,2,3],"string",1];
let [json,arr,s,i]=[{a:1,b:2,c:3},[1,2,3],"string",1];	//注意与上式的区别

1.6 数组

1.6.1 map(映射)

知识点:
map映射可以实现两个数组间的对应映射,比如下面a[],b[]两个数组间的元素一一对应:
a=[10,60,88,50,30];
b=['不及格','及格','及格','不及格','及格']

let score=[19,85,99,25,90];
let result=score.map(item=>item>=60?'及格':'不及格');
alert(score);	//分别输出19,85,99,25,90
alert(result);	//分别输出'不及格','及格','及格','不及格','及格'

1.6.2 reduce(汇总)

知识点:
reduce将数组[1,2,3]各个元素相加得到总数5

<!--将数组元素相加求和-->
let arr=[12,69,180,8763];
let result=arr.reduce(function(tmp,item,index){	//tmp代表两数相加产生的中间数,item表示当前第二个加数,index为索引(第一次运算得到中间数后为2)
	return tmp+item;
});

<!--求数组元素相加后的平均数-->
let arr=[12,69,180,8763];
let result=arr.reduce(function(tmp,item,index){
	if(index!=arr.length-1){	//不是最后一次运算
		return tmp+item;
	}else{
		return (tmp+item)/arr.length;
	}
});
alert(result);

1.6.3 filter(过滤器)

知识点:
filter将返回true或false来实现过滤

<!--过滤得到能被3整除的数-->
let arr=[12,5,8,99,27,36,75];
let result=arr.filter(item=>item%3==0);
alert(result);

1.6.4 forEach(循环迭代)

知识点:
forEach迭代输出数组的元素

let arr=[12,5,8,9];
arr.forEach((item,index)=>{	//index可加可不加
	alert(index,": ",item);
});

1.6.5 map和forEach的异同点

相同点:
都是遍历数组的每一项
执行匿名函数时都支持传入三个参数:item,index,arr	//item为当前项,index为索引,arr为原数组

不同点:
map会分配内存空间存储新数组并返回,forEach不会返回
forEach对数据的操作会改变原数组,map不会改变原数组,而是会返回一个新数组

1.7 字符串

1.7.1 startsWith和endsWith

知识点:
startsWith和endsWith通过判断字符串开头或结尾是否含有特定字符串来返回true和false

1.7.2 字符串模板:` 搭配 ${} 连接字符串

知识点:
可以直接把东西塞到字符串里面	$(东西)
可以折行书写代码

let title='标题';
let content='内容';

旧的写法:
let str='<div>\	//折行需要加'\'
	<h1>'+title+'</h1>\
	<p>'+content+'</p>\
</div>';

新的写法:
let str=`<div>	//使用反引号包裹
	<h1>$(title)</h1>	//不需要加'+'连接符
	<p>$(content)</p>
</div>`;

1.8 面向对象

1.8.1 老版本JS

缺点:
面向对象概念模糊,类和函数的不分家
方法需要在外面用prototype定义

<!--构造一个类和继承-->
function User(name,pass){
	this.name=name;
	this.pass=pass;
}

User.prototype.showName=function(){
	alert(this.name);
}

User.prototype.showPass=function(){
	alert(this.pass);
}

var u1=new User('zhang','123');

u1.showName();
u1.showPass();

//---------------继承User----------------

function VipUser(name,pass,level){
	User.call(this,name,pass);	//call实现继承
	this.level=level;
}

VipUser.prototype=new User();
VipUser.prototype.constructor=VipUser;	//个人猜测这里是加入User后,重新构造VipUser

VipUser.prototype.showLevel=function(){
	alert(this.level);
}

var v1=new VipUser('zhang','123',3);

v1.showName();
v1.showPass();
v1.showLevel();

1.8.2 ES6

优点:
强化面向对象概念,区分函数和类
class关键字、构造器和类分开了
class里面直接加方法

<!--构造一个类和继承-->
class User{
	constructor(name,pass){	//构造器
		this.name=name;
		this.pass=pass;
	}

	showName(){	//方法
		alert(this.name);
	}

	showPass(){
		alert(this.pass);
	}
}

var u1=new User('zhang','123');

u1.showName();
u1.showPass();

//---------------继承User----------------

class VipUser extends User{
	constructor(name,pass,level){
		super(name,pass);	//super关键字继承父类
		this.level=level;
	}

	showLevel(){	//直接在class里面加方法
		alert(this.level);
	}
}

var v1=new VipUser('zhang','123',3);

v1.showName();
v1.showPass();
v1.showLevel();

1.8.3 面向对象应用--React

React特点:
1. 强调组件化,一个组件即一个class
2. 强依赖与JSX(JSX==babel==browser.js)

(这里先简单介绍一下react框架,后续将会详细学习)

1.9 JSON

1.9.1 JSON和字符串之间的互换

知识点:
1. JSON转换成字符串:JSON.stringfy()
2. 字符串转换成JSON:JSON.parse()
3. 把字符串作为URI组件进行编码:encodeURIComponent()
4. JSON的标准写法:
 · 所有key和字符串类型的value都要用双引号包裹
 · 最外层用单引号包裹

eg:let str='{"a":12,"b":"hello"}';

1.9.2 JSON简写

知识点:
1. 名字一样可以简写(key和value一样)
2. 方法可以简写

eg:
<!--名字简写-->
let a=12;
let b=5;
let json={a:a,b:b};	//可简写为:let json={a,b};

<!--方法简写-->
let json={
	a:12,
	show:function(){	//可简写为:show(){alert(this.a);}
		alert(this.a);
	}
};

1.10 Promise

1.10.1 Promise简介与基本用法

知识点:
Promise的出现解决了ajax异步加载时代码复杂的问题,在较新版本的ajax中有封装了Promise

<!--Promise的基本写法-->

let p = new Promise(function(resolve,reject){
	$.ajax({
		url:'hello.txt',
		dataType:'json',
		success(arr){
			resolve(arr);	//执行成功调用resolve()返回arr
		},
		error(err){
			reject(err);	//执行失败调用reject()返回err
		}
	})
});

p.then(function(arr){	//接受resolve()返回的参数
	console.log('成功',arr);
},function(err){	//接受reject()返回的参数
	console.log('失败',err);
});

1.10.2 Promise.all()

知识点:
当有多个Promise一起异步执行时,使用Promise.all()来返回多个Promise调用结果

let p1 = new Promise(functioin(resolve,reject){...});

let p2 = new Promise(functioin(resolve,reject){...});

Promise.all([p1,p2]).then(arr=>{	//此处也可简写成箭头函数
	let [res1,res2]=arr;	//解构赋值
	console.log(res1,res2);
},err=>{
	let [err1,err2]=err;
	console.log(err1,err2);
});

1.10.3 Promise.race()

知识点:
与Promise.all()用法相似,原则是谁先来先返回谁,即哪个Promise返回的值快就返回谁,可以用于超时处理

Promise.race([p1,p2]).then(results=>{},err=>{});

1.11 generator

1.11.1 generator简介

知识点:
generator(生成器),执行过程中可以暂停去执行其他函数
generator跟promise相似,用于异步回调处理,异步的请求可以用类似同步的逻辑来写

普通函数异步请求:
function 函数(){
	代码...

	ajax(xxx,function(){
		代码...
	});
}

generator异步请求:
function *函数(){	//*不能省略
	代码...

	yield ajax(xxx);

	代码...
}

1.11.2 yield介绍

知识点:
yield把函数分成了几部分,通过调用next()来分别执行
yield可以传参和返回

传参:
function *show(){
	alert('a');

	let a=yield;	//执行第二个next的时候把5赋值给a

	alert('b');
	alert(a);	//输出5
}

let gen=show();
gen.next(12);	//执行yield的上半部分
gen.next(5);	//执行yield的下半部分

返回:
function *show(){
	alert('a');

	yield 12;	//返回12给第一个next

	alert('b');

	return 55;	//返回55给第二个next
}

let gen=show();

let res1=gen.next();
console.log(res1);	//输出{value:12,done:false}

let res2=gen.next();
console.log(res2);	//输出{value:55,done:true}

1.11.3 generator实例

知识点:
在使用前需要安装runner,并引入jquery.js(用于ajax)和runner.js

runner(function *(){

	//使用同步的写法实现异步的请求

	let data1=yield $.ajax({url:'data/1.txt',dataType:'json'});
	let data2=yield $.ajax({url:'data/2.txt',dataType:'json'});
	let data3=yield $.ajax({url:'data/3.txt',dataType:'json'});

	console.log(data1.data2.data3);
});

1.12 回调函数的对比

知识点:
1. 在同时请求多条数据的时候,promise和generator方法效果差不多

<!--传统回调-->
//第一层
$.ajax({
	url:xxx,
	dataType:'json',
	success(data1){
		//第二层
		$.ajax({
			url:xxx,
			dataType:'json',
			success(data2){
				//第三层
				$.ajax({
					url:xxx,
					dataType:'json',
					success(data3){
						//OK
					},error(){
						alert('失败');
					}
				});
			},error(){
				alert('失败');
			}
		});
	},error(){
		alert('失败');
	}
});

<!--promise-->
Promise.all([
	$.ajax({url:xxx,dataType:'json'}),
	$.ajax({url:xxx,dataType:'json'}),
	$.ajax({url:xxx,dataType:'json'}),
]).then(res=>{
	//OK
},err=>{
	alert('失败');
});

<!--generator-->
runner(function *(){
	let data1=yield $.ajax({url:xxx,dataType:'json'});
	let data2=yield $.ajax({url:xxx,dataType:'json'});
	let data3=yield $.ajax({url:xxx,dataType:'json'});

	//OK
});

2. 在请求完数据后,通过数据的值来判断下一条请求时,generator>传统回调>promise

<!--传统回调-->
$.ajax({url:'getUserData',dataType:'json',success(userData){
	if(userData.type=='vip'){
		$.ajax({url:'getVipData',dataType:'json',success(items){
			//OK
		},error(err){
			alert('失败');
		}})
	}
},error(err){
	alert('失败');
}})

<!--promise-->
Promise.all([
	$.ajax({url:'getUserData',dataType:'json'})
]).then(res=>{
	let userData=res[0];

	if(userData.type=='vip'){
		Promise.all([
			$.ajax({url:'getVipData',dataType:'json'})
		]).then(res=>{
			//OK
		},err=>{
			alert('失败');
		});
	}
},err=>{
	alert('失败');
});

<!--generator-->
runner(function *(){
	let userData=yield $.ajax({url:'getUserData',dataType:'json'});

	if(userData.type=="vip"){
		let items=yield $.ajax({url:'getVipData',dataType:'json'});
		//OK
	}
});

猜你喜欢

转载自www.cnblogs.com/windyz99/p/12732474.html