css3新特性、es6新特性、

CSS3 新特性

border-radius:圆角边框

box-shadow:盒子阴影

background-size:背景图片大小

transition:过渡

transform:转换(位移 旋转 缩放)

animation:动画

linear-gradient:线性渐变

box-sizing:css3 盒子模型

es6新特性

ES6新特性有哪些?
一、新的原始类型和变量声明
1,symbol
  在ES6之前,我们知道JavaScript支持8种数据类型:Object,String,Boolean,Number,Null,Undefined、Array、Function。现在,ES6新增了一种原始数据类型:symbol,表示独一无二的值,即每个symbol类型的值都不相同。这让我想起了另一个特殊的值:NaN,想一想,他们是不是有一点类似呢!

var sy = Symbol('test');
var sy1 = Symbol('test');
console.log(tepeof sy);   //'symbol'
sy == sy1;   //false
var sy2 = new Symbol('test');   //error : Symbol is not a constructor

创建symbol数据类型的值时,需要给Symbol函数传递一个字符串,并且有一点特殊的是:不能使用new关键字调用它。另外,每个symbol类型值都是独一无二的,即使传递的是相同的字符串。
2,let和const
  ES6新增了两个声明变量的关键字:let和const。
  他们声明的变量仅在let和const关键字所在的代码块内起作用,即在使用let和const的那一对大括号{}内起作用,也称块级作用域(ES6之前只有函数作用域和全局作用域)。
  let和const声明变量不会在预编译过程中有提升行为(在全局声明也不会变成window的属性),且同一变量不能重复声明。所以要使用这类变量,只能在let和const关键字之后使用它们。
  let和const关键字还有一个特性:“暂时性死区”,即在使用了该关键字的块级作用域中,其内部使用let和const关键字声明的变量与外部作用域中的变量相互隔绝,互不影响。即使是同名变量。

var a = 1;
{
   console.log(a);   //error Cannot access 'a' before initialization
   let a = 0;
   console.log(a);   //0
}
console.log(a);   //1

const用来声明一个常量,声明时必须赋值,且一旦声明就不能改变。

其实说const变量不能更改是不准确的,请看下面的例子:

const obj = {
    name:'ren',
    age:12
};
obj = {};   //error
obj.sex = male;
consol.log(obj);   //{name:'ren',age:12;sex:'male'}

const声明的如果是一个原始值,那么上面的说法是准确的,如果const声明的是一个引用值,那么更准确的说法应该是一个不能被重新赋值的变量。
3,解构赋值 
  解构赋值是对赋值运算符的扩展。它是一种针对数组或者对象进行模式匹配,然后对其中的变量进行赋值。

let [a,b,c] = [1,2,3];
console.log(a,b,c);    //1,2,3
 
let [a,b,c] = [1,,3];
console.log(a,b,c);    //1,undefined,3
 
let [a,,b] = [1,2,3];
console.log(a,b);//1,3
 
let [a,..b] = [1,2,3];    //...是剩余运算符,表示赋值运算符右边除第一个值外剩余的都赋值给b
console.log(a,b);//1,[2,3]

事实上所有可枚举(iterable)的对象都可以使用解构赋值,例如数组,字符串对象,以及ES6新增的Map和Set类型。

let arr = 'hello';
let [a,b,c,d,e] = arr;
console.log(a,b,c,d,e);  //'h','e','l','l','o'
  对象的解构赋值和数组类似,不过左边的变量名需要使用对象的属性名,并且用大括号{}而非中括号[]:

let obj = {name:'ren',age:12,sex:'male'};
let {name,age,sex} = obj;
console.log(name,age,sex);  //'ren' 12 'male'
let {name:myName,age:myAge,sex:mySex} = obj;  //自定义变量名
console.log(myName,myAge,mySex);  //'ren' 12 'male'

