1.ES5
(1)严格模式 - js的一种更加严格的运行模式
在代码开头添加"use strict"
行为的变更:
- 全局变量声明时,必须加var
- 全局函数的this不会指向window,而是undefined
- 函数参数名不允许重复(非严格模式下,重名的话,后面的会覆盖前面的)
- 禁止使用with语句
- 修改形参的值,arguments不会改变
arguments对象不允许被自调用 - 新增保留字:implements,interface,let,package,private,protected,public,static,yield,…
很多保留字在ES6里已经实现了
使用严格模式的好处:
- 消除js语法中不合理的地方 - js被人诟病的一个地方就是作用域繁琐
- 让项目更安全
- 增加运行速度 - 因为语法要求高了
- js发展到现在,希望自己能成为世界上最牛的语言,所以也要升级,所以可以为之后的版本做铺垫
(2)ES5新增数组API:
①Array索引方法:
方法名 | 用法 | 语法 |
---|---|---|
indexOf | 通过值找到对应的下标(第一次出现)- 从左边开始找如果数组里不存在查找的值,得到-1 | 数组.indexOf(元素,[开始查找的起始下标]) |
lastIndexOf | 通过值找到对应的下标(最后一次出现)- 从右边开始找如果数组里不存在查找的值,得到-1 | 数组.lastIndexOf(元素,[开始查找的起始下标]) |
②Array迭代方法:
方法名 | 用法 | 语法 |
---|---|---|
every | 判断数组中是否每个元素都满足条件 - true/false | 数组.every(function(值v,下标i,数组本身){ 返回 一个条件 }); |
some | 判断数组中是否有一个值是满足条件的 - true/false | 数组.some(function(值v,下标i,数组本身){ 返回 一个条件 }); |
filter | 过滤数组元素将数组中满足条件的元素组成一个新的数组返回 | 数组.filter(function(值v,下标i,数组本身){ return 一个条件 }); |
map | 将数组中的每个值都交给一个函数去处理处理后的新的值组成一个新的数组返回 | var arr = 数组.map(function(值v,下标i,数组本身){ return 处理的逻辑 }); |
forEach | 专门用来遍历数组 | 数组.forEach(function(值v,下标i,数组本身){ 遍历以后的操作 }); |
③Array归并方法:
方法名 | 用法 | 语法 |
---|---|---|
reduce | 从左往右归并,遍历数组(计算数组的和);每一次迭代得到的结果都作为下一次迭代的初始值 | 数组.reduce(function(prev,curr,index,array){ }[,prev初始值]); //curr:从数组的第二项开始的每一个元素 //prev:第一次是第一个元素,第二次开始是这个函数的返回值 |
reduceRight | 从右往左归并 |
(3)json:
特点:
1.json格式字符串一定要加双引号
2.格式中不能有分号、js关键字
json对象:
js中的数组或者对象都可以是json对象
json字符串:
json格式的字符串叫做json字符串
字符串和对象的转换:
JSON.stringify() //将 对象或者数组 转换为 json 格式的字符串
JSON.parse() //将 json 格式的字符串 转换为 对象或者数组
(4)Object:
object.key()
object.values()
var obj = {
id:1,
title:'笔',
price:20,
num:2
}
var arr1 = Object.keys(obj)
console.log(arr1)
var arr2 = Object.values(obj)
console.log(arr2)
Object.keys(obj)得到的是obj对象所有 属性名 构成的数组
Object.values(obj)得到的是obj对象所有 属性值 构成的数组
var obj = new Object()
Object.defineProperty(obj,'name',{
value:'张三',
writable:false //false代表不可写,就是不能被修改,默认是false
configurable:false //表示时候可以通过delete删除此属性,默认为false
enumerable:true //表示是否可枚举,是否可以通过for in遍历到,默认是false
})
1.writable
obj.name = '李四'
2.configurable
delete obj.name
3.enumerable
for(var key in obj){
console.log(key,obj[key])
}
object.assign()
//合并对象:合并时如果遇到重复的属性,后面的覆盖前面的
Object.assign(obj1,obj2,obj3) //obj2和obj3合并到obj1上
//如果想合并到一个新的对象上
var obj4 = Object.assign({},obj1,obj2,obj3) //三个原对象都不会被修改
2.ES6 (ECMAScript2015):
(1)定义(let/const):
以前定义变量一直使用var关键字,es6中可以使用另外两个关键字let和const。
块级: if、for、switch、while、function都叫块(含有大括号)。
let是声明变量的关键字,特点:
- 不允许重复声明
- 不存在预解析(变量提升)
- 在大括号中声明的变量只能在大括号中使用,如if、for的大括号中声明的变量
var变量的特点:写入内存(垃圾回收机制);值可以改变;松散类型(声明无需确定类型);同时定义多个(逗号分隔);前置访问undefined(预解析)。
let案例:点击li弹出对应下标
const是声明常量的关键字,特点:
- 不允许重复声明
- 不允许重新赋值(可以给对象中新增属性)
const定义引用类型(数组,对象,函数)的数据的时候,可以修改数据内部结构,但是不能修改地址 - 声明的时候必须赋值
- 不存在预解析(变量提升)
- 在大括号中声明的变量只能在大括号中使用,如if、for的大括号中声明的变量
(2)扩展运算符(…):
把数组或类数组对象展开成一系列用逗号隔开的值。
function fn(a,b,c){
console.log(a+b+c)
}
var arr = [3,2,5]
fn(arr[0],arr[1],arr[2],) // 10
(...)运算符可以把数组展开:
fn(...arr) // 10
var arr1 = arr //这种写法赋值的是引用(地址)
var arr1 = [...arr] // 这种写法arr1和arr是两个值相同的数组
var obj = {
name:'张三',
age:18
}
var obj1 = {...obj} // 这种写法obj1和obj是两个值相同的对象
还可以继续进行加键值对:
var obj1 = {...obj,键:'值'}
(3)rest运算符(…):
rest运算符也是… 可以把一系列逗号隔开的值合并到数组里,跟扩展运算符正好相反。
function fn (...arr){
//可以把所有传进来的参数合并到arr
console.log(arr) //Array(5)
}
fn(3,6,2,6,3)
(4)ES6新增字符串API:
repeat()重复功能:
语法:var rest = 字符串.repeat(重复次数)
var str = 'hello word'
var str1 = str.repeat(3)
console.log(str1) //hello wordhello wordhello word
1.判断字符串是否以某个字符(子字符串)开头 - 返回布尔值
字符串.startsWith(字符)
字符串.startsWith(字符,索引)//判断字符串[索引]是否以某字符开头
2.判断字符串是否以谁结尾 - 返回布尔值
字符串.endsWith(字符)
字符串.endWith(字符,索引)//判断字符串[索引]是否以某字符前的字符结尾
3.判断字符串中是否包含某一个字符/子字符串 - 返回布尔值
字符串.includes(字符)
(5)for of:
for of 可以用来遍历字符串
var s = "abc"
for(let b of s){
console.log(b) // "a" "b" "c"
}
(6)模板字符串(``):
var num = 10
console.log('我要打' + num + '个')
consolo.log(`我要打${num}个`) //字符串模板可以把表达式放在${ }里,就可以解析
${ }里面可以写表达式:
var num = 20
var str1 = `我要打${num>10 ? '很多' : '0'}个`
console.log(str1)// 我要打很多个
${}里面可以函数调用,会被解析成函数的返回值:
function fn () {
return 20
}
var str2 = `我要打${fn()}个`
console.log(str2) // 我要打20个
如果字符串本身就有一个`,就要用\进行转义,要写成\`
var str3 = `hello \` world`
console.log(str3) // hello ` world
(7)箭头函数 ( ( ) => { } ):
es6中的箭头函数是用来简写函数的。
let fn = function(){
代码段
}
fn();
使用箭头函数:
let fn = () =>{
代码段
}
fn();
注意:如果只有一个形参的时候,小括号可以省略:
let fn = function(a){
console.log(a);
}
使用箭头函数:
let fn = a => {
console.log(a);
}
注意:如果代码块中只有一行代码,而且这句话就是return,箭头函数可以省略大括号以及return关键字:
let fn = function(a){
return a + 1;
}
使用箭头函数:
let fn = a => a+1;
注意:如果返回的是对象,则要再加一层()
在箭头函数中,没有this这个关键字
那么箭头函数中的this就代表:箭头函数所在作用域中的this(箭头函数中的this指的就是箭头函数上一行代码的this)
let obj = {
name:'zhangsan'
say:function(){
//这里的this指向obj,所以在这里把this存下来
const _this = this
setTimeout(function(){
console.log(this) //window
console.log(_this) //obj
console.log(_this.name) // zhangsan
},1000)
}
}
使用箭头函数:
let obj = {
name:'zhangsan'
say:function(){
setTimeout( () => {
//箭头函数没有自己的this
console.log(this) //obj
console.log(this.name) //zhangsan
},1000)
}
}
箭头函数的缺陷:
- 箭头函数不能new,它的设计初衷就跟构造函数不太一样
- 箭头函数如果要返回一个JSON对象,必须要用小括号包起来
var test = ( ) =>({id:3,val:20})
(8)this关键字:
this是js的关键字;只存在于函数内
函数内部的 this 只和函数的调用方式有关系,和函数的定义方式没有关系。
全局定义的函数直接调用,this => window
function fn() {
console.log(this)
}
fn()
// 此时 this 指向 window
定时器的处理函数,this => window
setTimeout(function () {
console.log(this)
}, 1000)
// 此时定时器处理函数里面的 this 指向 window
事件处理函数,this => 事件源
div.onclick = function () {
console.log(this)
}
// 当你点击 div 的时候,this 指向 div
// 不一定是事件源,谁绑定就指向谁
自调用函数,this => window
(function () {
console.log(this)
})()
// 此时 this 指向 window
自调用函数还可以在前面加 ! 或 ~
对象方法,this => 对象本身(当前实例对象)
var obj ={
name:'lisi'
say:function(){
console.log(this) // obj
}
}
(9)修改this指向:
①bind
function fn6(){
console.log(this);
}
fn6(); // window
var arr = [1,2,3];
var fn7 = fn6.bind(arr);
fn7(); // Array(1,2,3)
②call
function fn1(){
console.log(123);
}
// fn1();
fn1.call(); // 使用call方法调用函数和小括号调用时一样的
function fn2(){
console.log(this);
}
fn2.call([1,2,3]); // 打印结果就是这个数组
call的参数可以有若干个,第一个参数用来改变函数内的this指向,其余的函数是作为调用函数的实参:
function fn3(num1,num2){
console.log(this);
console.log(num1+num2);
}
// fn3(10,20);
var arr = [10,20];
fn3.call(arr,arr[0],arr[1]); //结果: Array 30
如果call没有参数或第一个参数为null,那么函数中的this执行window:
function fn4(){
console.log(this);
}
fn4.call(); // window
fn4.call(null); // window
fn4.call(undefined); // window
③apply
apply只有两个参数,第二个参数是一个数组或者伪数组
function fn5(num1,num2){
console.log(this);
console.log(num1+num2);
}
var arr = [10,20];
fn5.apply(null,arr); // window 30
(10)解构赋值:
①解构数组:
let arr = [1,2,3];
let [a] = arr; // 从数组中拿出第一个元素赋值给a变量
解构多个元素:
let arr = [1,2,3];
let [a,b] = arr; // a = arr[0]=1 b = arr[1]=2
多维数组解构:
let arr = [1,2,3,[4,5,6]];
let [a,b,c,[aa,bb]] = arr;
console.log(aa,bb); // 4 5
利用解构交换两个变量的值:
let num1 = 1;
let num2 = 2;
let [num2,num1] = [num1,num2] // 1 2
②解构对象:
let obj = {
name:"张三",
age:12,
sex:"男",
}
let {name} = obj; // 表示从obj中获取name属性,并赋值给声明的name变量
等价于:let name = obj.name;
一次性解构多个变量:
let obj = {
name:"张三",
age:12,
sex:"男",
}
let {name,age} = obj; // 声明并赋值了两个变量,两个变量无序
将变量名换成一个别的名字:
let obj = {
name:"张三",
age:12,
sex:"男",
}
let {name:username,age:a} = obj; // 将obj的name属性值赋值给username变量,age属性值赋值给变量a
多级解构:
let obj = {
name:"张三",
age:12,
sex:"男",
wife:{
name:"翠花",
age:11,
}
}
let {wife} = obj;
let {name} = wife;
// 写为一行
let {wife:{name}} = obj;
使用说明:
1. obj必须是一个对象
2. 2. obj中必须有解构的这个属性名
(11)Set:数组去重
var arr = [3,5,6,4,9,5,6,]
var arr1 = Array.from( new Set (arr) )
console.log(arr1); //[3,5,6,4,9]