es6 兼容性 如何使用babel来编译我们的js(es6)代码
首先来谈一下es6 es6在大多数情况是没问题,据了解国内的环境,大部分业务(银行系统除外)支持到IE8就可以了,如果要兼容到IE6+,可以借助babel插件来完成,只要babel支持的都没问题的。
ES6新特性在Babel下的兼容性列表
ES6特性 | 兼容性 |
---|---|
箭头函数 | 支持 |
类的声明和继承 | 部分支持,IE8不支持 |
增强的对象字面量 | 支持 |
字符串模板 | 支持 |
解构 | 支持,但注意使用方式 |
参数默认值,不定参数,拓展参数 | 支持 |
let与const | 支持 |
for of | IE不支持 |
iterator, generator | 不支持 |
模块 module、Proxies、Symbol | 不支持 |
Map,Set 和 WeakMap,WeakSet | 不支持 |
Promises、Math,Number,String,Object 的新API | 不支持 |
export & import | 支持 |
生成器函数 | 不支持 |
数组拷贝 | 支持 |
那么我们来说一下如何使用这个babel来兼容我们的es6 代码(当然前提是babeljs文件已经存在在项目中,这里只是说明如何在webpack中让babel编译我们的js或者是jsx文件)
上一小小段代码:
module: {
loaders: [
//
{
test: /\.(jsx|js)$/,
loader: ['babel-loader'],
exclude: /node_modules/
}
]
}
一般处理我们的打包文件,我们都会放在module下的loader里去处理,上段代码中将以jsx/js为结尾的文件都会做一个babel来编译。
es6好用的新特性
1.var let const
在之前的js的版本中,我们多会选择用var来声明定义一个变量,这么做的弊端会造成浪费和占用了大量内存,在新的js版本es6中出现了两个新的用来声明标识符的方式:let 和 const
其实很好理解let其实定义了一个拥有着自己代码块的变量,所谓代码块其实就是当你在一个{}中使用let 定义一个变量后,let只在{}中存在,但是与js的函数作用域不同的是let定义的变量不会被提升。
var a = 1;
function fn1(){
console.log(a);
a = 2;
}
console.log(a);//1
fn1(); // 2
var b = 2;
function fn2(){
console.log(b);
let b = 1;
}
console.log(b)//2
fn2(); //
从这个例子中我们可以看到分别打印a,b变量 用let改的值在出了函数{}后失去了作用,而不是用let的赋值在出了{}后依然生效。
再举一个好用的应用场景,我们在一些特定需求时,会避免不了使用闭包,不了解闭包请移步跨域 闭包 ,例如一个常见的烂大街的问题,一个ul里的li打印它的索引或者内容。在es5中我们是这样做的:
var arr = [];
for(var i=0; i<5; i++){
arr.push((function (a){
return function (){
console.log(a);
}
})(i))
}
arr[1]() // 1
arr[2]() // 2
arr[3]() // 3
闭包的缺点时会占用内存不是放掉,那么我们来换一种写法:
var arr = []; // let arr = [] 都可以
for(let i=0; i<5; i++){
arr.push(function (){
console.log(i)
})
}
arr[0]() // 0
arr[1]() // 1
arr[2]() // 2
使用let会完美的解决这个问题。
再说说const就很好理解了,它就是定义一个常量的声明方式,拥有其他语言基础这个概念就不难理解,再次就不在做多余赘述。
2.解构赋值
ES6 允许按照一定模式,从数组和对象中提取值,对变量进行赋值,这被称为解构(Destructuring)。
let [a, b, c] = [1, 2, 3];
//等同于
let a = 1;
let b = 2;
let c = 3;
对象的解构赋值:获取对象的多个属性并且使用一条语句将它们赋给多个变量。
var {
StyleSheet,
Text,
View
} = React;
等同于
var StyleSheet = React.StyleSheet;
var Text = React.Text;
var View = React.View;
3.箭头函数
ES6中新增箭头操作符用于简化函数的写法,操作符左边为参数,右边为具体操作和返回值。
var sum = (num1, num2) => { return num1 + num2; }
//等同于
var sum = function(num1, num2) {
return num1 + num2;
};
同时箭头函数还有修复了this的指向,使其永远指向词法作用域:
var obj = {
birth: 1990,
getAge: function () {
var b = this.birth; // 1990
var fn = () => new Date().getFullYear() - this.birth; // this指向obj对象
return fn();
}
};
obj.getAge(); // 25
4.类 class
ES6提供了更接近传统语言的写法,引入了Class(类)这个概念,作为对象的模板。通过class关键字,可以定义类,与多数传统语言类似。
//定义类
class Point {
constructor(x, y) {
this.x = x;
this.y = y;
}
toString() {
return '(' + this.x + ', ' + this.y + ')';
}
}
同样的继承使用的是extends关键字
5.字符串
新增字符串处理函数:
startsWith() //检查是否以指定字符串开头,返回布尔值
let str = 'javascript';
str.startsWith('java');
endsWith() //检查是否以指定字符串结尾,返回布尔值
let str = 'javascript'
str.endsWith('pt');
includes() //检查字符串是否包含指定字符串 ,返回布尔值
let str = 'javascript';
str.includes('j');
repeat() //指定字符串重复次数
let str = 'javascript';
str.repeat('3');
Template Literals 字符串模板
使用 字符串模板字面量,我可以在字符串中直接使用特殊字符,而不用转义。
var text = "This string contains \"double quotes\" which are escaped.";
let text = `This string contains "double quotes" which don't need to be escaped anymore.`;
字符串模板字面量 还支持直接插入变量,可以实现字符串与变量的直接连接输出.
var name = 'Tiger';
var age = 13;
console.log('My cat is named ' + name + ' and is ' + age + ' years old.');
更简单的版本:
const name = 'Tiger';
const age = 13;
console.log(`My cat is named ${name} and is ${age} years old.`);
ES5中,我们要这样生成多行文本:
var text = (
'cat\n' +
'dog\n' +
'nickelodeon'
);
或者:
var text = [
'cat',
'dog',
'nickelodeon'
].join('\n');
字符串模板字面量 让我们不必特别关注多行字符串中的换行转义符号,直接换行即可:
let text = ( `cat
dog
nickelodeon`
);
字符串模板字面量 内部可以使用表达式,像这样:
let today = new Date();
let text = `The time and date is ${today.toLocaleString()};
6.第七种基本类型 Symbol
Symbols和其它基本类型大不一样。
从创建开始就是不可变的。你不能为它设置属性(如果你在严谨模式下尝试,会报类型错误)。它可以作为属性名。这是它的类字符串性质。
另一方面,每一个symbol都是唯一的。与其他的不同(就算他们的描述是一样的)你可以很容易地新创建一个。这是它的类对象性质。
ES6 symbols与Lisp和Ruby中的更传统的symbols很类似,但是没有如此紧密地集成到语言中。在Lisp中,所有的标识符都是symbols。在JS中,标识符和大多数属性的键值的首先仍是字符串,Symbols只是为开发人员提供了一个额外选择。
关于symbols的一个忠告:与JS中的其它类型不同,它不能被自动转换为字符串。试图拼接symbol与字符串将会引起类型错误。
(表示读过文档后依然蒙圈 先选择性放弃这个点)
7.Promise
一个 Promise 对象可以理解为一次将要执行的操作(常常被用于异步操作),使用了 Promise 对象之后可以用一种链式调用的方式来组织代码,让代码更加直观。而且由于 Promise.all 这样的方法存在,可以让同时执行多个操作变得简单。接下来就来简单介绍 Promise 对象。
直观些直接上代码:
function helloWorld (ready) {
return new Promise(function (resolve, reject) {
if (ready) {
resolve("Hello World!");
} else {
reject("Good bye!");
}
});
}
helloWorld(true).then(function (message) {
alert(message);
}, function (error) {
alert(error);
});
上面的代码实现的功能非常简单,helloWord 函数接受一个参数,如果为 true 就打印 “Hello World!”,如果为 false 就打印错误的信息。helloWord 函数返回的是一个 Promise 对象。
在 Promise 对象当中有两个重要方法————resolve 和 reject。
resolve 方法可以使 Promise 对象的状态改变成成功,同时传递一个参数用于后续成功后的操作,在这个例子当中就是 Hello World!字符串。
reject 方法则是将 Promise 对象的状态改变为失败,同时将错误的信息传递到后续错误处理的操作。
Promise 的三种状态
上面提到了 resolve 和 reject 可以改变 Promise 对象的状态,那么它究竟有哪些状态呢?
Promise 对象有三种状态:
- Fulfilled 可以理解为成功的状态
- Rejected 可以理解为失败的状态
- Pending 既不是 Fulfilld 也不是 Rejected 的状态,可以理解为 Promise 对象实例创建时候的初始状态
helloWorld 的例子中的 then 方法就是根据 Promise 对象的状态来确定执行的操作,resolve 时执行第一个函数(onFulfilled),reject 时执行第二个函数(onRejected)。
then 和 catch
then
helloWorld 的例子当中利用了 then(onFulfilld, onRejected) 方法来执行一个任务打印 “Hello World!”,在多个任务的情况下 then 方法同样可以用一个清晰的方式完成。function printHello (ready) { return new Promise(function (resolve, reject) { if (ready) { resolve("Hello"); } else { reject("Good bye!"); } }); }
上述例子通过链式调用的方式,按顺序打印出了相应的内容。then 可以使用链式调用的写法原因在于,每一次执行该方法时总是会返回一个 Promise 对象。另外,在 then onFulfilled 的函数当中的返回值,可以作为后续操作的参数,因此上面的例子也可以写成:
printHello(true).then(function (message) {
return message;
}).then(function (message) {
return message + ' World';
}).then(function (message) {
return message + '!';
}).then(function (message) {
alert(message);
});
function printWorld () {
alert("World");
}
function printExclamation () {
alert("!");
}
printHello(true)
.then(function(message){
alert(message);
})
.then(printWorld)
.then(printExclamation);
同样可以打印出正确的内容。
catch
catch 方法是 then(onFulfilled, onRejected) 方法当中 onRejected 函数的一个简单的写法,也就是说可以写成 then(fn).catch(fn),相当于 then(fn).then(null, fn)。使用 catch 的写法比一般的写法更加清晰明确。
Promise.all 和 Promise.race
Promise.all 可以接收一个元素为 Promise 对象的数组作为参数,当这个数组里面所有的 Promise 对象都变为 resolve 时,该方法才会返回。
var p1 = new Promise(function (resolve) {
setTimeout(function () {
resolve("Hello");
}, 3000);
});
var p2 = new Promise(function (resolve) {
setTimeout(function () {
resolve("World");
}, 1000);
});
Promise.all([p1, p2]).then(function (result) {
console.log(result); // ["Hello", "World"]
});
上面的例子模拟了传输两个数据需要不同的时长,虽然 p2 的速度比 p1 要快,但是 Promise.all 方法会按照数组里面的顺序将结果返回。
日常开发中经常会遇到这样的需求,在不同的接口请求数据然后拼合成自己所需的数据,通常这些接口之间没有关联(例如不需要前一个接口的数据作为后一个接口的参数),这个时候 Promise.all 方法就可以派上用场了。
还有一个和 Promise.all 相类似的方法 Promise.race,它同样接收一个数组,不同的是只要该数组中的 Promise 对象的状态发生变化(无论是 resolve 还是 reject)该方法都会返回。
兼容性
最后是关于 Promise 对象的兼容性问题。
在浏览器端,一些主流的浏览器都已经可以使用 Promise 对象进行开发,在 Node.js 配合 babel 也可以很方便地使用。
如果要兼容旧的浏览器,建议可以寻找一些第三方的解决方案,例如 jQuery 的 $.Deferred。
今天的文章浅谈ES6 常用 新特性 并了解其兼容性解决方案分享到此就结束了,感谢您的阅读。
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
如需转载请保留出处:https://bianchenghao.cn/19297.html