二  新的对象和方法
  1,Map和Set
  Map对象用于保存键值对,任何值JavaScript支持的值都可以作为一个键或者一个值。这听起来和对象差不多啊?其实它们还是有区别的:
    a) object的键只能是字符串或ES6的symbol值,而Map可以是任何值。
    b) Map对象有一个size属性,存储了键值对的个数,而object对象没有类似属性。

let myMap = new Map([['name','ren'],['age',12]]);
console.log(myMap);  //{'name'=>'ren','age'=>12}
myMap.set('sex','male');
console.log(myMap);  //{'name'=>'ren','age'=>12,'sex'=>'male'}
myMap.get('name');  //'ren'
myMap.has('age');  //true
myMap.delete('age');  //true
myMap.has('age');  //false
myMap.get('age');  //undefined

Map构造函数接收一个二维数组来创建一个Map对象。数组元素的第0位表示Map对象的key,第1位表示Map对象的value。
  Map对象使用set方法来新增数据,set方法接收两个参数,第一个表示key,第二个表示value。使用get方法获取数据,参数是对象的key。
  Map对象使用delete方法来删除数据,接收一个参数,表示需要被删除的key。
  Map对象使用has方法检测是否已经具有某个属性,返回boolean值。
  Set对象和Map对象类似,但它是用来存储一组唯一值的,而不是键值对。类似数组,但它的每个元素都是唯一的。

let mySet = new Set([1,2,3]);
console.log(mySet);  //{1,2,3}
mySet.add(4);
console.log(mySet);  //{1,2,3,4}
mySet.delete(1);  //true
mySet.has(1);  //false

利用Set对象唯一性的特点,可以轻松实现数组的去重:

let arr = [1,1,2,3,4,4];
let mySet = new Set(arr);
let newArr = Array.from(mySet);
console.log(newArr);  //[1,2,3,4]

2,对象新特性

创建对象的字面量方式可以更加简洁。直接使用变量名作为属性,函数体作为方法,最终变量值变成属性值,函数名变成方法名

let name = 'ren';
 let age = 12;
 let myself = {
     name,
     age,
     say(){
         console.log(this.name);
     }
 };
console.log(myself);  //{name:'ren',age:12,say:fn}
myself.say();  //'ren'

对象的拓展运算符(...)三点。用于拷贝目标对象所有可遍历的属性到当前对象。

let obj = {name:'ren',age:12};
let person = {...obj};
console.log(person);//{name:'ren',age:12}
obj == person;//false
let another = {sex:'male'};
let someone = {...person,...another};//合并对象
console.log(someone);//{name:'ren',age:12,sex:'male'}

ES6对象新增了两个方法,assign和is。

assign用于浅拷贝源对象可枚举属性到目标对象。

let source = {a:{ b: 1},b: 2};
let target = {c: 3};
Object.assign(target, source);
console.log(target);  //{c: 3, a: {b:1}, b: 2}
source.a.b = 2;
console.log(target.a.b);  //2

如果有同名属性,那么目标对象的属性值会被源对象的属性值覆盖。所以数组的表现就有一点特别了
数组的index就是属性名,当使用assign方法时,从第0位开始,目标数组的值便开始被源数组的值覆盖了。

is方法和(===)功能基本类似,用于判断两个值是否绝对相等。

Object.is(1,1);//true
Object.is(1,true);//false
Object.is([],[]);//false
Object.is(+0,-0);//false
Object.is(NaN,NaN);//true

他们仅有的两点区别是,is方法可以区分+0还是-0,还有就是它认为NaN是相等的。
  3,字符串新方法
  includes()判断字符串是否包含参数字符串,返回boolean值。如果想要知道参数字符串出现的位置,还是需要indexOf或lastIndexOf方法。
  startsWith()/endsWith(),判断字符串是否以参数字符串开头或结尾。返回boolean值。这两个方法可以有第二个参数,一个数字,表示开始查找的位置。

let str = 'blue,red,orange,white';
str.includes('blue');//true
str.startsWith('blue');//true
str.endsWith('blue');//false

