博客仅用来记录自己的学习历程,如果有错,希望您能私信我,或者在评论区提出,感谢
如果要说起es6,首先当然要说说let与const,那let又是什么,let,其实是es6新推出的,用来定义变量的关键字,用来取代已经老旧的var。
let的特点:有块级作用域,意思就是,变量的有效范围,只在它所在位置的一前一后的两个大括号中间。
没有预处理,意思是,不能在声明变量之前使用它。
不能重复定义。
let的作用与应用:作用就是定义一个变量,应用在循环遍历监听,比var方便很多
let btns = document.getElementsByTagName("button");
for( i = 0;i
const:定义一个常量,不可改变,其他的特点与let相同
解构赋值的主要理解就是,从数组或者对象中取值,然后赋值给多个变量。
而解构赋值的用途多用在给函数的多个形参赋值的时候。
//首先声明一个对象,一个数组
let obj = {
name:"小明",
age:10
}
let arr = [1,2,"333"];
//用解构赋值的方法,将obj中的name,age属性赋值给全局变量name,age
//注:如果要提取对象中的属性,声明变量时,一定要用大括号,大括号中的变量名,会一一对应
//目标对象中的同名属性
let {name,age} = obj;
//用解构赋值的方法,将arr中下标为0,1的数据赋值给了全局变量a,b
//注:如果要提取数组中的数据,则声明变量时,要用中括号括住,每个变量会与数组中相应的下标
//一一对应
let [a,b] = arr;
console.log(name,age);//小明 10
console.info(a,b); //1 2
//使用解构赋值的方法传递参数
function fun({name}) {
console.log(name);
}
fun(obj)
在使用字符串加变量拼接成一个新的字符串的时候,我们都需要用引号,加号,引号,加号之类的方法去拼接,这样的效率无疑是非常低下的,而es6给我们提供了模板字符串,让字符串加变量变得简便了很多。
es6模板字符串的拼接方式为 `` 两个重音符,把要拼接的字符串与变量写在里面,而变量则要写在 ${} 里面
`这里写字符串${这里是变量}字符串 `
let usernmae = "kobi",age = 40;
//相对于旧的拼接方式,新的模板字符串无疑是非常方便的
let str = `我叫${usernmae}我今年${age}岁了`;
let str2 = "我叫"+usernmae+"我今年"+age+"岁了";
console.log(str);//我叫kobi我今年40岁了
在es6中,对象中的属性和方法都是可以简写的
属性:如果在全局作用域中有同名属性,则属性值,可以省略不写,只写属性名就行
方法:方法可以省略function
let username = "2333";
let obj = {
username,
shuo(){
console.log("我也不知道我要说什么");
}
}
console.log(obj);
obj.shuo();//我也不知道我要说什么
在es6中,新增了一种声明函数的方式,即为箭头函数
let 函数名 = (参数) =>{函数体}
箭头函数与普通函数最大的区别就是 this,箭头函数没有自己的this,箭头函数的this,在于定义箭头函数时,它的外部,是否有普通函数,如果有,则普通函数的this就是箭头函数的this,如果没有,则this为window。
var obj = {
name:"obj",
fun8:()=>{
console.log(obj.name);
}
};
//外部有常规函数,this为常规函数的this,即为obj;
function fun5() {
console.log(this)
let fun6 = () => {
console.log(this)
}
return fun6;
}
//外部没有常规函数,this为window
let fun7 = () => {
console.log(this)
}
fun5.call(obj)();// obj
// obj
fun7(); //window
接下来是箭头函数的一些书写规则
let fun1 = name => console.log(name) // 一个形参时,形参位置可以没有括号
let fun2 = (name,age) => console.log(name,age)//两个即两个以上的形参,则需要括号,形参之间用逗号隔开;
let fun3 = name => name//如果函数体只有一行且没有大括号,那么这一行的执行结果会被直接返回
console.log(fun3("小明"));// 小明
let fun4 = (naem,age) => {
console.log(name);
console.log(age);
}//如果有两条以上的函数体,则需要大括号
三点运算符是es6为了取代arguments而定义的,因为arguments只是一个伪数组,没有一般数组的方法,而三点运算符是真的数组,而且比较灵活,不过三点运算符只能用来提取形参最后的参数。
function fun(...value){}
function fun(...value) {
console.log(value);
//三点运算符拥有数组的一般方法
value.forEach(function (item,index) {
console.log(item,index);
})
}
function fun2(a,...value) {
console.log(value);
}
fun(1,2,3,4); // [1,2,3,4]
fun2(1,2,3,4);// [2,3,4]
let arr = [1,6];
let arr2 = [2,3];
let arr3 = [1,...arr2,6] // arr3 = [1,2,3,6]
这样可以方便快捷的使数组进行拼接
形参默认值还是比较简单的,就是在定义形参的时候,给它赋一个默认值就好了
let fun = (name = "wu",age = 0) =>{
console.log(name,age);
}
fun();//wu 0
fun("小明",18);//小明 18
如果用户没有传入参数,则使用形参的默认值,如果用户传入了参数,则使用用户传入的参数。
promise函数是es6为了解决回调函数层层嵌套,也就是回调地狱从而创建的。
promise函数是用来表示未来要发生的某一件事(通常是异步操作),promise是一个构造函数,用来创建promise对象
let fun = () => {
let promise = new Promise(function (resolve,reject) {
console.log(1);
setTimeout(function () {
//用来模拟ajax调用的成功与失败
let num = Math.random();
if(num>0.5){
//将状态变为成功
resolve("成功了");
}else {
//将状态变为失败
reject("失败了");
}
console.log(num);
},2000)
})
return promise;
}
fun()
.then(
//成功的回调函数,如果状态变为fullfilled则会自动执行
function (data) {
console.log(data,"一次调用成功");
},
//失败的回调函数,如果状态变为rejected则会自动执行
function (data) {
console.log(data,"一次调用失败");
}
)
promise有三个状态,pending初始化状态,fullfilled:成功状态 ,rejected:失败状态
刚开始时,promise的状态为pending初始化,在某个时刻,如果调用resolve()函数则状态变为fullfilled成功
如果调用reject()函数,则状态变为rejected失败
当成功或者失败状态触发时,则promise对象的then方法则会调用相应的(成功或者失败)的函数。
promise还可以进行链式调用
fun()
.then(
//成功的回调函数,如果状态变为fullfilled则会自动执行
function (data) {
console.log(data,"一次调用成功");
//如果成功,则继续调用该方法,并把promise对象返回,进行链式调用
return fun();
},
//失败的回调函数,如果状态变为rejected则会自动执行
function (data) {
console.log(data,"一次调用失败");
}
)
.then(
function (data) {
console.log(data,"二次调用成功");
},function (data) {
console.log(data,"二次调用失败");
}
)
symbol属性是es6新增的一种属性
symbol属性的特点是:symbol属性对应的值是唯一的,解决了命名冲突的问题
symbol属性不可以与任何属性进行计算,哪怕是字符串的拼接
for in for of 遍历时不会遍历到symbol属性
如果要使用symbol属性的话,需要调用Symbol函数,返回值为symbol属性
如:let symbol = Symbol(); let obj = {}; obj[symbol] = "hello";
//Symbol函数的返回值就是symbol对象
let symbol = Symbol();
let obj = {}
obj.symbol = "11";
console.log(obj);//symbol:"11"
//Symbol函数还可以传入参数
let symbol = Symbol('one');
let symbol2 = Symbol('two');
let symbol3 = Symbol();
let symbol4 = Symbol();
//任意两个symbol都不相等
console.log(symbol3 == symbol4); // false
console.log(symbol);// Symbol('one')
console.log(symbol2);// Symbol('two')
Symbol对象除了可以自定义之外,es6还提供了11个内置的symbol对象,用来指向相对应的方法。
如:Symbol.iterator属性,指向的是该对象的默认遍历器方法。
iterator接口是为了让所有数据类型拥有统一的访问机制。
作用:为所有数据提供统一的,简便的访问接口。
能够让数据结构的成员按照某种次序排列。
es6新推出了一种遍历方式 for of ,而iterator则是为for of服务。
iterator的原理:首先当数据进行遍历是,让指针对象(遍历器对象)指向数据结构的起始位置,当调用next方法时,指针对象后移一位,并且返回一个对象,包含两个属性,value 与 done,value表示的是指针对象所在位置属性的值,而done则表示数据结构是否已经结束(指针对象大于等于length)。原生具备iterator接口的数据类型才可以使用for of遍历。
let iterator =(arr) =>{
//首先将指针对象指向数据类型的起始位置
let nextIndex = 0;
//然后返回的对象中有一个next方法
return {
//用于返回value属性,done属性
next:()=>{
return nextIndex < arr.length?{value:arr[nextIndex++],done:false}:
{value:undefined,done:true};
}
}
}
let arr =[1,2,"abc"];
let bianli = iterator(arr);
console.log(bianli.next());
console.log(bianli.next());
console.log(bianli.next());
console.log(bianli.next());
Generaator函数也是es6为了解决回调函数问题而设计的,Generator函数又称为可暂停函数。
Generator函数第一次调用时不会执行,只有调用next方法时才会开始执行,Generator函数内部有 yield 语句,每当执行到yield时,则会暂停,如果用Generator函数返回的对象调用next方法,则会返回yield后面一行语句的执行结果,并且再次暂停,直到下次调用next方法。
next方法的返回值是一个对象,value done,value属性值是next函数的返回值,done则表示函数是否执行到最后。
如果要使用Generator函数,则需要在正常函数的function后加一个*号。
function* getNews() {
console.log(1)
//变量a是下一个next方法传入的参数
let a = yield 233
console.log(a)
}
//开始不会执行
var news = getNews();
//只有在调用next方法时,才会执行,遇到yield则暂停,返回值是yield后面一行语句的执行结果
console.log(news.next());//1
// {value: 233, done: false}
console.log(news.next("我是next方法传入的参数"));//我是next方法传入的参数
//{value: undefined, done: true}
接下来将用Generator函数来向服务器发送请求,获取数据。分别要获得新闻数据和评论数据,只有在新闻获取成功之后才获取评论。
//服务器获取新闻的url是http://127.0.0.1:3000/news?id=3
//这个方法是通过jquery的ajax方法从服务器获取数据的。
//传入url,获取到数据
function getNews(url) {
$.get(url,function (data) {
console.log(data);
let url = "http://127.0.0.1:3000"+data.commentsUrl;
// 2. 如果新闻获取成功的话,再用拼接好的url获取评论
//传入的参数会成为一个yield语句的返回值,给获取评论的函数一个url
send.next(url);
})
}
//这是Generator函数,用来进行每一步的ajax请求
function* sendXml() {
// 1. 首先传入第一个url,获取新闻
let url = "http://127.0.0.1:3000/news?id=3";
url = yield getNews(url);
// 3. 通过上一个函数得到url,获取评论
yield getNews(url);
}
let send = sendXml();
// 0 Generator函数开始执行。
send.next();
async函数是es2017提出来,彻底解决异步函数调用的。
async函数不需要像Generator函数一样调用next方法指向下一步,而是等待异步操作执行完之后自动调用下一步,返回的对象是promise对象,可以用then方法进行下一步的操作。
async取代了*,await取代了yield。
await的返回值,如果后面语句是表达式,则直接返回
如果是函数的话,返回值就是一般函数的返回值
如果是promise对象的话,返回值是resolve函数传入的参数。
async的语法
async function foo() {
//遇到await则等待后面的异步函数执行完毕才会执行下一步。
let a = await 1;
console.log(a);
}
foo()//1
接下来将用async函数向服务器请求数据。
//这是想服务器请求数据的方法
async function getNews(url) {
//这个函数返回的是promise对象,
return new Promise((resolve,reject) => {
console.log(1);
$.ajax({
method:"GET",
url,
//如果请求成功,则await的返回值为resolve的参数
success:(data)=> resolve(data),
error:(error) => resolve(false)
})
})
}
async function send() {
//进行新闻的请求
let url = "http://127.0.0.1:30001/news?id=1"
let result = await getNews(url);
//如果请求失败,则给用户提示,并且结束函数
if(!result){
alert("暂时没有新闻内容,请稍后再来");
return;
}
console.log(result);
//如果成功,则继续请求评论
result = await getNews("http://127.0.0.1:3000"+result.commentsUrl);
console.log(result);
}
send();
终于,在es6中,js也有类的概念了,所谓类,其实是一个抽象的概念,比如,我定义人这个类,人可以走,可以吃饭,我就在类中,写好吃饭,走,两个方法,但是因为每个人的名字,性格等待都不相同,我就在构造方法中,写入两个形参,名字,性格,然后让this.name = name ,这样就可以让每个人类的实例,可以有不同的姓名,性格等,而且他们还拥有人类的方法。
通过class关键字创建一个类 class people{}
在类中,可以通过constructor关键字来定义构造方法。
如果要在类中定义方法的话,不能有function关键字,而是直接书写方法 如:getName(){};
类与类之间通过extends来进行继承。并且需要在子类的构造方法中调用super()方法调用父类构造函数。
通过new关键字,new类名来创建一个实例。
//这是定义的人类
class people{
//构造方法,人有名字,有年龄,所以传入相应的参数
constructor(name,age){
this.name = name;
this.age = age;
}
//这是父类的获取名字的方法,实例可以直接打点调用该方法
getName(){
console.log(this.name);
console.log("这是父类的方法");
}
}
//这是我,继承的人这个类
class wo extends people{
//子类构造方法
constructor(name,age,gongzi){
//必须调用父类构造方法,并且super关键字需要是第一行
super(name,age);
this.gongzi = gongzi;
}
//因为父类无法满足,所以在子类重写了该方法
getName(){
console.log(this.name+" "+this.gongzi);
console.log("这是子类的方法");
}
}
let ren = new people("呵呵",1);
ren.getName();
//呵呵
//这是父类的方法
let me = new wo("哈哈",2,100000000);
me.getName();
//哈哈 100000000
//这是子类的方法
接下来说说es6对于数组,对象,字符串,Number 扩展的一些方法,先从字符串说起。
字符串扩展方法: includes(str) // 判断字符串是否包含制定的字符串。
startWith(str)//判断是否以指定字符串为开头。
endsWith(str)//判断是否以字符串为结尾
repeat(count)//重复指定次数
let str = "abcdefg";
console.log(str.includes("c"));//true;
console.log(str.startsWith("a"));//true
console.log(str.endsWith("g"));//true
console.log(str.repeat(2));//abcdefgabcdefg
Number的扩展方法: Number.isFinite(i)//判断是否是有限大的数
Number.isNaN(i)//判断是否是NaN
Nubber.isInteger(i)//判断是否是整数
Number.parseInt(i)//将字符串转换为数字
Number.trunc(i)//去除小数点
二进制与八进制数值表示法: 二进制用0b, 八进制用0o
console.log(0b1001);//9
console.log(0o56);//46
console.log(Number.isFinite(Infinity));//false
console.log(Number.isNaN(NaN));//true
console.log(Number.isInteger(123.3));//false
console.log(Number.parseInt("123acc"));//123
console.log(Math.trunc(123.33));//123
数组的方法: Array.from() // 用来将一个伪数组(arguments之类的)转换成真数组。
Array.of() //用来将传入的参数转换成数组
Array.Prototype.find(function(iteam,index){})//返回数组中以第一个条件为true的数据
Array.Prototype.findIndex(function(iteam,index){})//返回数组中以第一个条件为true的数据下标
function test(){
let arr = Array.from(arguments)
arr.forEach(function (iteam,index) {
console.log(iteam);
})
}
test(1,1,2,3,3,3);//
let arr = Array.of(1,2,3,4,"abc");
arr.forEach(function (iteam,index) {
console.log(iteam,"我是Array.of()转化成数组的数据");
})
//find方法与filter方法比较类似,不过find方法只会返回第一个
let arr2 = arr.find(function (iteam,index) {
return iteam>2
})
console.log(arr2,"我是find方法");
let arr3 = arr.findIndex(function (iteam,index) {
return iteam > 2
})
console.log(arr3,"我是findIndex方法");
对象的扩展方法 Object.is(v1,v2)//判断两个数据是否完全相等
Object.assign(target,source1,source2);//将一个或多个对象的数据复制到目标对象上
可以直接操作__proto__属性
console.log(0 == -0);//true
console.log(NaN == NaN);//false
console.log(Object.is(0, -0));//false
console.log(Object.is(NaN, NaN));//true
let obj1 = {};
let obj2 = {name:"小明"};
Object.assign(obj1,obj2);
console.log(obj1);//{name:"小明"}
let obj3 = {qian:5000000000};
let obj4 = {};
obj4.__proto__ = obj3;
console.log(obj4.qian);//5000000000
什么是深度克隆呢
浅克隆:修改克隆的对象,原对象也随之改变,即位浅克隆,有时浅克隆是有风险的。
深度克隆:如果修改了克隆之后的对象,对原对象没有影响的话,就是深度克隆。
如果复制一个基本数据类型,再新的变量修改的话,不会对原数据有影响,但如果复制的是一个引用类型的话,如果修改新的引用,也会对原对象有所影响。
下面是几个拷贝数据的方法 : Object.assign(target,ziyuan)//将资源对象,复制到目标对象 浅拷贝
Array.prototype.concat(arr)//用于连接两个或者多个数组,返回值是连接后的数组
浅拷贝
Array.prototype.slice(num,num)//用于分割数组 浅拷贝
JSON.parse(JSON.stringify())//将一个对象转化成json字符串,然后在转换回来 深拷贝
下面将自定义一个方法,进行对象的克隆,使修改新的对象时,不会对原对象有影响。
主要就是将对象中的基本数据类型复制到新对象中,如果其中还有对象的话,就遍历对象,接着复制基本数据类型。
//我们定义checkType这个方法,是因为我们要对不同的数据类型进行不同的操作。
//如:遇到基本数据类型,直接复制就可以,而遇到数组或者对象,就要遍历他们中的每一项值,在进行值的复制
//因为typeof返回的数据类型只有六种(String Number boolean Undefined object function)
//所以我们自己定义一个方法,可实现返回所有的数据类型
let checkType = (target) =>{
//通过Object的toString方法,并且用call调用传入要识别的对象,然后返回对应类型的字符串
return Object.prototype.toString.call(target).slice(8,-1);
}
//这是克隆方法,只要传入目标对象,就可以返回克隆好的对象,并且修改克隆对象,对新的对象也不会有影响
function clone(target) {
//首先创建一个空对象来接收要复制的对象
let newTarget = null;
//如果要遍历的对象是一个数组,那么newTarget就是一个数组
if(checkType(target) == "Array"){
newTarget = [];
}else if(checkType(target) == "Object"){
newTarget = {};
}else{
//如果既不是数组,也不是对象,直接返回就可以了,因为基本数据类型,没有浅克隆这个概念
return target;
}
//用for in方法遍历数组中的每一项值,如果是基本数据类型,就直接用newTarget的对象接收。
//如果是对象或者数组,就接着遍历其中的每项值,然后返回一个新的对象或者数组,用newTarget接受
for(let i in target){
if(checkType(target[i]) === "Array" || checkType(target[i]) === "Object"){
//用递归的方法去遍历对象(数组)中的数组或者对象。
newTarget[i] = clone(target[i]);
console.log("遍历到一个对象或数组");
}else {
newTarget[i] = target[i];
console.log("遍历到一个基本数据类型");
}
}
//最后,返回一个新的对象
return newTarget;
}
let obj = {
name:1,
info:{
age:2
},
class:"yiban"
}
console.log(clone(obj));
js中的容器与数组比较类似,set容器:无序的,不可重复的多个value的集合体。 说白了,就是不能重复的数组
map容器:无序的key value组合,key值不能重复
set容器的语法:let setarr = new Set([1,1,2,3,4]);
new Set()即可,形参传入数组,数组中传入想穿的数据。
map容器语法:let maparr = new Map([["name","xiaoming"],["age",18]])
//new Map()即可,形参传入二维数组,一维数组是大的容器,二维数组中第一个值是key,第二个是value
set与map容器,都可以用for of去遍历,接下来我将用for of与set为一个数组去重
let arr = [1,1,2,5,4,6,9,8];
let arr1 = []
//因为Set容器不许有重复的数据,所以会自动去掉重复数
let setarr = new Set(arr);
//然后用for of遍历setarr,将数据放入新数组。
for(let i of setarr){
arr1.push(i)
}
console.log(arr1);
幂 **
a ** b 就是a的b次方幂
Array.prototype.includes(value)表示数组中是否有这个数据
console.log(5 ** 5);3125
let arr2 = [1,2,3,"abc"]
console.log(arr2.includes(1));//true
console.log(arr2.includes("a"));//false