一、变量let、const:
var存在的问题:1、重复声明;2、函数级
经典案例:
<body>
<input type="button" value="1">
<input type="button" value="2">
<input type="button" value="3">
</body>
<script>
window.onload = function () {
//var aBtns = document.getElementsByTagName('input');
// 点击每个按钮都弹出“3”
// for (var i = 0, len = aBtns.length; i < len; i ++) {
// aBtns[i].onclick = function () {
// alert(i)
// }
// }
// 闭包处理点击分别弹出“0、1、2”
// for (var i = 0, len = aBtns.length; i < len; i ++) {
// (function(i) {
// aBtns[i].onclick = function () {
// alert(i)
// }
// })(i);
// }
// let 分别弹出“0、1、2”
// for (let i = 0, len = aBtns.length; i < len; i ++) {
// aBtns[i].onclick = function () {
// alert(i)
// }
// }
}
</script>
let : 不能重复声明、块级、变量
const: 不能重复声明、块级、常量
二、箭头函数=>
1.方便,简写规则:
(1)如果只有一个参数,()可以省
(2)如果只有一个return,{}也可以省
2.修正this
this相对正常点,指向问题、“箭头函数”的this,总是指向定义时所在的对象,而不是运行时所在的对象。
三、参数扩展:...
例子:
function show(a, b, ...arg) {
console.log(a);// 1
console.log(b); // 2
console.log(arg); // [3,4,5,6,7,8,89]
}
show(1, 2, 3, 4, 5, 6, 7, 8, 89);
let arr = [12, 5, 8];
let arr2 = [...arr, ...arr];
console.log(arr2); // [12, 5, 8, 12, 5, 8]
//解构 可以是嵌套数组、对象
let [a, b, c] = [1, 2, 3];
四、字符串
传统上,JavaScript 只有indexOf方法,可以用来确定一个字符串是否包含在另一个字符串中。ES6 又提供了三种新方法。
includes():返回布尔值,表示是否找到了参数字符串。
startsWith():返回布尔值,表示参数字符串是否在原字符串的头部。
endsWith():返回布尔值,表示参数字符串是否在原字符串的尾部。
let s = 'Hello world!';
s.startsWith('Hello') // true
s.endsWith('!') // true
s.includes('o') // true
这三个方法都支持第二个参数,表示开始搜索的位置。
let s = 'Hello world!';
s.startsWith('world', 6) // true
s.endsWith('Hello', 5) // true
s.includes('Hello', 6) // false
上面代码表示,使用第二个参数n时,endsWith的行为与其他两个方法有所不同。它针对前n个字符,而其他两个方法针对从第n个位置直到字符串结束
ES2017 引入了字符串补全长度的功能。如果某个字符串不够指定长度,会在头部或尾部补全。padStart()用于头部补全,padEnd()用于尾部补全。
'x'.padStart(5, 'ab') // 'ababx'
'x'.padStart(4, 'ab') // 'abax'
'x'.padEnd(5, 'ab') // 'xabab'
'x'.padEnd(4, 'ab') // 'xaba'
五、数组
1、map 映射 一个对一个
let arr = [1, 5, 7];
let result = arr.map(function(item) {
return item * 2;
})
// let result=arr.map(item=>item*2); // 简写
alert(result); // 2,10,14
let score = [30, 60, 100, 10, 80];
let result = score.map(item => item >= 60? '及格': '不及格');
console.log(score); // [30, 60, 100, 10, 80]
console.log(result) // ["不及格", "及格", "及格", "不及格", "及格"]
2、reduce 总汇:一堆 -> 一个(算总数、平均数等)
参数说明:*第一个参数是上次reduce函数运算的结果
*第二个参数是下次要参与运算的元素
let arr = [12, 69, 180, 8763];
let result = arr.reduce(function (tmp, item, index) {
console.log(`${tmp},${item},${index}`);// 12,69,1 81,180,2 261,8763,3
return tmp + item;
});
console.log(result); // 9024
3、filter 过滤: 一堆-> 剩下的
let arr = [
{title: '男士衬衫', price: 75},
{title: '女士包', price: 57842},
{title: '男士包', price: 65},
{title: '女士鞋', price: 27531}
];
let result = arr.filter(item => item.price > 10000)
console.log(result);// [{title: '女士包', price: 57842},{title: '女士鞋', price: 27531}]
4、forEach 循环(迭代)
let arr = [12, 5, 8];
arr.forEach((item, index) => {
if (index > 1) {
// break; // 报错 不能用在function中
// continue; // 报错 不能用在function中
//return; // 0:12 1:5
}
console.log(`${index}:${item}`);// 0:12 1:5 2:8
});
5、includes数组是否包含某个东西
该方法的第二个参数表示搜索的起始位置,默认为0。如果第二个参数为负数,则表示倒数的位置,如果这时它大于数组长度(比如第二个参数为-4,但数组长度为3),则会重置为从0开始。
[1, 2, 3].includes(3, 3); // false
[1, 2, 3].includes(3, -1); // true
6、 keys/values/entries
它们都返回一个遍历器对象,可以用for...of循环进行遍历,唯一的区别是keys()是对键名的遍历、values()是对键值的遍历,entries()是对键值对的遍历。
for (let index of ['a', 'b'].keys()) {
console.log(index);
}
// 0
// 1
for (let elem of ['a', 'b'].values()) {
console.log(elem);
}
// 'a'
// 'b'
for (let [index, elem] of ['a', 'b'].entries()) {
console.log(index, elem);
}
// 0 "a"
// 1 "b"
五、Promise(封装异步操作);
// 1、基本用法
let promise = new Promise((resolve, reject) => {
$.ajax({
url: 'url',
dataType: 'json',
success(res) {
resolve(res);
},
error(err) {
reject(err);
}
})
})
promise.then(res => {
console.log(res); // 成功
}, err => {
console.log(err);// 失败
})
//2、 Promise.all,在一个接口中用到另一个接口中的数据
Promise.all([
$.ajax({url: 'url', dataType: 'json'}),
$.ajax({url: 'url', dataType: 'json'})
]).then(results => {
let [data1, data2] = results;
console.log(data1, data2);
}, () => {
alert('失败了');
});
六、generator生成器 yield表达式;
function* show(num1, num2) {
console.log(`${num1}, ${num2}`); // 6,2
let n1 = num1 + num2;
let a = yield n1;
console.log(a); // 2
let n2 = num1 - num2;
let b = yield n2;
console.log(b) // 3
let n = n1 * n2;
return n;
}
let gen = show(6, 2);
console.log(gen.next(1)); // {value: 8, done: false}
console.log(gen.next(2)); // {value: 4, done: false}
console.log(gen.next(3)); // {value: 32, done: true}
console.log(gen.next(4)); // {value: undefined, done: true}
function *show() {
yield $.ajax({url: 'url', dataType: 'json'});
return $.ajax({url: 'url', dataType: 'json'})
}
let genObj = show();
console.log(genObj.next()); // {value: {…}, done: false}
console.log(genObj.next()); // {value: {…}, done: true}
七、async await
与generator对比:1.不依赖于外部的runner了——统一、性能2.可以用箭头函数;
八、面向对象 类 Class
/* 类Class */
// 先看 原型-面向对象
// 定义一个用户类
function User (name, phone) {
this.name = name || 'user'; // 属性
this.phone = phone || '000'; // 属性
this.showName = function () {
console.log(`姓名:${this.name}`);
}
}
User.prototype.showUserInfo = function (id) {
console.log(`ID:${id}/姓名:${this.name}/手机号:${this.phone}`);
}
let user = new User('小明', '110');
console.log(user);
user.showName();
user.showUserInfo('666');
// 定义一个vip用户子类
function VipUser(name, phone, level) {
User.call(this, name, phone, level);
this.level = level;
}
VipUser.prototype = new User(); // 将父级实例作为子类的原型
VipUser.prototype.constructor = VipUser; // 需要修复构造函数指向
VipUser.prototype.showVipInfo = function() { // 箭头函数会造成this指向问题
console.log(`姓名:${this.name}/会员等级:${this.level}颗星/手机号:${this.phone}`)
}
let v1 = new VipUser ('老王', '12345678', '10')
console.log(v1);
v1.showUserInfo(123);
v1.showVipInfo();
//对比
// es6 写法
class User {
constructor(name, phone) {
this.name = name || 'user'; // 属性
this.phone = phone || '000'; // 属性
}
showName () {
console.log(`姓名:${this.name}`);
// this.showPhone();
// User.showPhone(this.phone);
}
static showPhone(phone) { // 只能内部使用,不能通过this/实例化方法调用
// console.log(`手机号:${this.phone}`);
console.log(`手机号:${phone}`);
}
showUserInfo (id) {
console.log(`ID:${id}/姓名:${this.name}/手机号:${this.phone}`);
}
}
let user = new User('小明', '110');
console.log(user);
user.showName();
// user.showPhone();
user.showUserInfo('666');
class VipUser extends User {
constructor(name, phone, level) {
super(name, phone);
this.level = level;
}
showVipInfo () {
console.log(`姓名:${this.name}/会员等级:${this.level}颗星/手机号:${this.phone}`)
}
}
let v1 = new VipUser ('老王', '12345678', '10')
console.log(v1);
v1.showUserInfo(123);
v1.showVipInfo();
九、JSON
JSON.stringify({a:12,b:5}) => '{"a":12,"b":5}' // 从一个对象中解析出字符串
JSON.parse('{"a":12,"b":5}')=> {a:12,b:5} // 从一个字符串中解析出JSON对象
十、Symbol
ES6 引入了一种新的原始数据类型Symbol,表示独一无二的值。它是 JavaScript 语言的第七种数据类型,前六种是:undefined、null、布尔值(Boolean)、字符串(String)、数值(Number)、对象(Object)。作用:作为对象属性的唯一标识符,防止对象属性冲突发生。
// let a = Symbol();
// let b = Symbol();
// console.log(a === b); // false
// console.log(typeof(a)); // symbol
// let obj = {};
// let isOk = Symbol();
// obj[isOk] = 'ok';
// console.log(obj[isOk]); // ok
// console.log(obj.isOk); // undefined 不能用点
//Symbol.for会根据给定的键 key,来从运行时的 symbol 注册表中找到对应的 symbol,
//如果找到了,则返回它,否则,新建一个与该键关联的 symbol,并放入全局 symbol 注册表中。
// let sym = Symbol('abc');
// let sym1 = Symbol.for('abc');
// let sym2 = Symbol.for('abc');
// console.log(sym === sym1); // false
// console.log(sym1 === sym2);// true
十一、Iterator
JavaScript 原有的表示“集合”的数据结构,主要是数组(Array)和对象(Object),ES6 又添加了Map和Set。这样就有了四种数据集合,用户还可以组合使用它们,定义自己的数据结构,比如数组的成员是Map,Map的成员是对象。这样就需要一种统一的接口机制,来处理所有不同的数据结构。
遍历器(Iterator)就是这样一种机制。它是一种接口,为各种不同的数据结构提供统一的访问机制。任何数据结构只要部署 Iterator 接口,就可以完成遍历操作(即依次处理该数据结构的所有成员)。
Iterator 的作用有三个:一是为各种数据结构,提供一个统一的、简便的访问接口;二是使得数据结构的成员能够按某种次序排列;三是 ES6 创造了一种新的遍历命令for...of循环,Iterator 接口主要供for...of消费。
Iterator 的遍历过程是这样的。
(1)创建一个指针对象,指向当前数据结构的起始位置。也就是说,遍历器对象本质上,就是一个指针对象。
(2)第一次调用指针对象的next方法,可以将指针指向数据结构的第一个成员。
(3)第二次调用指针对象的next方法,指针就指向数据结构的第二个成员。
(4)不断调用指针对象的next方法,直到它指向数据结构的结束位置。
每一次调用next方法,都会返回数据结构的当前成员的信息。具体来说,就是返回一个包含value和done两个属性的对象。其中,value属性是当前成员的值,done属性是一个布尔值,表示遍历是否结束。
for...of...不能循环对象是因为
Iterator 接口的目的,就是为所有数据结构,提供了一种统一的访问机制,即for...of循环(详见下文)。当使用for...of循环遍历某种数据结构时,该循环会自动去寻找 Iterator 接口。
原生具备 Iterator 接口的数据结构如下。
Array
Map
Set
String
TypedArray
函数的 arguments 对象
NodeList 对象
没有提供Object的数据机构接口
十二、Set 和 Map 数据结构
ES6 提供了新的数据结构 Set。它类似于数组,但是成员的值都是唯一的,没有重复的值。Set 本身是一个构造函数,用来生成 Set 数据结构。
let a = new Set([1, 2, 3]);
let b = new Set([5, 3, 2]);
// 并集
let union = new Set([...a, ...b]);
console.log(union);// Set {1, 2, 3, 4}
// 交集
let intersect = new Set([...a].filter(x => b.has(x)));
console.log(intersect)// set {2, 3}
JavaScript 的对象(Object),本质上是键值对的集合(Hash 结构),但是传统上只能用字符串当作键。这给它的使用带来了很大的限制。
const data = {};
const element = document.getElementById('myDiv');
data[element] = 'metadata';
data['[object HTMLDivElement]'] // "metadata"
上面代码原意是将一个 DOM 节点作为对象data的键,但是由于对象只接受字符串作为键名,所以element被自动转为字符串[object HTMLDivElement]。
为了解决这个问题,ES6 提供了 Map 数据结构。它类似于对象,也是键值对的集合,但是“键”的范围不限于字符串,各种类型的值(包括对象)都可以当作键。也就是说,Object 结构提供了“字符串—值”的对应,Map 结构提供了“值—值”的对应,是一种更完善的 Hash 结构实现。如果你需要“键值对”的数据结构,Map 比 Object 更合适。
const m = new Map();
const o = {p: 'Hello World'};
m.set(o, 'content')
console.log(m); // Map(1) {{…} => "content"}
console.log(m.get(o)); // "content"
console.log(m.has(o)); // true
m.delete(o);
console.log(m.has(o)) // false
上面代码使用 Map 结构的set方法,将对象o当作m的一个键,然后又使用get方法读取这个键,接着使用delete方法删除了这个键。
网友评论