repeat()方法按指定次数返回一个新的字符串。如果次数是大于0的小数则向下取整,0到-1之间的小数则向上取整,其他负数将抛出错误。

console.log('hello'.repeat(2));//'hellohello'
console.log('hello'.repeat(1.9));//'hello'
console.log('hello'.repeat(-0.9));//''
console.log('hello'.repeat(-1.9));//error

padStart()/padEnd(),用参数字符串按给定长度从前面或后面补全字符串,返回新字符串。

let arr = 'hell';
console.log(arr.padEnd(5,'o'));  //'hello'
console.log(arr.padEnd(6,'o'));  //'helloo'
console.log(arr.padEnd(6));  //'hell  ',如果没有指定将用空格代替
console.log(arr.padStart(5,'o'));  //'ohell'

另外,如果字符串加上补全的字符串超出了给定的长度,那么,超出的部分将被截去。

4,数组的新方法

of()是ES6新增的用于创建数组的方法。of把传入的参数当做数组元素,形成新的数组。

let arr = Array.of(1,'2',[3],{});
console.log(arr);   //[1,'2',[3],{}]

from()方法可以将可迭代对象转换为新的数组。函数可接受3个参数:第一个表示将被转换的可迭代对象,第二个是回调函数,将对每个数组元素应用该回调函数,然后返回新的值到新数组,第三个是回到函数内this的指向。后两个参数是可选的。

let obj = {
    double(n) {
        return n * 2;
    }
}
let arr = [1, 2, 3];
console.log(Array.from(arr, function (n){
    return this.double(n);
}, obj)); // [2, 4, 6]

find()和findIndex(),查找数组中符合条件的元素值或索引,方法不会修改原数组。
  接受一个回调函数作为参数,函数可以接受四个参数,分别是当前遍历到的元素,当前遍历到的索引,数组本身以及函数内this的指向。方法会把回调函数作用于每一个遍历到的元素,如果遍历到某一个元素可以使回调函数返回true,那么find方法会立即返回该元素,findIndex方法会返回该元素的索引。并终止继续遍历。
  如果有多个符合条件的,也将只返回第一个。如果遍历完整个数组也无法是回调函数返回true,那么find方法将返回undefined,findIndex方法将返回-1。

let arr = [1,2,3,4,5];
console.log(arr.find((ele) => {
    return ele === 1;
}));//1
console.log(arr.findIndex((ele) => {
    return ele > 4;
}));  //4

fill()/copyWithin(),替换数组中部分元素,会修改原数组。

let arr = [1,2,3,4,5];
console.log(arr.fill(0,0,3));//[0,0,0,4,5]
//参数1表示目标值,参数2,3表示替换的始末位置,左闭右开区间。
console.log(arr.copyWithin(0,2,4));//[0,4,0,4,5]
//参数1表示修改的起始位置,参数2,3表示用来替换的数据的始末位置,左闭右开区间。

fill()用指定的值替换,copyWithin()使用数组中原有的某一部分值替换。
  includes()用于检测数组是否包含某个值,可以指定开始位置。
let arr = [1,2,3,4,5]; console.log(arr.includes(2));//true console.log(arr.includes(1,1));//false
三、函数

1,参数默认值

ES6首次添加了参数默认值。我们再也不用在函数内部编写容错代码了。

function add(a=1,b=2){
    return a + b;
}
add();//3
add(2);//4
add(3,4);//7

和参数默认值一起,ES6还带来了不定参。它的功能和使用arguments差不多。

function add(...num){
    return num.reduce(function(result,value){
        return result + value;
    });
}
add(1,2,3,4);//10

下面介绍的箭头函数没有arguments属性,如果箭头函数内要实现不定参,上述方式就是一个不错的选择了。
  2,箭头函数
  箭头函数实现了一种更加简洁的书写方式,并且也解决了关键字声明方式的一些麻烦事儿。箭头函数内部没有arguments,也没有prototype属性,所以不能用new关键字调用箭头函数。
  箭头函数的书写方式:参数 => 函数体。

