ECMAScript 和 JavaScrip的关系
简单的说ECMA 是一个标准,任何语言都可以去实现这个标准,但目前为止只有javascript 实现了。所以也就默认认为ECMAScript就是javascript。
ECMAScript 简称 ECMA 或 ES。
ECMAScript 历史版本
1996, ES1.0 Netscape 将 JS 提交给 ECMA 组织,ES 正式出现
1999, ES3.0 被广泛支持
2011, ES5.1 成为 ISO 国际标准
2015, ES6.0 正式发布
ES6(ES2015) 支持的环境 IE10+, Chrome, FireFox, 移动端, NodeJS
解决不兼容办法,编译、转换
<script src="browser.js" charset="utf-8">script>
<script type="text/babel">
let a = 3;
let b = 6;
script>
let 和 const
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Documenttitle>
<script>
window.onload= function () {
var aBtn = document.getElementsByTagName('input')
for (var i = 0; i < aBtn.length; i++) {
(function (i) {
aBtn[i].onclick = function () {
alert(i)
}
})(i)
}
}
script>
head>
<body>
<input type="button" value="按钮1">
<input type="button" value="按钮2">
<input type="button" value="按钮3">
body>
html>
ES6
在ES6中,直接将变量声明var
改为let
就解决了。
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Documenttitle>
<script>
window.onload= function () {
var aBtn = document.getElementsByTagName('input')
for (let i = 0; i < aBtn.length; i++) {
aBtn[i].onclick = function () {
alert(i)
}
}
script>
head>
<body>
<input type="button" value="按钮1">
<input type="button" value="按钮2">
<input type="button" value="按钮3">
body>
html>
普通函数
function name(){
...
}
匿名函数
function(){
}
去掉关键字function
和函数名,使用=>
连接参数列表和函数体。
let name = () =>{
....
}
1.如果只有一个参数,() 可以省;没有参数,()不能省
let show1 = function () {
console.log('abc')
}
可以写成
let show1 = () => {
console.log('abc')
}
let show2 = function(a){
return a*2;
}
可以写成
let show2 = a=>{
return a*2;
}
2.如果只有一个return,{}可以省,return可以省
let show = function (a) {
return a*2
}
可以写成
let show = a => a * 2
ES5:
ES5中我们使用函数中的类数组对象argments可以获取所有参数。
如果要获取传入的多余参数,这如下。
function show(a,b){
for(var i=arguments.length-show.length-2,len=arguments.length;i<len; i++){
console.log(arguments[i]);
}
}
show(1,2,3,4,5,6,7);
ES6:
在参数列表中使用..args
可以将多余的参数装入到数组args
中,再使用..args
就可以将数组展开。
在ES6要获取传入的多余参数很简单,使用...args收集多余的参数
function show(a, b, ...args) {
console.log(a)
console.log(b)
console.log(args)
}
console.log(show(1, 2, 3, 4, 5)) 输出3,4,5
参数展开
let arr1 = [1, 2, 3]
let arr2 = [4, 5, 6]
let arr3 = [...arr1, ...arr2]
console.log(arr3)
ES5:
function hello(txt){
var str = txt || 'hello poorpenguin';
}
ES6:
function hello(txt='hello poorpenguin'){
}
左右两个边结构必须一样
let [a, b, c] = [1, 2, 3]
console.log(a, b, c); 1 2 3
let {x, y, z} = {x: 1, y: 2, z: 3}
console.log(x, y, z);
let [{a4, b2}, [num1, num2, num3], num4 ,str2] = [{ a4: 1, b2: 2 }, [1, 2, 3], 8, 'str'];
console.log(a4, b2, num1, num2, num3, num4, str2);
可以自行选择解析的粒度
let [json, arr, num, str] = [{ a: 1, b: 2 }, [1, 2, 3], 8, 'str']
console.log(json, arr, num, str);
这样式错误的
let [a,b] = {a:12,b:45};
右边必须是合法的
这样式错误的
let {a,b} = {12,5}
声明和赋值赋值不能分开,必须在一句话
这种是错误的。
let [a,b];
[a,b] = [12,5];
ES6中新增了4个数组的方法
可以遍历一个数组,对数组中的值进行操作,不改变原数组,并返回一个新数组。
数组中的每一项都会作为回调函数的参数。使用return
才可以将值返回给新数组。
例子1:
let arr = [2,6,1,40];
let newArr = arr.map(function(item){
return item*3;
});
console.log(newArr);
输出[6, 18, 3, 120]
可以使用ES6函数简写:
let newArr = arr.map((item)=>item*3);
例子2:
let score = [19,60,56,80,100]; 学生成绩
let result = score.map((item)=>item>=60?'及格':'不及格');
console.log(result);
和学生的成绩一一对应["不及格", "及格", "不及格", "及格", "及格"]
例子1:求和
var arr = [22,33,12,67,98];
temp为回调函数中上一次的返回值,第一次temp的值为arr[0]
item为数组项
index为item的下标
var result = arr.reduce(function(temp, item, index){
return temp+item;
});
console.log(result);
232
ES6简写
var result = arr.reduce((temp, item, index)=>temp+item);
例子2:求平均值
前几次都是求和,在最后一次才求平均值
var arr = [22,33,12,67,98];
var result = arr.reduce(function(temp, item, index){
if(index!=arr.length-1){
return temp+item;
}else{ 最后一次加完并求平均值
return (temp+item)/arr.length-1;
}
});
console.log(result);
45.4
ES6简写:
var result = arr.reduce(
(temp, item, index)=>(index!=arr.length-1)?temp+item:(temp+item)/arr.length-1
);
通过回调函数return
返回的值来决定值是否保留,true
保留;false
过滤掉。
不改变原数组,并返回一个新数组。
例子1:保留能被3整除的数
let arr=[12,34,23,67,23,89,15];
let result = arr.filter(item=>item%3==0);
console.log(result);
例子2:商品价格过滤
let arr=[
{title: '男士衣服1', price:200},
{title: '男士衣服2', price:240},
{title: '女生衣服1', price:2000},
{title: '女生衣服2', price:3000},
{title: '女生衣服3', price:4000},
];
let result = arr.filter(item=>item.price<1000);
console.log(result);
forEach
有两个参数,第二个参数是下标,可加可不加。
var arr = [32, 12, 45, 9];
var result = arr.forEach(item => console.log(item));
var result = arr.forEach((item, index)=>console.log(item, index));
true
,否返回false
;true
,否返回false
;startsWith()
和endsWith()
就是可判断字符串是否以规定的字符串开头和结尾。
例子1:判断网址是什么类型的
代替了之前使用正则判断。
let str='https://www.baidu.com';
if(str.startsWith('https://')){
console.log('加密网址');
}else if(str.startsWith('http://')){
console.log('普通网址');
}else if(str.startsWith('git://')){
console.log('普通网址');
}else if(str.startsWith('svn://')){
console.log('普通网址');
}
例子2:判断文件类型
根据扩展名。也是代替了正则判断。
let str = 'test.txt';
if(str.endsWith('.jpg')){
console.log('图片文件');
}else if(str..endsWith('.txt')){
console.log('文本文件');
}else{
console.log('其他');
}
该功能很强大,很好用。
let a = 12
let str1 = `asdf${a}`
console.log(str1)
输出asdf12
let title = '标题'
let content = '内容'
let str = `
${title}
${content}
`
console.log(str)
输出
<div>
<h1>标题</h1>
<p>内容</p>
ES5
ES5的面向对象是没有类这个概念的。
function Person(name,age){
this.name=name||'未知';
this.age=age||18;
}
Person.prototype.sayHello(){
console.log('你好我是'+this.name);
}
var user = new Person('poorpenguin',25);
user.sayHello();
ES6
而ES6中的面向对象很像java。
class
constructor
构造器 class Person{
构造函数
constructor(name, age){
this.name=name||'未知';
this.age=age||18;
}
方法
sayHello(){
console.log('你好我是'+this.name);
}
}
var user = new Person('poorpenguin',25);
user.sayHello();
ES5中的继承其实就是各种方法凑合出来的,写起来脑壳疼。
ES6的继承更像java。
extends
继承。super
调用父类(超类)构造器。 class User{
constructor(name, age){
this.name = name;
this.age = age;
}
sayHi(){
console.log('你好,我是'+this.name);
}
}
class VipUser extends User{
constructor(name, age, level){
super(name, age);
this.level = level;
}
sayLevel(){
console.log('vip等级'+this.level);
}
}
var user = new VipUser('poorpenguin',25,3);
user.sayHi(); 你好,我是poorpenguin
user.sayLevel(); vip等级3
json是一种格式,我们经常在js中写的对象就是json格式的。
1.json的转换的常用方法(ES5中就有的)
{}
中所有的key都必须用双引号包起来。{}
中只能使用双引号。 json字符串的正确格式
var str1 = '{"a":12,"b":15,"c":"str"}'; √
var str2 = '{a:12,b:15,c:"str"}'; ×
json——>字符串
var str = 'hi,' + JSON.stringify(json)
如果想要将json转为字符串作为参数,必须使用 encodeURIComponent()将json字符串进行编码
var json = {a: 12, b: 5}
var url = 'http://www.xx.com/' + encodeURIComponent(JSON.stringify(json))
console.log(str)
console.log(url)
字符串——>json
var str = '{"a": 12, "b": 4, "c": "abc"}'
var json = JSON.parse(str)
冒号:
和function
var a = 12, b = 5
var obj1 = {a:a,b:b};
简写
var obj1 = {a,b};
var obj3 = {
name: 'poorpenguin',
age: 25,
say: function(){
console.log('hello world!');
}
}
简写
var obj3 = {
name: 'poorpenguin',
age: 25,
say(){
console.log('hello world!');
}
}
Promise就是异步解决方案,他是一个代理对象,和原先要进行的操作无关,使用它只是避免产生回调地狱。
Promise对象有三种状态:
执行器中的代码在new Promise()
时,就立即执行了。
new Promise(
//执行器
function(resolve, reject){
//异步操作
if(数据处理结果){ 成功
resolve();
}else{ 失败
reject();
}
}
).then(function(){
//成功,下一步
},function(){
//失败,相应处理
});
刚开始实例化Promise对象时,它的状态是pending。
当在执行器中调用resolve()
时,Promise实例对象的状态被改为fulfilled。
当在执行器中调用reject()
时,Promise实例的状态被改为rejected。
Promise实例的状态发生改变,就会立即触发then()
里对应的处理函数(回调函数)。
let p1 = new Promise(function(resolve, reject){
使用setTimeout模拟异步操作
setTimeout(function(){
console.log('异步操作执行成功!');
resolve('这是返回的数据');
},2000);
});
我们会发现在实例化promise
对象的候秒钟,控制台就输出结果。但是我们并没有调用。
所以建议使用函数将new Promise
包裹起来并return promise实例化出来的对象
,需要的时候再调用。
function run(){
let p1 = new Promise(function(resolve, reject){
//使用setTimeout模拟异步操作
setTimeout(function(){
console.log('异步操作执行成功!');
if(true){
resolve('这是返回的数据');
}else{
reject();
}
},2000);
});
return p1;
}
run().then(function(data){
console.log('对'+data+'做了其他操作');
},function(data){
});
then()
接收两个函数作为参数,分别代表fulfilled和rejected两个状态的响应函数then()
返回一个新的Promise实例,所以可以链式调用。then()
会根据最终状态,调用特定的响应函数。(不管哪一级的then()
都遵循)then()的返回值的三种情况:
return 新的promise
。下一级then()
等待return 新的promise 状态改变后再根据状态执行。 function run(){
let p1 = new Promise(function(resolve, reject){
setTimeout(function(){
console.log('异步执行完成!');
if(true){
resolve(1);
}else{
reject();
}
},2000);
});
return p1;
}
run().then(function(data){
console.log('获得'+data+',并作为数据执行下一步');
return new Promise(function(resolve, reject){
if(data == 1){
resolve(2);
}
});
}).then(function(data){
console.log('获得'+data+',并作为数据执行下一步');
return new Promise(function(resolve, reject){
if(data == 2){
resolve(3);
}
});
}).then(function(data){
console.log('获得'+data+',结束');
});
then()
中没有return
。下一个then()
得到的值就是underfined
function run(){
let p1 = new Promise(function(resolve, reject){
setTimeout(function(){
console.log('异步执行完成!');
if(true){
resolve(1);
}else{
reject();
}
},2000);
});
return p1;
}
run().then(function(data){
console.log(data); 1
}).then(function(data){
console.log(data); underfined
})
return
非promise。那么值就是这个非promise。 function run(){
let p1 = new Promise(function(resolve, reject){
setTimeout(function(){
console.log('异步执行完成!');
if(true){
resolve(1);
}else{
reject();
}
},2000);
});
return p1;
}
run().then(function(data){
console.log('1');
return 'poorpenguin';
}).then(function(data){
console.log('2');
return data;
}).then(function(data){
console.log('3');
console.log(data); poorpenguin
});
var promise = Promise.all( [p1, p2, p3] )
promise.then(
...
).catch(
...
)
当p1、p2、p3的状态都变成fulfilled时,父promise才会变成fulfilled,并调用then()的已完成回调,但只要有一个子promise变成rejected状态,父promise就会立刻变成rejected状态
和Promise.all()差不多,很少用。
只要有一个子Promise状态变成fulfilled时,父promise的状态就为fulfilled。
$.ajax()
的返回值就是Promise实例
let promise = $.ajax({url:'.....',dataType: 'json'});
所以
Promise.all([
$.ajax({url:'.....',dataType: 'json'}).
$.ajax({url:'.....',dataType: 'json'}),
$.ajax({url:'.....',dataType: 'json'}),
]).then(function(data){
let [arr1, arr2, arr3] = data;
console.log(arr1, arr2, arr3);
});