箭头函数
使得函数表达式更短,不绑定自己的
this
,arguments
,super
,new.target
,适合用于非方法函数,并且不能用作构造函数
语法
-
var fn=p=>p
:中间的p
是参数,后面的p
是返回值,这是表达式的写法
,相当于var fn=p=>{ return p; // 函数体写法 语义化更加清楚 } var res=fn(123); console.log(res); // 123
-
没有参数的情况下,可以这样写:
var fn=()=>'返回值'
,多个参数的时候:var fn=(n,m)=>n+m
,当然这些写法都可以写成上面的函数体形式
var fn=(n,m)=>{ return n+m; } var res=fn(2,3); console.log(res); //5
箭头函数里面的this
指向
说起
this
,先复习一下前所知道的this
的作用:
- 自执行函数中的
this
,永远指向window
- 当元素身上的事件被触发的时候,会执行一个函数,
函数中
的this
指向当前这个元素- 回调函数中的
this
,一般都是window
- 当函数被调用的时候,点前面是谁,
this
就是谁- 遇到
call,apply,bind
的时候,会改变this
的指向
所有箭头函数里面的this
是指向父函数里面的this
var fn1=()=>{
console.log('外面的this:'+this); // 这个this是指向 window
return{// 返回一个对象
fn:function(){
console.log('以前对象的写法,键值对'+ this); // 这个this是指向 函数前面的调用者 Object
}
// 也可以这样写 ES6的写法
// fn(){console.log('ES6的写法,和以前的写法一样'+this)}
fn:()=>{
console.log('箭头函数'+this) // 箭头函数里面的this永远指向父级的this,写法还是键值对的方式, window
}
}
}
var obj=fn1();// 获取的是fn函数return返回的地址,地址指向的是fn这个空间
obj.fn();// return 里面的函数fn执行
构造函数的创建和继承
创建构造函数
创建一个类用
class
,创建一个构造函数用constructor
,构造函数是用来初始化的,私有属性和方法;查看一个方法是否是公有还是私有的,直接使用console.dir(对象)
,看这个方法是否在__proto__
上,和constructor
在一起
继承一个函数使用extends
static
是来修饰一个属于类身上的方法,实例访问不到,类的静态方法,类的私有方法
class Father{
constructor(name,age){
// 构造函数 里面放私有属性和方法
this.name=name;
this.age=age;
}
// 公有的属性和方法 就放在原型上面 prototype
getName(){
console.log(this.name);
}
// 静态的属性和方法:指的是类身上的属性和方法,实例不能使用静态的属性和方法,实例只能使用原型上面的属性和方法,通过原型链去找父级的私有属性和方法
static aa(){
console.log('icessun1')
}
}
// 子类继承父类 公有的属性和方法 私有的属性和方法,但是属于类本身的方法(使用static修饰的)调用不到
class Son extends Father{
constructor(name,age,color){
super(name,age);//super 必须写 继承父类的东西 私有和公有
this.color=color;
}
// 重写父级的方法 属于子类的方法
getName(){
console.log('icessun1111');
}
}
// 创建一个实例
var f1=new Father('icessun',18);
var s1=new Son('icessun11',20,'red');
f1.name;// icessun
f1.getName(); // icessun
增强的对象字面量
当对象的属性名和属性值一样的时候,我们可以省略
obj{fn:fn,aa:aa}
直接写成obj{fn,aa}
// 原先创建一个对象的方法 键值对
var obj={name:'icessun',age:18};
var aa='icessun';
var fn=()=>{console.log('icessun')}
// 现在想新创建一个对象来继承上面的又不影响上面的
var obj2={__proto__:obj,aa,fn};
// 一般在对象里面写属性名和属性值,键值对方式 var obj2{aa:aa,fn:fn}
console.log(obj.name);// icessun
obj2.name='icessun2'
console.log(obj2.name);// icessun2
模版字符串
注意模版里面的不是引号,是
``
// 以前的写法
var data=new Date().getFullYear();
console.log('现在是'+data+'年');
// 现在的写法 模版
console.log(`现在是${data}年`)
解构赋值
因为我们操作
JS
都是操作对象身上的属性和方法,对于一个对象来说,通过解构赋值,我们可以更好更快的操作其身上的属性和方法,需要使用那个属性或者方法,我们就解构赋值,拿到的是对象身上该属性名对应的值
var obj={name:'icessun',age:18,fn(){alert(123)}};
// 解构赋值 左边对象的值取决于右边对象身上的属性值
var {name,age}=obj;
// 直接就可以使用name 和 age了 获取的是obj对象上面对应的属性的属性值
let和const
变量
以前在
for
循环里面使用var
定义变量的时候,其循环里面不会形成一个私有作用域,只有函数被调用的时候才会形成私有作用域,故:
var n=10;
for(var i=0;i<5;i++){
var n=20;
document.body.click=function(){
console.log(i); // 5 在循环里面获取的i的值是错误的,永远是最大值 事件是异步的
}
}
console.log(n); // 20
因为不会形成私有作用域,故
window
中定义声明了变量n
,就不会在循环里面重复定义一次,所以其赋值会把window
里面的赋值给覆盖掉,最后打印出来的是循环里面赋值的20
;但是当循环里面使用了let
定义变量的时候,结果就会不一样,因为循环里面会形成一个私有作用域,从而与外界隔绝,不会相互影响。
var n=10;
for(let i=0;i<5;i++){
let n=20;
console.log(n); // 20 20 20 20 20
}
console.log(n); // 10
总结let和const
- 这两个都不会预解释
-
let
会形成块级作用域
-
const
是一个常量,不能进行更改
可扩展的参数
以前我们对于未知参数个数的时候,一般使用
arguments
来接收,现在可以使用...keys
// 传了参数按照传的参数来,没有就按照默认的参数来
var fn=(a=12,b=5)=>{
console.log(a+b);
}
fn(); // 17
fn(10,30); // 40
// 多个参数传的时候 不知道参数的个数
var fn=(a,b,...keys)=>{
console.log(`a:${a}`); // icessun
console.log(`b:${b}`); // 19
console.log(`...keys:${keys}`); // icessun122 20 icessun33
}
fn('icessun',19,'icessun122',20,'icessun33')
扩展的运算符 ...
var ary=[29,14,3];
var ary2=[1,2,...ary]; // 1,2,29,14,3
var res = Math.max(...ary2); // 29
求最大值和最小值的方法
- sort
- Math.max配合eval
- Math.max配合apply
- 假设法
- 扩展运算符
Promise
体验
使用
Promise
来实现三个小球滚动的效果,会使用到定时器,递归
,对比传统的方式和使用Promise
方式的区别:传统的方法递归嵌套深,Promise
方法更容易理解
传统的方式
html代码:
<div class='div1' style='margin-left:0'></div>
<div class='div2' style='margin-left:0'></div>
<div class='div3' style='margin-left:0'></div>
<style>
div{
width: 60px;
height: 60px;
-webkit-border-radius: 50%;
-moz-border-radius: 50%;
border-radius: 50%;
}
.div1{
background: red;
}
.div2{
background: green;
}
.div3{
background: blue;
}
</style>
JS代码:
var div1=document.getElementsByTagName('div')[0];
var div2=document.getElementsByTagName('div')[1];
var div3=document.getElementsByTagName('div')[2];
var timer=null;
// 以前的写法 封装一个运动函数
function animate(ele,target,callback){
// ele:运动的元素 target:目的地,callback:到达目的地要做的事情 函数
timer=setTimeout(function(){
// 开启一个定时器 获取运动元素距离左边的距离 所有的事情都是在定时器里面进行
var n=parseInt(ele.style.marginLeft);
if(n===target){
// 到达目的地要干的事情 调用这个函数 只有到达目的地了才调用callback函数
callback();
return;
}else{
// 没有到达目的地的处理办法
if(n>target){
n--;
}else{
n++;
}
ele.style.marginLeft=n+'px';
animate(ele,target,callback);// 调用运动函数
}
},13); // 每隔13毫秒执行一次
}
// 递归
animate(div1,100,function(){
animate(div2,200,function(){
animate(div3,300,function(){
animate(div3,150,function(){
animate(div2,150,function(){
animate(div1,150,function(){
clearTimeout(timer);
alert('运动完毕');
})
})
})
})
})
})
使用Promise
的方式
then语句
:接下来要做的事情
function promiseAnimate(ele,target){
// 这个函数返回的是个实例对象 resolve:成功干什么;reject:失败干什么
return new Promise(function(resolve,reject){
function animate(){ // 没有参数
setTimeout(function(){
var n=parseInt(ele.style.marginLeft);
// 到达目的地要做的事情
if(n===target){
resolve();
}else{
if(n<target){
n++;
}else{
n--;
}
ele.style.marginLeft=n+'px';
animate();
}
},13);
}
animate(); // 调用函数
})
}
promiseAnimate(div1,100)
.then(function(){
return promiseAnimate(div2,200);
})
.then(function(){
return promiseAnimate(div3,300);
})
.then(function(){
return promiseAnomate(div3,150);
})
.then(function(){
return promiseAnomate(div2,150);
})
.then(function(){
return promiseAnomate(div1,150);
})
.then(function(){
alert('运动结束')
})
网友评论