ES5-ES6新特性介绍
ES5新特性
严格模式
- 除了正常运行模式(混杂模式),ES5添加了第二种运行模式:”严格模式”(strict mode)。顾名思义,这种模式使得Javascript在更严格的语法条件下运行
- 目的:
- 消除Javascript语法的一些不合理、不严谨之处,减少一些怪异行为;
- 消除代码运行的一些不安全之处,为代码的安全运行保驾护航;
- 为未来新版本的Javascript做好铺垫;
- 使用
- 在全局或函数的第一条语句定义为: ‘use strict’;
- 如果浏览器不支持, 只解析为一条简单的语句, 没有任何副作用;
语法和行为改变
必须用var声明变量;
<script type="text/javascript"> "use strict" age = 12; console.log(age);// age is not defined </script>
禁止自定义的函数中的this指向window;
- 因此使用构造函数时,如果忘了加new,this不再指向全局对象,而是报错。
"use strict" function Person(name,age) { //在严格模式下,自定义普通函数中的this是禁止指向window的。 console.log(this); //undefined this.name = name; this.age = age; } Person('kobe',12); //定时器不是自定义函数,所以可以输出window setTimeout(function () { console.log(this);//window }, 1000);
- 因此使用构造函数时,如果忘了加new,this不再指向全局对象,而是报错。
创建eval作用域;
- eval() 函数可计算某个字符串,并执行其中的的 JavaScript 代码。
- 正常模式下,Javascript语言有两种变量作用域(scope):全局作用域和函数作用域。严格模式创设了第三种作用域:eval作用域。
正常模式下,eval语句的作用域,取决于它处于全局作用域,还是处于函数作用域。严格模式下,eval语句本身就是一个作用域,不再能够生成全局变量了,它所生成的变量只能用于eval内部。
var name = 'kobe'; eval('var name = "anverson";console.log(name)');//anverson console.log(name);//kobe
对象不能有重名的属性;正常模式下最后赋值的属性会覆盖前面的值,严格模式下属于语法错误;
JSON的对象
- JSON基于两种结构:
- “名称/值”对的集合;
- 值的有序列表;
JSON具有以下这些形式:
对象(object):是一个无序的“‘名称/值’对”集合。
- 一个对象以“{”(左括号)开始,“}”(右括号)结束。
- 每个“名称”后跟一个“:”(冒号);“‘名称/值’ 对”之间使用“,”(逗号)分隔。
{'名值对1','名值对2'......}
数组(array):是值(value)的有序集合。
- 一个数组以“[”(左中括号)开始,“]”(右中括号)结束。
- 值之间使用“,”(逗号)分隔。
[value1,value2......]
值(value):可以是双引号括起来的字符串(string)、数值(number)、true、false、 null、对象(object)或者数组(array)。这些结构可以嵌套。
- 字符串(string):是由双引号包围的任意数量Unicode字符的集合,使用反斜线转义。
- JSON 字符串:数值(number) 也与C或者Java的数值非常相似。只是JSON的数值没有使用八进制与十六进制格式。
JSON的两种方法
- JSON.stringify(obj/arr); js对象(数组)转换为json对象(数组)
- JSON.parse(json); json对象(数组)转换为js对象(数组)
var obj = {name:"kobe",age:39}; // JSON.stringify(obj/arr); js对象(数组)转换为json对象(数组) obj = JSON.stringify(obj); console.log(obj);//{"name":"kobe","age":39} console.log(typeof obj); //JSON.parse(json); json对象(数组)转换为js对象(数组) obj = JSON.parse(obj);//string console.log(obj);//{name: "kobe", age: 39} console.log(typeof obj);//object
Object扩展
Object扩展了好一些静态方法, 常用的2个:
Object.create(prototype, [descriptors])
- 作用:
- 以指定对象为原型创建新的对象;
- 为新的对象指定新的属性, 并对属性进行描述;
- 有关参数:
- value : 指定值
- writable : 标识当前属性值是否是可修改的, 默认为true
- get : 用来得到当前属性值的回调函数
- set : 用来监视当前属性值变化的回调函数
var obj = {name:'ldy',age:18}; var obj1 = Object.create(obj); console.log(obj1); //直接继承obj的属性,作为自己的原型对象 /* * {}; * __proto__: age: 18name: "ldy"__proto__: Object */ obj1.sex = '男'; //继承obj的对象obj1可以添加直接属性 console.log(obj1); /* * {sex: "男"}; * __proto__: age: 18name: "ldy"__proto__: Object */ //可以直接继承obj属性作为原型链上的属性,并且直接通过第二个参数传入一个对象,作为对象的直接属性。 //注意:第二个参数内的键值对的值需要是一个对象{value:...}。 obj1 = Object.create(obj,{ address:{value:'daguanyuan'}, att:{value:'wenrou'} }); console.log(obj1); /* * {address: "daguanyuan", att: "wenrou"} * __proto__: * age:18 * name:"ldy" * */
- 作用:
Object.defineProperties(object, descriptors)
- 作用: 为指定对象定义扩展多个属性
- 存取器属性:setter,getter一个用来存值,一个用来取值
- 对象本身的两个方法
- get propertyName(){} 用来得到当前属性值的回调函数;
- set propertyName(){} 用来监视当前属性值变化的回调函数;
- 注意,get方法只有在调用它掌控的属性的时候,才会被调用该get方法的。
var obj2 = {wname:'xiannv1',wname2:'xiannv2'}; Object.defineProperty(obj2, 'wife2',{value:'ldy'}); Object.defineProperties(obj2,{ wife3:{ value:'xbc' },wife4:{ get:function(){ //此时会将return后的内容作为值返回给obj2.wife4; return this.wifevalue; }, set:function(data){ //set方法里接收的就是设置的obj2.wife4 = 'jyc'的值。 console.log(data);//'jyc' this.wifevalue = data; } } }) obj2.wife4 = 'jyc'; console.log(obj2.wife4);//'jyc' console.log(obj2);//{wname: "xiannv1", wname2: "xiannv2", wifevalue: "jyc", wife2: "ldy", wife3: "xbc", wife4:"jyc"}
Array扩展
- Array.prototype.indexOf(value) : 得到值在数组中的第一个下标
- Array.prototype.lastIndexOf(value) : 得到值在数组中的最后一个下标
- Array.prototype.forEach(function(item, index){}) : 遍历数组
- Array.prototype.map(function(item, index){}) : 遍历数组返回一个新的数组,返回加工之后的值
- Array.prototype.filter(function(item, index){}) : 遍历过滤出一个新的子数组, 返回条件为true的值
//map\forEach\filter区别
var arr = [23,65,6,43,1,5,3,2,8];
//filter相当于筛选,返回的是满足条件的筛选值
var arr3 = arr.filter(function (item) {
return item<20;
})
console.log(arr3);// [6, 1, 5, 3, 2, 8]
//foeEach相当于是遍历,是将原数组都输出;但是并不能直接对遍历的值进行加工
var arr2 = arr.forEach(function (item) {
console.log(arr);//[23, 65, 6, 43, 1, 5, 3, 2, 8]
return item*3;
})
console.log(arr2);//undefined
//map可以对遍历出来的字,进行加工,返回的是一个加工后的新数组。
var arr1 = arr.map(function (item) {
return item*3;
})
console.log(arr);//[23, 65, 6, 43, 1, 5, 3, 2, 8]
console.log(arr1);//[69, 195, 18, 129, 3, 15, 9, 6, 24]
function扩展
- Function.prototype.bind(obj) :
- 作用: 将函数内的this绑定为obj, 并将函数返回
面试题: 区别bind()与call()和apply()?
- 都能指定函数中的this;
- call()/apply()是立即调用函数;
- bind()是将函数返回;
var age = 20; var obj = {username:'kobe',age:28}; function fn(username) { console.log(this.age,username); }; //apply和call都是一调用就立即执行 //apply只传入数组,而call可以传非数组 fn.apply(obj);//直接执行了,输出了28he undifined; fn.apply(obj,['xbc']);//28 "xbc" fn.call(obj,'jyc');//28 "jyc" //bind调用之后没有立即执行函数,在想执行的时候再调用。传入的参数和call一样。 fn.bind(obj,'jby');//无 fn.bind(obj,'jby')();//28 "jby"
ES6新特性
新关键字
let关键字
- 1.作用:
- 与var类似, 用于声明一个变量
- 2.特点:
- 在块作用域内有效
- 不能重复声明
- 不会预处理, 不存在提升
- 3.应用:
- 循环遍历加监听
- 使用let取代var是趋势
let btn = document.getElementsByTagName('button');
//方法一
for(var i=0;i<btn.length;i++){
(function (i) {
btn[i].onclick = function () {
alert(i);
}
})(i)
}
//方法二
for(var i=0;i<btn.length;i++){
btn[i].dream = i;
btn[i].onclick = function () {
alert(this.dream);
}
}
//方法三
for(let i=0;i<btn.length;i++){
btn[i].onclick = function () {
alert(i);
}
};
const定义一个常量
- 1.作用:
- 定义一个常量
- 2.特点:
- 不能修改
- 其它特点同let
- 3.应用:
- 保存不用改变的数据
const sex = 'nan';
console.log(sex);
sex = '女';//Assignment to constant variable.
console.log(sex);
变量的结构赋值
- 1.理解:
- 从对象或数组中提取数据, 并赋值给变量(多个)
- 2.对象的解构赋值: let {n, a} = {n:’tom’, a:12}
let obj = {name:'ldy',age:'17'};
let {age,name} = obj;
console.log(age,name);//17 ldy
- 3.数组的解构赋值: let [a,b] = [1, ‘atguigu’];
let arr = ['a','b','c','d'];
let [a,b,c,d] = arr;
console.log(a);//'a'
console.log(b);//'b'
console.log(c);//'c'
console.log(d);//'d'
- 4.用途
- 给多个形参赋值
//当传入的对象有很多属性,但是需要传入的实参仅需要其中的两个,那么就可以通过对象的解构赋值,接收传入实参对象中的其中某两个属性。
function fn({name,age}) {
console.log(name,age);//hlm 38
}
let obj1 = {add:'dgy',name:'hlm',sex:'nan',age:38};
fn(obj1);
模版字符串
- 模板字符串 : 简化字符串的拼接
- 模板字符串必须用 “ 包含
- 变化的部分使用${xxx}定义
let obj = {
name : 'anverson',
age : 41
};
console.log('我叫:' + obj.name + ', 我的年龄是:' + obj.age);
//我叫:anverson, 我的年龄是:41
console.log(`我叫:${obj.name}, 我的年龄是:${obj.age}`);//我叫:anverson, 我的年龄是:41
简化对象写法
- 省略同名的属性值
- 省略方法的function
let x = 3;
let y = 5;
//普通写法
// let obj = {
// x:x,
// y:y,
// getPoint:function () {
// return 'fun';
// }
// }
// console.log(obj);//{x: 3, y: 5, getPoint: ƒ}
//简化写法
let obj = {
x:x,
y:y,
getPoint() {
return 'fun';
}
}
console.log(obj);//{x: 3, y: 5, getPoint: ƒ}
三点运算符
用途
- 1.rest(可变)参数:用来取代arguments 但比 arguments 灵活,只能是最后部分形参参数
//简单举例 function fun(...values) { console.log(arguments);// [1, 2, 3, callee: (...), Symbol(Symbol.iterator): ƒ];一个对象,类数组 // arguments.forEach(function (item, index) { // console.log(item, index);//报错 // }); console.log(values);//[1, 2, 3];一个数组 values.forEach(function (item, index) { console.log(item, index); }) } fun(1,2,3); //详解 let fun1=function(...args){ for(let arg of args){ console.log(arg); }; console.log(args) }; fun1('a','b','c');//a b c,[a,b,c] fun1(1,2);//1 2,[1,2] ...args表示了所有的形参,不管传入多少参数,都可以通过args进行遍历得到,args则集合所有的参数组成参数数组 let fun2=function(arr,...args){ console.log(arr); console.log(args); }; fun2(1,2,3);//1, [2,3] fun2(1);//1, []当...args有其他参数时,rest参数args数组集合除去前面参数之后的参数。 let fun3=function(arr1,..args,arr2){ console.log(args); }//此时报错!!!切记,三点作为rest参数的时候,其后不能再有任何参数,只能作为最后一个角色出现!
- 2.扩展运算符
let arr1 = [1,3,5]; let arr2 = [2,...arr1,6]; arr2.push(...arr1); //详细讲解 let arr=[1,2,3]; console.log(...arr);//1, 2, 3返回数组中的各项 let a=[2,3]; console.log(1,...a,4);//1,2,3,4扩展运算符可以放在中间 let divs=document.querySelectorAll('div'); [...divs];//Array[300],[]可以将divs转为数组解构; console.log(...divs);//div1,div2....遍历divs各项 let set=new Set([1,2,3,3]); [...set];//返回数组[1,2,3],可以将set数据结构转化为数组 let map=new Map([[1,'a'],[2,'b'],[3,'c']]); [...map.keys];//返回[1,2,3],属性数组; [...map.values];//返回[a,b,c],value数组 /////////////// [...'wbiokr'];//["w", "b", "i", "o", "k", "r"]遍历字符串,返回各个字符; let str='abc'; ['aaa',...str,'ccc'];//[aaa, a, b, c, ccc]扩展运算符位置比较任性
形参的默认值
形参的默认值—-当不传入参数的时候默认使用形参里的默认值
//定义一个点的坐标 function Point(x=12, y=12) { this.x = x; this.y = y; } let point = new Point(25, 36); console.log(point);//Point {x: 25, y: 36} let p = new Point(); console.log(p);//Point {x: 12, y: 12}
class类
- 1.通过class定义类/实现类的继承
- 2.在类中通过constructor定义构造方法
- 3.通过new来创建类的实例
- 4.通过extends来实现类的继承
- 5.通过super调用父类的构造方法
- 6.重写从父类中继承的一般方法
// class定义类的方式,构造对象
class Mul{
// 类里面的属性,其实可以理解为实例对象的构造函数。
// 所以它里面定义的属性和方法,在实例对象的直接属性之中。
constructor(name,age){
this.name = name;
this.age = age;
// this.hello = function () {
// console.log(5678);
// }
}
// 这个定义的方法,可以理解为定义在构造函数的原型上面,所以只能在实例对象的__proto__上可以找到。
showName(){
console.log('name');
}
}
let mul = new Mul('zly',14);
console.log(mul);//Mul {name: "zly", age: 14}
//实现类的继承
class newFun extends Mul{
constructor(name,age,sex){
super(name,age);//调用父类的构造方法
this.sex = sex;
this.newMsg = function () {
console.log(this.age,this.sex,this.name);
}
}
// showName(){
// console.log('name');
// }
}
let newfun = new newFun('SWK',23,'nan');
console.log(newfun);//newFun {name: "SWK", age: 23, sex: "nan", newMsg: ƒ}
// 此时的newfun的原型对象的原型对象中有showName(){console.log('name');}函数。因为newfun是继承Mul类的,而super方法是继承Mul类的构造方法作为了自己的直接属性,可是showName()是定义在Mul的原型上的,并没有继承到直接属性上,所以就在newfun的原型的原型上,extends方法是类的继承,。
字符串扩展
- 1.includes(str) : 判断是否包含指定的字符串
var str = 'asdkjhgfdfghjkl';
console.log(str.includes('w'));//false
console.log(str.includes('j'));//true
- 2.startsWith(str) : 判断是否以指定字符串开头
var str = 'asdkjhgfdfghjkl';
console.log(str.startsWith('a'));//true
console.log(str.startsWith('as'));//true
console.log(str.startsWith('b'));//false
- 3.endsWith(str) : 判断是否以指定字符串结尾
var str = 'asdkjhgfdfghjkl';
console.log(str.endsWith('l'));//true
console.log(str.endsWith('kl'));//true
console.log(str.endsWith('k'));//false
- 4.repeat(count) : 重复指定次数
var str = 'asdkjhgfdfghjkl';
console.log(str.repeat(2));//asdkjhgfdfghjklasdkjhgfdfghjkl
数值扩展
- 1.二进制与八进制数值表示法: 二进制用0b, 八进制用0o;
console.log(0b1010);//10
console.log(0o65);//53
- 2.Number.isFinite(i) : 判断是否是有限大的数
console.log(Number.isFinite(NaN));//false
console.log(Number.isFinite(10));//true
- 3.Number.isNaN(i) : 判断是否是NaN
console.log(Number.isNaN(NaN));//true
console.log(Number.isNaN(true));//false
- 4.Number.isInteger(i) : 判断是否是整数
- 5.Number.parseInt(str) : 将字符串转换为对应的数值
- 6.Math.trunc(i) : 直接去除小数部分
console.log(Math.trunc(120.4));//120
console.log(Math.trunc(0.120));//0
数组扩展
- 1.Array.from(v) : 将伪数组对象或可遍历对象转换为真数组
//html结构上有三个button按钮;
//通过dom获得一个类数组;
var btn = document.getElementsByTagName('button');
console.log(btn);//HTMLCollection(3);一个html对象,是一个类数组
//通过from方法,将类数组转化为真数组;
var btn1 = Array.from(btn);
console.log(btn1);//Array(3); [button, button, button]
- 2.Array.of(v1, v2, v3) : 将一系列值转换成数组
var btn = document.getElementsByTagName('button');
console.log(btn);//HTMLCollection(3);一个html对象,是一个类数组
var btn2 = Array.of(btn);
console.log(btn2);//[HTMLCollection(3)];这是一个数组,这个数组只有一项.
var arr = 'sdf[sdf]';
console.log(Array.of(arr));//["sdf[sdf]"]
var str = 'a,b,c,d,e';
console.log(Array.of(str));//["a,b,c,d,e"]
- 3.find(function(value, index, arr){return true}) : 找出第一个满足条件返回true的元素
var arr = [2,3,4,'f','s','e','r'];
console.log(arr.find(function (item) {
return item<5;
}));//2;找到的是第一个小于5的元素,直接返回。
- 4.findIndex(function(value, index, arr){return true}) : 找出第一个满足条件返回true的元素下标
var arr = [2,3,4,'f','s','e','r'];
console.log(arr.findIndex(function (item) {
return item<5;
}));//0;找到的是第一个小于5的元素,正好是2,返回他的下标
Object扩展
1.Object.is(v1, v2)
- 判断2个数据是否完全相等;
console.log(Object.is(NaN,NaN));//true console.log(Object.is(0,-0));//false
- 判断2个数据是否完全相等;
2.Object.assign(target, source1, source2..)
- 将源对象的属性复制到目标对象上
let obj = {name:'kobe',age:39}; let objn = {sex:'男'}; let obj1 ={}; let obj2 = {}; Object.assign(obj1,obj.name); console.log(obj1);//{0: "k", 1: "o", 2: "b", 3: "e"} //将后两个对象,复制到第一个参数对象上。可以复制多个。 Object.assign(obj2,obj,objn); console.log(obj2);//{name: "kobe", age: 39, sex: "男"}
- 将源对象的属性复制到目标对象上
3.直接操作 proto 属性
let obj3 = {name : 'anverson', age : 41}; let obj4 = {}; obj4.__proto__ = obj3; console.log(obj4, obj4.name, obj4.age);//{} "anverson" 41
Set和Map数据结构
- 1.Set容器 : 无序不可重复的多个value的集合体
- Set()
- Set(array);
- add(value);增加指定项
- delete(value);删除指定项
- has(value);是否含有
- clear();清空
- size;set容器内容长度
var set1 = new Set(['a','f',2,5,1]);
console.log(set1);//Set(5) {"a", "f", 2, 5, 1}
console.log(set1.size);//5
//删除指定项
set1.delete(1);
console.log(set1);//Set(4) {"a", "f", 2, 5}
//检查是否含有指定项
console.log(set1.has(2));//true
console.log(set1.has(1));//false
//增加指定项
set1.add('sd');
console.log(set1);//Set(5) {"a", "f", 2, 5, "sd"}
//清空指定项
set1.clear();
console.log(set1);//Set(0) {}
- 2.Map容器 : 无序的 key不重复的多个key-value的集合体
- Map()
- Map(array)
- set(key, value)//添加
- get(key);获得
- delete(key);删除
- has(key);判断是否有
- clear();清除
- size
let map = new Map([['abc',12],[56,'fre']]);
console.log(map);//Map(2) {"abc" => 12, 56 => "fre"}
console.log(map.size);//2
map.set('sex','男');
console.log(map);//Map(3) {"abc" => 12, 56 => "fre", "sex" => "男"}
console.log(map.get('abc'));//12
map.delete('sex');
console.log(map);//Map(2) {"abc" => 12, 56 => "fre"}
console.log(map.has('sex'));//false
console.log(map.has(56));//true
map.clear();
console.log(map);//Map(0) {}
遍历
- for(let value of target){}循环遍历
- 1.遍历数组
- 2.遍历Set
- 3.遍历Map
- 4.遍历字符串
- 5.遍历伪数组
//遍历数组
let arr = [1,2,3,4,5];
for(let num of arr){
console.log(num);//1到5依次输出
}
//遍历set
let set = new Set([1,2,3,4,5]);
for(let num of set){
console.log(num);//1到5依次输出
}
//遍历字符串
let str = 'abcdefg';
for(let num of str){
console.log(num);//a到g依次输出
}
//遍历伪数组
let btns = document.getElementsByTagName('button');
for(let btn of btns){
console.log(btn.innerHTML);//按钮1、按钮2、按钮3
}