es6中有哪些新特性:
新的变量声明方式 let/const
// 没有变量提升
console.log(a); //error
let a = 3;
// 增加了块级作用域
{
let b = 10
console.log(b);
}
console.log(b); // error
我们常常使用let来声明一个值会被改变的变量,而使用const来声明一个值不会被改变的变量,也可以称之为常量。
const a = 5;
a = 7; // Uncaught TypeError: Assignment to constant variable.
const b = {};
b.a = 5 ; //ok can change
b = []; // Uncaught TypeError: Assignment to constant variable.
如何实现const定义的引用类型也不能改变?
https://mathiasbynens.be/notes/es6-const
https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Object/freeze
// 结合freeze和const
const foo = Object.freeze({
'bar': 27
});
箭头函数的使用
//其次还有一个至关重要的一点,那就是箭头函数中,没有this。如果你在箭头函数中使用了this,那么该this一定就是外层的this。
var a = ()=> {
// do something
}
模板字符串
var a = 'world';
var b = `hello ${a}`;
解析结构
const props = {
className: 'tiger-button',
loading: false,
clicked: true,
disabled: 'disabled'
}
const {loading, clicked} = props;
默认参数
function add(num1=10,num2=20){
return num1 + num2;
}
扩展运算符
在ES6中用...
来表示展开运算符,它可以将数组方法或者对象进行展开
var a = [1,2,3];
var b = [...a, 4,5,6];
function addAll(...num){
return num.reduce((num1,num2)=>{return num1 + num2})
}
对象字面量简写
// 如果变量名和属性值相同时
var name = 'zhangzhuo';
var age = 18;
// es6
const person = {
name,
age
}
// es5
person1 = {
name: name,
age: age
}
// 在对象字面量中可以使用中括号作为属性,表示属性名也能是一个变量了。
const person = {
[name]: true,
[age]: true
}
class
// es6
class Person{
constructor(name, age){
this.name = name;
this.age = age;
}
sayName(){
console.log(this.name)
}
}
//es5
function Person(name, age){
this.name = name;
this.age = age;
}
Person.prototype.sayName = function(){
console.log(this.name)
}
继承extends
// es6
class Person{
constructor(name, age){
this.name = name;
this.age = age;
}
sayName(){
console.log(this.name)
}
}
class Student extends Person{
constructor(name, age, gender, classes) {
super(name, age);
this.gender = gender;
this.classes = classes;
}
getGender() {
return this.gender;
}
}
// es5
function Person(name, age){
this.name = name;
this.age = age;
}
Person.prototype.sayName = function(){
console.log(this.name)
}
function Student(name, age, gender, classes){
Person.call(this,name,age);
this.gender = gender;
this.classes = classes;
}
Student.prototype = new Person();
Student.prototype.constructor = Student;
Student.prototype.getGender = function(){
return this.gender;
}
Promise
var getJson = function(){
return new Promise(function(resolve,reject){
setTimeout(function(){
resolve(1000);
console.log(1)
}, 1000)
})
}
var getJson2 = function(){
return new Promise(function(resolve,reject){
setTimeout(function(){
resolve(1000);
console.log(2)
}, 1000)
})
}
getJson().then(function(){
return getJson2()
}).then(function(){
console.log(33333)
});
then之后return是一个新的promise
es7 Async/await语法
function getSomething() {
return "something";
}
async function testAsync() {
return Promise.resolve("hello async");
}
async function test() {
const v1 = await getSomething();
const v2 = await testAsync();
console.log(v1, v2);
}
test();
模块 modules
引入模块
import test from './test'
-
import
表示引入一个模块, - test 我们暂时理解为引入模块的名字,
- from表示从哪里引入
-
./test
为./test.js
的简写,表示将要引入模块的路径
对外提供接口
// test.js
const num = 20;
const arr = [1, 2, 3, 4];
const obj = {
a: 0,
b: function() {}
}
const foo = () => {
const a = 0;
const b = 20;
return a + b;
}
export default {
num,
arr,
obj,
foo
}
在test.js
中,我们使用export default
对包暴露了一个对象。他的意思就是当我们使用import test from './test'
时,这个test对象就默认等于export default
暴露的对象。
我们还可以在test.js中,仅仅通过export
暴露几个方法与属性,我们来看看index.js中test会变成什么样子。
// src/test.js
export const bar = () => {}
export const zcar = 12345;
保存运行后,我们发现,index.js中的test对象并没有变化,因为它仅仅等于export default
抛出的对象,因此,为了获得模块test.js
暴露的所有接口,我们得通过如下的方式。
// src/index.js
import * as test from './test';
其中的 *
表示所有,这是比较常用的通配符,as表示别名,* as test
的意思是将test.js暴露的所有接口组成的对象,命名为test。那么我们在index.js中log出test,结果就如下。
如果大家还记得前面一篇文章里,我所讲的ES6解析结构的语法,那么对于如下的用法相信就不难理解。
// src/index.js
import test, { bar, zcar } from './test';
console.log(test);
console.log('bar:', bar);
console.log('zcar:', zcar);
test,仍然表示为export default
暴露的对象,而 { bar, zcar }
则表示利用解析结构的语法,从整个返回对象中去取得对应的接口。输出结果也就很清晰了。
这种方式还是比较常见,比如我们在使用react时,常常这样使用:
import React, { Component } from 'react'
它其实暗示了React的封装方式,也暗示了我们应该如何去封装我们的模块。
webpack的优化
引用自https://segmentfault.com/a/1190000007891318
方案一、合理配置 CommonsChunkPlugin
webpack的资源入口通常是以entry为单元进行编译提取,那么当多entry共存的时候,CommonsChunkPlugin的作用就会发挥出来,对所有依赖的chunk进行公共部分的提取,但是在这里可能很多人会误认为抽取公共部分指的是能抽取某个代码片段,其实并非如此,它是以module为单位进行提取。
假设我们的页面中存在entry1,entry2,entry3三个入口,这些入口中可能都会引用如utils,loadash,fetch等这些通用模块,那么就可以考虑对这部分的共用部分机提取。通常提取方式有如下四种实现:
1、传入字符串参数,由chunkplugin自动计算提取
new webpack.optimize.CommonsChunkPlugin('common.js')
这种做法默认会把所有入口节点的公共代码提取出来, 生成一个common.js
2、有选择的提取公共代码
new webpack.optimize.CommonsChunkPlugin('common.js',['entry1','entry2']);
只提取entry1节点和entry2中的共用部分模块, 生成一个common.js
3、将entry下所有的模块的公共部分(可指定引用次数)提取到一个通用的chunk中
new webpack.optimize.CommonsChunkPlugin({
name: 'vendors',
minChunks: function (module, count) {
return (
module.resource &&
/\.js$/.test(module.resource) &&
module.resource.indexOf(
path.join(__dirname, '../node_modules')
) === 0
)
}
});
提取所有node_modules中的模块至vendors中,也可以指定minChunks中的最小引用数;
4、抽取enry中的一些lib抽取到vendors中
entry = {
vendors: ['fetch', 'loadash']
};
new webpack.optimize.CommonsChunkPlugin({
name: "vendors",
minChunks: Infinity
});
添加一个entry名叫为vendors,并把vendors设置为所需要的资源库,CommonsChunk会自动提取指定库至vendors中。
方案二、通过 externals 配置来提取常用库
在实际项目开发过程中,我们并不需要实时调试各种库的源码,这时候就可以考虑使用external选项了。
简单来说external就是把我们的依赖资源声明为一个外部依赖,然后通过script外链脚本引入。这也是我们早期页面开发中资源引入的一种翻版,只是通过配置后可以告知webapck遇到此类变量名时就可以不用解析和编译至模块的内部文件中,而改用从外部变量中读取,这样能极大的提升编译速度,同时也能更好的利用CDN来实现缓存。
external的配置相对比较简单,只需要完成如下三步:
1、在页面中加入需要引入的lib地址,如下:
2、在webapck.config.js中加入external配置项:
module.export = {
externals: {
'react-router': {
amd: 'react-router',
root: 'ReactRouter',
commonjs: 'react-router',
commonjs2: 'react-router'
},
react: {
amd: 'react',
root: 'React',
commonjs: 'react',
commonjs2: 'react'
},
'react-dom': {
amd: 'react-dom',
root: 'ReactDOM',
commonjs: 'react-dom',
commonjs2: 'react-dom'
}
}
}
适用场景
在实际的开发过程中,可灵活地选择适合自身业务场景的优化手段。
优化手段 | 开发环境 | 生产环境 |
---|---|---|
CommonsChunk | √ | √ |
externals | √ | |
DllPlugin | √ | √ |
Happypack | √ | |
uglify-parallel | √ |
工程演示demo
event中target和currentTarget的区别?
document.body.onclick = function(event){
}
this和currentTarget都等于document.body。 然而target指向真正触发的元素。
css让元素垂直居中
有2个元素,让子元素相对于父元素水平垂直居中。
css设置元素水平垂直居中显示
已知元素的宽度
1、利用定位及设置元素margin值为自身的一半
.box{
width: 400px;
height: 200px;
border: 5px solid #ddd;
margin: 50px auto;
position: relative;
}
.innerbox{
width: 300px;
height: 100px;
border: 5px solid #f00;
font-size: 16px;
position: absolute;
left: 50%;
top: 50%;
margin: -50px 0 0 -150px;
说明:此方法,在我们工作中经常用到,兼容性好。demo
2、margin:auto
.box{
width: 400px;
height: 200px;
border: 5px solid #ddd;
margin: 50px auto;
position: relative;
}
.innerbox{
position: absolute;
left: 0;
top: 0;
right: 0;
bottom: 0;
width: 300px;
height: 100px;
margin: auto;
border: 5px solid #f00;
}
说明: position: absolute; left: 0; right: 0; top: 0; bottom: 0;这是自动填充父元素的可用空间。然而给子元素设定了宽高,那么多余的空间,会被margin:auto平均分配。
实现未知元素宽高
1、利用css3属性transform实现
.box{
width: 400px;
height: 200px;
border: 5px solid #ddd;
margin: 50px auto;
position: relative;
}
.innerbox{
position: absolute;
left: 50%;
top: 50%;
border: 5px solid #f00;
transform: translate(-50%,-50%);
}
说明:这种方法在移动端被广泛使用。但是,只支持高版本浏览器(IE9+以上的浏览器支持)。
2、将父元素设置成display: table, 子元素设置为单元格 display: table-cell
这个方法跟上面介绍的方法不同,它不是让元素居中,而是让元素包含的内容居中
.box{
width: 400px;
height: 200px;
border: 5px solid #ddd;
margin: 50px auto;
display: table;
}
.innerbox{
display: table-cell;
vertical-align: middle;
text-align: center;
border: 5px solid #f00;
}
说明:利用表格的特性,将子元素看成行内元素,实现元素中的文字(文字可以是单行的,也可以是多行的)或图片水平垂直居中。demo
3、css3新的布局方法,弹性布局 display: flex
.box{
width: 400px;
height: 200px;
border: 5px solid #ddd;
margin: 50px auto;
display: flex;
align-items: center;
justify-content: center;
}
.innerbox{
width: 300px; /*宽度可以省略*/
height: 100px; /*高度可以省略*/
border: 5px solid #f00;
font-size: 16px;
}
说明: 此方法只支持IE9+以上的浏览器。display: flex代表弹性布局,align-items: center 代表垂直方向上的居中,justify-content: center代表水平方向上的居中。这些是css3中的新属性,感兴趣的同学可以查找相关资料学习。这里不多介绍。demo
移动端300ms延迟的解决方案
原来的解决方案:fastclick
其实现在已经不需要了, 浏览器自己做了处理:
https://developers.google.com/web/updates/2013/12/300ms-tap-delay-gone-away?hl=en
lib-flexible的多分辨率解决方案
引用项目里面的话https://github.com/amfe/lib-flexible
由于
viewport
单位得到众多浏览器的兼容,lib-flexible
这个过渡方案已经可以放弃使用,不管是现在的版本还是以前的版本,都存有一定的问题。建议大家开始使用viewport
来替代此方案。vw
的兼容方案可以参阅《如何在Vue项目中使用vw实现移动端适配》一文。
在内在都用vw单位了, 关于rem中的问题可以参考:谈谈 rem 与 vw -- rem