看完了ES6的胖哥blog,感觉对ES6有点上道的意思了。所以看完了,代码也敲完了,那么是时候该沉淀一波了。
之所以我会将其写为ES6系列的01,与其网上一大堆的ES6 tutorials相比较,肯定就有点关公面前玩大刀了(阮一峰大哥那是真的厉害,看着ES6居然不知不觉又看上了他的简介…)。
随便问问度娘,出现了一大堆ES6吹捧者的好评。至于前端开发者为啥对ES6这么见之不忘,思之如狂的爱慕,可以去知乎上看看大佬们的牛吹得是有多优雅[https://www.zhihu.com/question/53045668]。
根据我的规划,打算将ES6分为3次来分享。毕竟太过优雅的东西,狼吞虎咽后,太过可惜。
下面是我的整体性思维导图。这是跟着阮哥走。
废话不多说,上车!
变量的声明
const、let、var
- const 声明的是一个只读的常量。
- 声明的范围:只在块级范围内有效
- 可操纵性:readonly
- 本质:const也是先声明后使用,且不可重复声明。在C语言中,也有关键字const。对于一个基本类型的const 常量来说,一个值对应着一个存储地址,由于const的存在,限制了其在出生的时候就要定义了它的基本信息,但是const一个对象时,它意味着一个指针指向这个对象,但是这个对象里的属性是随意开辟新的空间的,貌似和c语言中的结构体一样,一个字符串的长度未知时可以用 * 来表示,以便后期动态开辟内存空间,扯远了,我在想Js啥时候能出现个指针类型,那就有点意思了。
// define a const object.
const obj = {}
// set the prop of this obj.
obj.name = 'jshan';
console.log(obj);
//Its a right way to handle.
const arr = [];
arr.push('hello');
//all right.
- let 不多说,就是一个在块级范围内有效的关键字。
- var 命令声明变量是在ES5中就有了的,globe是node环境下的对其使用,window是浏览器环境下的对其使用。
变量的解构赋值
What’s the destructing?(啥叫解构)
ES6 允许按照一定的模式,从数组和对象中提取值,对变量进行赋值,这个过程叫做解构。
How to destruct that?
我想用代码块直接来说明问题。
/*
******************数组解构******************
*/
let [start,...end] = [1,2,3,4,5,6,7];
//对于 Set 结构,也可以使用数组的解构赋值
let [x,y,z] = new Set([106.2,38.6,1.05]);
//事实上,只要某种数据结构具有 Iterator 接口,
//都可以采用数组形式的解构赋值。
let [a=fun(),b='sterry'] = [undefined,null];// a= fun;b=null
/*
******************对象解构********************
*/
//对象解构赋值的本质是先找到同名属性,然后在赋值给对应的变量
let {first_N:js} = {First_N:"jshan"}
//数组本质是特殊的对象,因此可以对数组进行对象属性的解构,是对象!
let arr = [1,2,3];
let {0:first,[arr.length-1]:last} = arr;
/*
****************字符串解构*********************
*/
const [a,b,c,d,e] = 'jsonp';
// a = 'j'
let {length:len} = 'jsonp';
//len = 5
/*
*****************数值&布尔值解构赋值**************
*/
//需要注意的是在等号右边是数值或者布尔值,则会先转换为对象
let {toString:s} = 123;
/*
***************函数参数的解构赋值******************
*/
let arr = [[1,3],[6,10]].map([x,y]=>{return a+b});
//arr=[4,16]
let objx = {
move_av:function({x=0,y=0})
}
//注意两个函数的默认参数区别
let spp = ({ x = 0, y = 0 }={}) => {
console.log([x,y]);
return [x, y];
};
let t = ({x,y}={x:0,y:0})=>{
console.log([x,y]);
return [x,y];
};
spp({}); //[0,0]
t({x:1}); //[1,undefined]
WHY WE PREFER THAT?
- 交换变量的值
- 从函数返回多个值
- 函数参数的定义
- 提取JSON数据【感觉这个就是提取JSON数据的神器啊!!6的飞起~】
- 遍历MAP结构【说到底还是将MAP对象的KEY & VAL 返回给变量数组】
- 输入模块的指定方法:在dojo中,我们引入一个模块时,模块中有大量的函数,我们可以定制化的显示,指定输入的方法,这样的话看起来清爽,用起来效率也会清爽的不得鸟~
字符串的扩展
阮一峰大哥大哥讲求的是全,所以面面俱到。在这块,我选了几个比较重要的和大家分享。
字符串遍历器的接口 & CHARAT() & SO ON
算了上代码吧,这个没啥好讲的,阮哥说还可以识别异常码点,这个在特定环境下使用的比较多。
//迭代器
for(let xp in 'China'){
console.log(xp);
}
// [z,x,c,v,b] = 'China'
//charat()
'japan'.charat(0)
// startsWith() endsWith() includes()
'America'.startsWith('s') //false
//repeat()
'Nation'.repeat(3); //Nation * 3
模板字符串
咳咳,这玩意好家伙,模板输出大大简化操作。先看看在浏览器端的应用。需要注意的一点是所有模板字符串的空格和换行,都是被保留的!不想要的话直接后面trim()方法将其干掉!
$('#rst').append(
`
There are ${classmates.gn} girls in your classroom.
`.trim()
);
//模板字符串中嵌入变量,需要将变量名写在${}之中。
//大括号内部可以放入任意的 JavaScript 表达式,可以进行运算,以及引用对象属性。
let x =1,
y=2;
console.log(`${x*2}+${y*3}=${x*2+y*3}`);
//模板字符串之中还能调用函数。
function xp()
{
x='That a xp os.';
return x;
}
console.log(`${xp()}`);
//标签模板
xp`${()}`
正则 & 数值的扩展
什么叫正则表达式 & 怎么使用
[]: http://www.runoob.com/jsref/jsref-obj-regexp.html “正则表达式”
这还是讲的比较详细的,可以作为参考。
数值的扩展
感觉在数值扩展这块记住几个函数方法,在实战过程中可以应用就好了。
- Number.isFinite() 用来检查一个数值是否为有限的(finite)返回布尔。
- Number.isNaN() 用来检查一个值是否为NAN。
- Number.parseInt() & Number.parseFloat() 将数值转换为Int或者Float
- Number.isInteger() 判断是否是整数 返回布尔
- Number.EPSILON 表示一个min[1,+1]
- 为了精确,JS出现了个安全数Number.isSafeInteger()
- Math.trunc() 用于去掉一个数的小数部分
- Math.signn() 判断是整数(返回+1)负数(-1)零(0)其他值(NAN)
- 当然还有对数、指数、双曲函数的方法也有相应的增加,用到直接查。
函数的扩展
函数参数的默认值
用代码说几个比较有意思的,剩下的用法简单。
//参数默认值是惰性求值的
let x =99;
let lzy = (p=x+1)=>{
console.log(p);
}
lzy(); //100
x =100;
lzy(); //101
//在函数有多个参数时,含有默认参数的位于后面,否则默认参数设置可能无效
function parms(x=0,y=0,{x,y=0}={}){/*...*/}; // parms()即可
//可以计算要输入函数参数的个数方法:parms.length //return 0;
REST 参数 & 严格模式 & name属性
比较简单的东西,写代码学习。
/*
*************REST parms****************
1.REST 参数后不能在跟其他参数
2.REST 参数所在的函数对其length属性求参时,不包括REST参数
*/
let rstf = (num1,...numn)=>{
let tmp = 0;
for (let i of numn){
tmp+=i;
}
return tmp;
}
let len = rstf.length; //len = 1;
/*
******************严格模式****************
1.规定只要函数参数使用了默认值、解构赋值、或者扩展运算符,那么函数
内部就不能显式设定为严格模式,否则会报错
2.表示是'use strict'
3.注意: 3.1 设定全局性的严格模式,这是合法的。
3.2 是把函数包在一个无参数的立即执行函数里面
*/
const dsth = (()=>{
'use strict'
return (val=42)=>val;
}());
//获取函数名
let nm =dsth.name; //dsth
箭头函数
基本语法就不赘述( A=>B )
需要注意:
- 函数体内的this对象,就是定义时所在的对象,而不是使用时所在的对象。
- 不可以当作构造函数
- 不可以使用arguments对象,如果要用,可以用 rest 参数代替。
- 不可以使用yield命令,箭头函数不能用作 Generator 函数
//this 使用方式
function fps()
{
setTimeout(()=>{console.log('id',this.id)},200);
}
fps.call({id:2});
//下面的这种方式是因为call和箭头函数对操作对象互相限制,就是互怼!
//[https://blog.csdn.net/ganyingxie123456/article/details/70855586]
//上面网址解释了apply() & call() 服气!
let fpst = ()=>{
console.log(this.id);
setTimeout(()=>{console.log('id',this.id)});
}
fspt.call({id:2});
/*
***划重点*****
1.函数存在自己的this,所有的嵌套内层的箭头函数都会指向最外层的函数的this
2.arguments、super、new.target在箭头函数中也是不存在的
*/
数组 & 对象扩展
数组
- 数组的扩展运算符
- 扩展运算符后面是可以放置表达式的。(将一个数组转为用逗号分隔的参数序列)
- 如果将扩展运算符用于数组赋值,只能放在参数的最后一位,否则会报错。
let x = 8;
const arr = [-1,...(x>0?['a','w','d','s']:[]),'b'];
console.log(arr);
- 替代函数的apply()方法
//ES5
let arr = [1,2,3,4,5,6,8,66];
Math.max.apply(null,arr); //return 66
//ES6
Math.max(...arr);
// 常规
Math.max([1,2,4,5,6,7]);
let arr2 = [1112,3,2,1,233,2,1];
Array.prototype.push.apply(arr,arr2);
arr.push(...arr2);
//Array.from()可以将一些对象转换为数组[https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Array/of]
let x =Array.of(...arr); //对应起来x还是arr数组
- 其他常用函数
/*
*********** Find() & FindIndex()****************
*/
let arr = [1,11,44],
person = {
name:'jshan',
age:12
};
arr.find((value,index,arr)=>value>9);
function fv(v)
{
return v>this.age;
}
arr.find(f,person);//return 44
NaN.findIndex(NaN=>Object.is(NaN,NaN));//return 0;
/*
*************fill()*****************
*/
let psr = [1,2,3,4,5,6,7];
psr.fill('a',1,4);//parm1:val parm2:startpos parm3:endpos
// entries(),keys() 和 values() & for of.
//可以使用arr.entries.next()进行手动遍历
/*
*** includes() & Array.prototype.includes() ***
两个方法类似,返回值都是布尔值。
*/
const contains = (() =>
Array.prototype.includes
? (arr, value) => arr.includes(value)
: (arr, value) => arr.some(el => el === value)
)();
contains(['foo', 'bar'], 'baz'); // => false
//注意:Map 结构的has方法,是用来查找键名的;Set 结构的has方法,是用来查找值的.
//还有就是空位的处理,唯一建议是避免空位的出现。
对象
- 属性名表达式如果是一个对象,默认情况下会自动将对象转为字符串[object Object],这一点要特别小心。
const ka = {a:1},
kb ={b:2};
const myobj = {
[ka]:'valA',
[kb]:'valB'
}//后者会覆盖前者
//在使用obk对象时,首先应该对其设置值set然后再get(),否则是undefined
const obk ={
get(){
retun this.val;
},
set(val){
this.val =val;
}
}
// Object.is() 注意=== & Object.is(a,b) 之间的区别
+0 === -0 //true
NaN === NaN // false
Object.is(+0, -0) // false
Object.is(NaN, NaN) // true
- Object.assign()方法【第一个参数是目标对象,后面的参数都是源对象。用于拷贝】
//目标对象与源对象有同名属性,或多个源对象有同名属性,则后面的属性会覆盖前面的属性。
const target = {
a:1
},source1 = {
a:1,
b:2
},source2 ={
b:5,
c:6
};
let cx = Array.of(source1,source2);
let pc =Object.assign(target,...cx);
console.log('Object.assign():');
console.log(pc);
//由于undefined和null无法转成对象,所以如果它们作为参数,就会报错。
Object.assign(undefined);//error!
let obj = {a:1};
Object.is(Object.assign(obj,undefined),obj);//return true.
//浅拷贝 & 同名属性的替换 & 数组的处理 & 取值函数的处理
- 一旦遇到同名属性,Object.assign的处理方法是替换,而不是添加。
- 可以用来处理数组,但是会把数组视为对象
- 只能进行值的复制,如果要复制的值是一个取值函数,那么将求值后再复制
- Object.assign()常见用途
- 为对象添加属性
class Point{
constructor(x=0,y=0){
Object.assign(this,{x,y});
},
set(x,y){
Object.assign(this,{x,y});
},
get(){
console.log('x:'+this.x+';y:'+this.y);
}
}
- 为对象添加方法 & 克隆对象 & 合并多个对象 & 为属性指定默认值
Object.assign(classA.prototype,{
method1(){},
method2(){}
});
//只能克隆对象自身的值不能克隆继承值
function clone(origin){
return Object.assign({},origin);
}
const merge = (...source)=>Object.assign({},...source);
//为属性指定默认值
const DEFAULTS = {
host: 'localhost',
port: '8080'
};
function processContent(options) {
options = Object.assign({}, DEFAULTS, options);
console.log(options);
// ...
}
- 属性的枚举和遍历
之前有谈到数组的遍历 for of 、arr.entries()、key、value的遍历,还有手动遍历arr.entries.next(),那么对象的遍历是怎样的呢?
- for…in 循环遍历对象自身的和继承的可枚举属性(不含symbol,它对属性有保密安全作用)
- Object.keys(obj) 返回一个数组,包括对象自身的(不含继承的)所有可枚举属性(不含 Symbol 属性)的键名
- Object.getOwnPropertyNames(obj) 返回一个数组,包含对象自身的所有属性(不含 Symbol 属性,但是包括不可枚举属性)的键名
- Object.getOwnPropertySymbols(obj) 返回一个数组,包含对象自身的所有 Symbol 属性的键名
- Reflect.ownKeys(obj) 返回一个数组,包含对象自身的所有键名,不管键名是 Symbol 或字符串,也不管是否可枚举
- Object.getOwnPropertyDescriptors() & proto属性,Object.setPrototypeOf(),Object.getPrototypeOf()
//es6
const obj ={
method(){}
}
obj.__proto__=someObj;
//es5无论从语义的角度,还是从兼容性的角度,都不要使用这个属性,
//而是使用下面的Object.setPrototypeOf()(写操作)、
//Object.getPrototypeOf()(读操作)、Object.create()(生成操作)代替。
var obj = Object.create(someOtherObj);
obj.method = function() { ... };
//Object.setPrototypeOf()用来设置一个对象的prototype对象,返回参数对象本身
let proto = {};
let obj = { x: 10 };
Object.setPrototypeOf(obj, proto);
proto.y = 20;
proto.z = 40;
//该方法与Object.setPrototypeOf方法配套,用于读取一个对象的原型对象。
function Rectangle() {
// ...
}
const rec = new Rectangle();
Object.getPrototypeOf(rec) === Rectangle.prototype
// true
Object.setPrototypeOf(rec, Object.prototype);
Object.getPrototypeOf(rec) === Rectangle.prototype
- this <=> super:这个让我想起了Java或者c#的super。一个道理,super指向的是本对象的它爹,而this所指的是对象本身,那么就好理解了。
//super.foo等同于Object.getPrototypeOf(this).foo(属性)
//或Object.getPrototypeOf(this).foo.call(this)(方法)。
const proto = {
x: 'hello',
foo() {
console.log(this.x);
},
};
const obj = {
x: 'world',
foo() {
super.foo();
}
}
Object.setPrototypeOf(obj, proto);//这句话就把父子关系给建立了
obj.foo() // "world"
- Object.keys()、Object.values()、Object.entries() 返回的是个数组或者嵌套数据。
未完,下期再聊哈~
司马相如一首小情苏打动了卓文君小镁铝,还是强、
凤求凰
有一美人兮,见之不忘。
一日不见兮,思之如狂。
凤飞翱翔兮,四海求凰。
无奈佳人兮,不在东墙。
将琴代语兮,聊写衷肠。
何日见许兮,慰我彷徨。
愿言配德兮,携手相将。
不得於飞兮,使我沦亡。
凤兮凤兮归故乡,遨游四海求其凰。
时未遇兮无所将,何悟今兮升斯堂!
有艳淑女在闺房,室迩[ěr]人遐毒我肠。
何缘交颈为鸳鸯,胡颉颃[xié háng]兮共翱翔!
凰兮凰兮从我栖,得托孳尾[zī wěi]永为妃。
交情通意心和谐,中夜相从知者谁?
双翼俱起翻高飞,无感我思使余悲。
分享有价值的玩意,Bye。