ECMAScript
ES5回顾—
前端: 用户所操作
前台: html+css +js
后端: 后台程序员进行维护
后台: php java nodel.js(交互数据)
严格模式
语言类型:
弱类型语言:声明变量是由后面的值确定声明的变量的数据类型的,eg:js,php
强类型语言:必须先声明变量,再赋值,eg:Java,c#,c++
严格模式:‘use strict’,进入严格模式
1,将‘use strict’放在脚本文件第一行
2,声明定义变量必须用var
3,严格模式下不能删除变量
4,函数里的this没有对象
非严格模式:
1,可以删除变量
2,可以用var声明变量,也可以不用
3,普通函数中的this指向window
进入严格模式的标志:
- 必须放在脚本第一行
<scritp>
'use strict';
</scritp>
声明定义变量的时候必须加var
a=10;
console.log(a);//报错
禁止自定义的函数中的this指向全局对象
function Obj(name,sex){
this.name=name;//没有实例化,所以this指向全局对象
this.sex=sex;
}
Obj('张三','男');//报错:Cannot set property 'name' of undefined
//也就是undefined,他和下面其实是一样的
function obj(){
// return this;
}
console.log(obj());//undefined
创建eval作用域更安全
var name='张三';
eval('var name="王五";console.log(name,111)');//王五 111
console.log(name,222);//张三 222
//eval中的name并不会影响外面的
JSON对象
-
JSON.stringify()将js对象,数组转换为json的数据
object/arr—>string
-
JSON.parse()将json数据转换为js对象
string/json—>object
var obj={
name:'张三',
age:20,
sex:'女'
};
var obj1=JSON.stringify(obj);
console.log(typeof obj1);//string
console.log(obj1);//{"name":"张三","age":20,"sex":"女"}
var obj2=JSON.parse(obj1);
console.log(typeof obj2);//object
console.log(obj2);//{name: "张三", age: 20, sex: "女"}
Object扩展
Object.create(原型,{新的属性})
1,新创建的对象可以继承原型的属性和值,2,并且可以创建自己的新的属性和值,3,如果新的对象的新的属性和原型的属性一致,新的会覆盖原型的。
/*格式:
Object.create(对象原型,{
属性值1:{
value:值,//给新的属性赋值
writable:true,//默认false,是否允许修改属性值
configurable:true//默认false,是否允许删除属性
enumerable:true//默认false,是否枚举,遍历
}
})*/
var obj={name:'张三',age:20}
var obj1=Object.create(obj);
console.log(obj1);//{}
console.log(obj1.name);//张三
obj1.name='王五'
console.log(obj1.name);//王五
console.log(obj.name);//张三
var obj2=Object.create(obj,{
sex:{
value:'男',
writable:true,
enumerable:true
},
sex2:{
value:'女',
writable:true,
configurable:true,
enumerable:true
}
})
console.log(obj2);
console.log(obj2.sex2);//女
obj2.sex2='保密';
console.log(obj2.sex2);//保密
console.log(delete obj2.sex2)//true
console.log(obj2.sex2);//undefined
for(var attr in obj2){
console.log(attr,obj2[attr],2222);
}
Object.defineProperties()
未指定的对象扩展多个属性;get:获取当前属性值的回调函数;set:修改设置属性值的回调函数。
var obj={firstname:'小明',lastname:'小红'};
console.log(obj);
Object.defineProperties(obj,{
obj1:{
get:function(){//回调函数
return this.firstname+','+this.lastname
},
set:function(value){
var name=value.split(',');
this.firstname=name[0];
this.lastname=name[1];
}
}
})
obj.obj1='张三,李四';
console.log(obj);
回调函数:执行完某个函数以后做的操作;递归函数:自己调用自己
Array扩展
indexOf(value)
- 得到的值在数组中第一次出现的下标
- 下标从0开始
- 如若没有则返回-1
lastIndexOf(value)
- 得到的值是数组中最后一个出现的下标
- 下标从0开始
- 如若没有则返回-1
forEach(function(item,index){循环体})
- 遍历数组
map(function(item,index){循环体})
- 遍历数组返回一个新的数组
- 因为item是局部定义的一个变量,要有返回值
filter(function(item,index){循环体})
- 遍历数组,将满足条件的数组过滤出来,组成一个新的数组
var arr=[2,3,3,2,1,5];
console.log(arr.indexOf(2));//0,第一次出现的下标
console.log(arr.lastIndexOf(2));//3,最后一次出现的下标
arr.forEach(function(value,index){//遍历数组
// console.log(value,index);
});
var arr1=arr.map(function(value,index){
return value*2;//遍历数组,将计算以后的值组成一个新的数组
});
// console.log(arr1);
var arr2=arr.filter(function(value,index){
return value>2;//过滤数组,将满足条件的值组成一个新的数组
})
console.log(arr2);
函数(function)的扩展
函数.bind(obj)
- 将函数内部的this绑定为obj,并将函数返回
function fun(age){
this.name='张三',
this.age=age,
this.sex='男'
}
var obj={};
fun.bind(obj,20)();
console.log(obj);
console.log(typeof obj);
console.log(obj.name+'的年龄是'+obj.age+'岁');
函数.apply(函数,[参数1,参数2…])
-
用另一个对象调用当前对象的方法
function obj(a,b){ console.log(a+b); } function obj2(a,b){ console.log(a-b); } obj.apply(obj2,[5,5]);//10
函数.call(函数,参数1,参数2…)
-
用另一个对象调用当前对象的方法
function obj(a,b){ console.log(a+b); } function obj2(a,b){ console.log(a-b); } obj.call(obj2,1,1);//2
ES6简介—
let
新增块级作用域 {} let在{}中使用,块级作用域包括for(){},if(){}
let特点:
1,不能重复声明变量
let a=10;
let a=11;
console.log(a);//报错
2,不会预处理,不存在变量提升
console.log(a);//undefined
var a=10;
console.log(b);//报错
let b=10;
var特点
1,可以重复声明
var a=10;
console.log(a);//10
var a=11;
console.log(a);//11
let块级作用域
//let只在代码块中有效
{
let a=10;
console.log(a);//10
}
console.log(a);//报错
let循环
for(let j=0;j<10;j++){
console.log(j);//j只有在本轮循环里面有效,循环体外就会报错
}
// console.log(j,1111);//j is not defined
var arr1=arr2=[];
for(var i=0;i<10;i++){
arr1[i]=function(){
console.log(i);
}
}
arr1[5]();//10
for(let i=0;i<10;i++){
arr2[i]=function(){
console.log(i);
}
}
arr2[5]();//5
// for循环还有一个特别之处,就是设置循环变量的部分是父作用域,循环体内部是一个单独的子作用域
for(let j=0;j<3;j++){
let j='aaa';
console.log(j);//输出三次aaa
// 这表明,函数内部的变量即使和循环内部的变量名一致,也不会互相影响,
// 因为函数内部的变量和循环变量不在同一个作用域,都有各自的作用域
}
// var div=document.getElementsByTagName('div');
// for(var i=0;i<div.length;i++){
// div[i].οnclick=function(){
// console.log(i);//输出的就一直是4
// }
// }
// for(let i=0;i<div.length;i++){
// div[i].οnclick=function(){
// console.log(i+1);//点第几个盒子输出第几个数
// }
// }
const
声明一个常量:
const 常量名=值;
特点:
1,只能声明一次;
2,声明的常量必须初始化,不可以后面再赋值,且不能再进行修改;
3,常量的命名用驼峰标识,大写和变量区分,多个单词用下划线分开;
4,和let一样,只能在块级作用域里有效
//const-->常量
// 声明常量
// 常量命名经常是大写,这样好和变量分辨
const NUM=10;
// NUM=10;//Missing initializer in const declaration
// 常量声明的时候必须初始化,不能后面再赋值
// const NUM=11;//Identifier 'NUM' has already been declared
//常量只能声明一次,在一次声明会报错
// NUM=15;//Assignment to constant variable.
//后期不能修改常量的值
console.log(NUM);
{
const AA=5;
console.log(AA,1111);
// 和let一样,只能在块级作用域里有效
}
// console.log(AA,2222);//AA is not defined
let解析赋值
解析对象:
let{参数1,参数2,参数3}=对象
- 参数名必须和对象里的某个属性名一致,如若参数名在对象名中不存在返回undefined
- 参数名可以超过对象中的参数名的数量,不存在的返回undefined就行
let obj={
name:'张三',
age:20,
sex:'女'
}
let{name,a,age,sex,b}=obj;
console.log(name,a,age,sex,b);
let{参数1,参数2}={属性1:属性值1,属性2:属性值2}
- let中的参数名要和属性名一样才可以返回对应的属性值
- 若是多出就返回undefined
let{name,a,age,c}={name:'李四',age:18}
console.log(name,a,age,c)
解析数组
let arr=[1,2,3,4];
let[a,b]=arr;
- 默认从数组的第一个值开始输出
- 若是let中的数比数组中的数多,多的就是undefined
let arr=['a',1,3];
let[a,b,c]=arr;
console.log(a,b,c);
字符串的解析,模板字符串
也就是字符串连接,
es5:
(“名字”+obj.name+";年龄:"+obj.age)
es6:
``反引号,里面:${对象.属性}
(名字:${obj.name};年龄:${obj,age}
)
let obj={
name:'小红',
age:16
}
// es5解析字符串,就是字符串输出的模式
console.log(obj.name+"今年"+obj.age+"岁");
// es6解析字符串的方式
console.log(`${obj.name}今年${obj.age}岁`);
对象简写
//不简写之前
let x=10;
let y=10;
let obj={
x:x,
y:y,
fun:function(){console.log(x-y);}
}
//简写之后
let x=10;
let y=10;
let obj={
x,
y,
fun(){console.log(x-y);}
}
箭头函数
()=>{}等价于function(){}
箭头函数,调用不可以放在声明前面
箭头函数的几种情况:
-
没有参数时:变量名=()=>{函数体}
let fun1=()=>{ console.log('emm...'); } fun1();//emm...
-
有参数时:变量名=(参数1,参数2)=>{函数体}
-
有一个参数时:可以将括号()省略
// 有一个参数 let fun2=a=>{ console.log(a); } fun2('我是谁');
-
有两个和两个以上的参数时:括号就不可以再省略了
let fun3=(b,c)=>{ console.log(b,c); } fun3('aaaaa',11);
-
-
有返回值时:变量名=(参数)=>(return 返回值)
-
函数体中只有一条语句时,可以省略大括号{},如果这条语句是返回值时,还可以吧return省略
注意:省略return的同时必须省略{}
// 有一条语句 let fun6=(d)=>{console.log(d)}; fun6(12); // 这一条语句正好是返回值的时候 let fun4=aa=>aa*2; console.log(fun4(10)); let fun5=(bb,cc)=>bb+cc; console.log(fun5(1,1));
-
函数体中有多条语句时,就不可以省略{}和return了
let fun7=(dd,ss,aa)=>{ console.log(dd);//1 return ss+aa; } console.log(fun7(1,2,3));//5
-
关于箭头函数的总结:1,如果函数体中就一条语句,可以省略{} , 2,如果这条语句是返回值,还可以省略return ,3,如果只有一个参数,可以省略(),4,其他情况()和return ,{}都要加,多个参数用,隔开,5,省略return的时候,必须省略{},否则会报错
箭头函数中的this
-
在全局函数中的this–>指向window
function fun1(){ console.log(this);//window } fun1(); var fun2=()=>{ console.log(this);//window } fun2();
-
在事件处理函数中的this—>指向window
var div=document.getElementsByTagName('div')[0]; var divi=document.getElementsByTagName('div')[1]; div.οnclick=function(){ console.log(this);//<div></div> //es5指向触发事件的对象 } divi.οnclick=()=>{ console.log(this);//window //es6指向window }
-
在对象方法(构造函数)中的this
function Fun(){ this.eat=function(){ // console.log(this); return function(){ console.log(this);//这里的this指向的是window // 因为return到了外面,传到了全局,所以指向的是window } } } var fun3=new Fun(); console.log(fun3.eat())//指向返回后面的函数 fun3.eat()()//window //----------------------------------------------- function Fun1(){ this.eat=()=>{ return ()=>{ console.log(this);//在哪里定义他就指向谁,所以指向Fun1 } } } var fun4=new Fun1(); console.log(fun4.eat());//指向返回后面的函数 fun4.eat()();//Fun1
-
箭头函数注意点:
-
函数体内的this对象,指向的是定义时所在对象,而非使用时所在的对象
function Fun1(){ this.eat=()=>{ return ()=>{ console.log(this);//在哪里定义他就指向谁,所以指向Fun1 } } } var fun4=new Fun1(); console.log(fun4.eat());//指向返回的函数 fun4.eat()();//Fun1
-
不可以当做构造函数,也就是说,不可以使用new命令
var Fun2=(name)=>{ this.name=name; } var fun5=new Fun2('张三'); console.log(fun5.name);//Fun2 is not a constructor
-
不可以使用arguments对象,该对象在函数体内不存在
var fun6=function(a,b,c){ console.log(arguments); //Arguments(3) [1, 2, 3, callee: ƒ, Symbol(Symbol.iterator): ƒ] } fun6(1,2,3); var fun7=(q,w,e)=>{ console.log(arguments);//arguments is not defined } fun7(1,1,1);
-
如果要用,可以用rest参数代替
-
什么是rest参数:
-
格式:…变量名
-
用于获取将他们放到一个数组中,rest参数后面就不能再有其他的参数了
var fun7=(a,...num)=>{ console.log(a);//1 console.log(num);//[2, 1] } fun7(1,2,1); //------------------------------ var fun7=(...num)=>{ console.log(num);//[1,2, 1] } fun7(1,2,1);
-
-
扩展运算符
扩展运算符是三个点(…),他就像rest参数的逆运算,将一个数组转为以逗号作为分隔的参数序列
console.log(...[1,2,3,4,10,22]);//1 2 3 4 10 22
console.log('a',...[1,2,3,10,22],'cc','ss');//a 1 2 3 10 22 cc ss
一般用于函数调用
var add=(a,b)=>{
return a+b;
}
const num=[1,2];
console.log(add(...num));//3
应用
-
复制数组
const arr1=[1,2,3,4]; const arr2=[...arr1]; console.log(arr2);//(4) [1, 2, 3, 4]
-
将类似数组转换为真正的数组
console.log(...'hello world');//h e l l o w o r l d console.log([...'hello world']); //(11) ["h", "e", "l", "l", "o", " ", "w", "o", "r", "l", "d"] var div=document.getElementsByTagName('div'); console.log([...div]);//(4) [div, div, div, div] // 还可以正确识别四个字节的Unicode字符
函数默认值
-
es6之前不能直接为函数指定默认值
function fun(x,z){ z=z||'world'; console.log(x,z); } fun('hello');//hello world fun('hello','china');//hello china // 上述做法,如果我们给z赋值了,只是对应的布尔值是false, // 那么这次的赋值应该不起作用,z应该为空,但是被改为了默认值
-
es6允许为函数的参数设置默认值
function fun(x,z='aaa'){ console.log(x,z); } fun('yyy');//yyy aaa fun('yyy','xxx');//yyy xxx fun('yyy','');//yyy
参数变量是默认声明的,不能用let或者const再次声明
function ff(q,w){
var q=10;
console.log(q);//10
// let w=1;
// const w=1;
console.log(w);//Identifier 'w' has already been declared
}
ff(1,2);