let add = (a,b) => {
    return a+b;
}
let print = () => {
    console.log('hi');
}
let fn = a => a * a;
//当只有一个参数时,括号可以省略,函数体只有单行return语句时,大括号也可以省略,强烈建议不要省略它们,是真的难以阅读

当函数需要直接返回对象时,你必须使用小括号把对象包裹起来。否则将抛出错误。

const fn = () =>{name:'ren',age:12};
// SyntaxError
*******************************************
const fn = () =>({name:'ren',age:12});

箭头函数和普通函数最大的区别在于其内部this永远指向其父级AO对象的this。
  普通函数在预编译环节会在AO对象上添加this属性,保存一个对象(请参照《JavaScript之深入对象(二)》)。每个普通函数在执行时都有一个特定的this对象,而箭头函数执行时并不直接拥有this属性,如果你在箭头函数中使用this,将根据函数作用域链,直接引用父级AO对象上this绑定的对象。普通函数的AO对象只有在函数执行时才产生,换言之,普通函数的this是由函数执行时的环境决定。而箭头函数的特别之处在于,当函数被定义时,就引用了其父级AO对象的this,即箭头函数的this由定义时的环境决定。
  根据箭头函数的特点,不难推测:如果定义对象的方法直接使用箭头函数,那么函数内的this将直接指向window。

var age = 123;
 let obj = {
     age:456,
     say:() => {
         console.log(this.age);
     }
 };
obj.say();   //123
//对象是没有执行期上下文的(AO对象),定义对象的方法实际上是在全局作用域下,即window

如果你一定要在箭头函数中让this指向当前对象,其实也还是有办法的(但是没必要这么麻烦啊,直接使用普通函数不是更好吗?):

var age = 123;
 let obj = {
     age:456,
     say:function(){
         var fn = () => {
         console.log(this.age);
        }
         return fn();
      }
 };
obj.say();  //456

我们来分析一下这是怎么做到的:首先,我们使用obj调用say方法时,say内创建了AO对象,并且该AO对象的this属性指向了obj(这里不明白的请回去复习一下我的《JavaScript之深入函数/对象》),然后,say内部又声明了一个箭头函数。我们说箭头函数在声明时就要强行引用父级AO的this属性,那么现在该箭头函数的父级AO是谁呢?当然就是say的AO啦,所以这里箭头函数的this直接就绑定了obj,最后箭头函数在执行时拿到的this,实际上就是say方法的AO.this,即obj本身。
  上面是在对象中使用箭头函数,如果那让你难于理解,那么请看下面这种方式:在普通函数中使用箭头函数。

var obj = {name:'ren'};
function test(){
    var fn = () => {
        console.log(this);
    };
    fn();
}
test();  //window
test.call(obj);  //{name:'ren'}

test函数在全局执行时,其this指向window,这时也产生了箭头函数的定义,于是箭头函数内的this也被指向了window,所以最终打印出window对象。
  当我们手动改变test函数执行时this的指向时,箭头函数定义所绑定的this实际上也被我们修改了。所以最终打印出obj。
四、class(类)  
  class 作为对象的模板被引入ES6,你可以通过 class 关键字定义类。class 的本质依然是一个函数。
  1,创建类

class Ex {   //关键字声明方式
    constructor(name){
        this.name = name;
        this.say = () => {
            console.log(this.name);
        }
    }
    methods(){
        console.log('hello ' + this.name);
    }
    static a = 123;
    static m = () => {
        console.log(this.a);
    };
}
//let ex = class{}  字面量方式
var example = new Ex('ren');
example.say();    //'ren'
Ex.m();   //123
example.methods();  //'hello ren'

constructor是创建类必须的方法,当使用new调用类创建实例时,将自动执行该方法,该方法和构造函数类似,默认返回this对象。实例的方法和属性都定义在constructor内部。相当于构造函数的this方式。
类保留了prototype属性,类中的方法不需要使用function关键字,并且方法之间不需要逗号隔开。类中定义的方法实际上还是保存在类的prototype属性上。
  创建实例依然使用new关键字。

2、类的继承

类的继承通过extends关键字实现。
class Person {
    constructor (name,age){
        this.name = name;
        this.age = age;
    }
    say(){
        console.log(this.name + ':' + this.age);
    }
}
class Student extends Person{
    constructor (name,age,sex){
        super(name,age);
        this.sex = sex;
    }
}
var student = new Student('ren',12,'male');
student.name;  //'ren'
student.sex;  //'male'
student.say();  //'ren:12'

子类继承自父类,不会隐式的创建自己的this对象,而是通过super()引用父类的this。这个过程和在子构造函数内使用父构造函数call(this)很像,但他们有本质的区别。另外,ES6规定,super()必须在子类的this之前执行。所以一般我们把super()放在子类constructor方法的第一行,这样准没错!
五、模块导入和导出
  1,导入
  ES6使用关键字 import 导入模块(文件),有两种常用的方式:

import ‘模块名称’ from ‘路径’;
import  ‘路径’;

通过 import...from 的方式引入模块,模块名称实际上相当于定义一个变量,用来接收即将导入的模块。
  路径可以有很多方式,既可以是绝对路径,也可以是相对路径,甚至只是一个简单的模块名称,更甚至连文件后缀都不需要。当你使用该命令时,系统会自动从配置文件中指定的路径中去寻找并加载正确的文件。

import Vue from "vue";
//完整路劲其实是 "../node_modules/vue/dist/vue.js";

通过 import... 的方式一般用来引入样式文件或预处理文件,因为他们不需要用变量来接收。
  2,导出
  ES6 通过 export 和export default 导出模块。导出的含义是向外暴露、输出,在一个文件中通过 import 导入另一个文件,通过变量即可以接收到导出的数据了。一般情况下,JS文件可以向外输出变量、函数和对象。

let name = 'ren',age = 12;
export {name,age};
//注意:变量需要用大括号包裹,然后才能向外输出

如果仅需向外暴露一个变量:

export var name = 'ren';

使用 export 向外输出函数的用法和变量相同,这里不再举例。
  总结:使用 export 向外输出成员时,可以同时输出多个,并且必须用‘{}’大括号包裹,在其他地方使用 import 导入时,接收成员的变量名必须和这里输出的名称一致,同时,可以根据实际情况,仅接收实际需要的的成员(接收的时候也要用大括号包裹)。
  如果希望通过 export 向外暴露成员,并且在导入的时候自定义接收名称,那么你可以使用 as 关键字重命名。

let name = 'ren', age = 12;
export {name, age};
 
import {name as myName, age as myAge} from 'url';

与 export 相比,export default 有以下几点不同:首先,在同一个模块中,export default 只允许向外暴露一次成员;然后,这种方式可以使用任意的名称接收,不像 export 那样有严格的要求;最后,export 和 export default 可以在同一模块中同时存在。


let person = {name:'ren'};
let age = 12;
let address = 'cd';
export default person;
export {age};
export {address};
 
import man,{age,address} from 'url'

小技巧:通常 import 无法直接被浏览器识别,即如果在HTML文档中引入的 JS 文件直接使用了 import 关键字,浏览器会报错。要想直接在被HTML文档引用的 JS 文件中使用 import,需要给该
六  异步机制
  ES6新增了两种实现异步的新机制,Promise和Generator。文笔有限,怕讲的不清楚,误人子弟,请有兴趣的同学去下面的链接继续学习,廖老师的教程也是受很多人推崇的,当然MDN更官方。
1,Promise
2,Generator

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,732评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,496评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,264评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,807评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,806评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,675评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,029评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,683评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 41,704评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,666评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,773评论 1 332
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,413评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,016评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,978评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,204评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,083评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,503评论 2 343

推荐阅读更多精彩内容