ES6和js面向对象和js同步异步和闭包的作用和DOM重绘回流的解析?

ES6:

//ES6:
    //全局中的this是一个空对象,指向window,函数中的this是global

    /*let声明的变量不允许重复(在一个块级区域内)*/
    //1.数组的解读
    //解构的目标=解构的源
    // let ary=[1,2,3,4,[5,6]];
    // // let [a,b,c,d,[e,f]]=ary;
    // // console.log(e,f);//5,6
  

    // let [g,...k]=ary;
    // console.log(g,k);

    // let [h,,...j]=ary;
    // console.log(h,j);

    // //合并数组
    // let x=100,y=200;
    // let ary2=[x,y];
    // console.log(ary2);//[100,200]


    // //改变原先的值
    // let v=300,m=400;
    // [v,m]=[m,v];
    // console.log(v,m);//400,300

    // //2.字符串解构解读
    // //如果其中某一项没有可以用解构赋值的方式 (例子:d=90)
    // //特别注意的地方:let声明如果有相同的会报错某解析错误
    // let str='abc';
    // let [a,b,c,d=90]=str;
    // console.log(a,b,c,d);//a b c 90
    
    // //3.对象的解构解读
    // let obj={
    //     n:100,
    //     m:200,
    //     t:[1,2]
    // }
    // // let {n,m:m2,z=500,t:[f,q]}=obj;//解构名必须一致;
    // //解构名也可以重新起个别的名(m:m2)然后调用  
    // // console.log(n,m2,z,f,q);//100 200 500 1 2

    // //解构赋值也可以通过扩展符号接收
    // let {n,...e}=obj;
    // console.log(n,e);/*100 
    //                   {m: 200, t: Array(2)}
    //                    m: 200
    //                    t: (2) [1, 2]
    //                 __proto__: Object */


   //.给对象调换一下解构
  //  let a={
  //    x:100,
  //    y:200
  //  }
  //  a={x,y}={x:200,y:100};
  //  console.log(x,y);//200 100
    
  // //4.模板字符串``
  // //好处可以相互嵌套多个标签
  
  // //5.includes 
  // //includes()方法就是为了简化indexof()的判断
  // //因为indexof()方法返回的是包含字符串的位置,如果==-1的话,那也就是不包含这个字符串
  // //includes()方法返回的是布尔值 false或true
  // //测试str.includes('测试')?console.log(true):console.log(false);


  // //includes相当于截取字符串的位置,返回的是布尔类型的值
  // //也类似于some 、every、节省了不用去循环
  // let ary3=[1,23,3];
  // let s=ary3.includes(23);
  // console.log(s);//true
  // let str="abc";
  // let s2=str.includes('d');
  // console.log(s2);//false 如果有就返回true没有就false
  

  //5.箭头函数
  //箭头函数注意事项
  /*
  1.this取决于上级作用域,而不是调用
  2,箭头函数不用new关键字
  3.箭头函数不可以使用arguments获的参数列表,可以使用rest参数代替
  引入了rest参数(形式:...变量名),参数放入数组中
  let f00=(...param=>{
    console.log(param);
  }) 
  foo(12,56);
  */
 //箭头函数例子:rest代替参数列表
//  let  foo=(...a)=>{//...在箭头函数中rest代替参数列表接收箭头函数
//    console.log(a);//1 2 3 4
//  }
//  foo(1,2,3,4);

   //6.引入class(类)这个概念,通过class关键字可以定义类
   //通过class关键字定义类,必须使用constructor来定义this(和使用this,否则就报错)
  //  class Fn{//
  //    constructor(){//函数接收this上的
  //     this.n=10;
  //     this.m=20;//接收this
  //    }
  //    //获取原型上的继承(例子:如下方法)
  //    sum(){
  //      console.log('我是公共的sum内容')
  //    }
  //  }
  //  let f=new Fn();
  //  console.log(f.n,f.m);//10 20
  //  f.sum();//调取:我是公共的sum内容
  


 //7.模块化:es6的模块化分为导出(export)与导入(import)两个模块
 //export default导出对象包含多个/export一个一个的导出


 //8.promise本身是同步的
 //promise先预定之后再去执行这些方法
 //promise用来异步操作,是构造函数,参数为then(失败和成功的执行)和catch(捕获失败的执行)后需要执行的方法
 //then()可以有两个函数一个成功,一个catch的失败,
 //catch()只能捕获上一级then的失败的状态
 //all:全部(调多个异步接口都成功才会成功,否则就catch失败状态)
 //race:比赛(多个异步同时执行哪个快就执行哪个)
 //有三种状态:从pending到成功  从pending到失败  catch捕获到失败
 //本身是一个类,可以用new出来一个promise
 //解决了回调地狱和来回嵌套的问题。

 //9.Object.assign:是合并对象,把多个对象合并到第一个对象上

let obj1={n:1},
obj2={m:2},
obj3={k:3};

Object.assign(obj1,obj2,obj3);
console.log(obj1);//会自动合并到第一个对象上//{n: 1, m: 2, k: 3}

//10.generator yield 函数
function* name(){
  yield console.log('执行1');//执行1
  yield console.log('执行2');//执行2
  function h(){
    console.log('执行函数h');//执行函数h
  }
  yield h();//调用函数
}
let s=name();
//next:代表执行下一项
s.next();
s.next();
s.next();

//11.Symbol唯一值



//2个变量交换值
let a=1,b=2;
[b,a]=[a,b];
console.log(a,b);//2 1


//js设计模式有哪几种?:发布订阅设计模式和单例设计模式和工厂设计模式

JS面向对象:

//面向对象的理解:
    //(封装、继承、多态、属于后台的面向对象)
    //1.js的面向对象:Object Oriented  Programming 简称OOP
     /*
     常用的编程思想有2种:
     1.面向对象编程:js、java、PHP、python、c#.....
     2.面向过程编程:c
     -js本身就是基于面向对象的编程语言,具备它自己的编程思想
     -面向对象编程需要我们掌握对象,类,实例的概念
     面向对象:万物皆对象
     类:对象的细分
     实例:类中具体的一个事物
     举个例子说明上面三个词:自然界是个大环境,包含万物,把这些万物
     按照特征区分了很多种类,包含人类、动物类、植物类...
     我们要学习人类这一类别,就会拿出具体的一个人来研究,学习了这个人
     有什么特征,就知道了其他人也拥有相同的特征了,这个具体的人就是人类中的实例

     
     回归js中
     js也有很多的东西。把这些东西分成很多类,我们学习其中一个类,就先拿出这一类中的一个具体实例来
     研究。学习了一个实例具有的属性和方法,就知道了其他实例也会拥有相同的属性和方法
     例如:学习数组,就先var ary=[1,2,3];研究这个数组有什么方法和属性,就知道其他数组也有同样的方法
     和属性,每一个ary数组就是Array数组类的一个实例,这个实例就是我们要操作的对象

     面向对象要有类,实例这些东西,js中有哪些类?
     1.自定义类:new 出它的实例
     2.内置类:Number、String、Boolean、Function、Array...
     每一个实例都有自己的所属类,包括每一个元素都有自己的所属类
     1,2,3,4...每一个数字都是Number类的一个实例
     var ary=[1,2,3],var ary2=[]...每一个数组都是Array类的一个实例

     总结:js本身就是面向对象开发的,他提供了很多内置类,我们操作js就是操作这些类的实例
     所以每一个内置类的实例,都是我们要操作的对象,操作js本身就是面向对象编程。

     后台的面向对象有封装、继承、多态性的特性,js中面向对象可以实现函数的封装,多种继承的方式
     但是没有多态一说,如果非要说多态,可以把给一个函数中传递不同的参数,会实现不同的效果
     勉强说成多态。
     
     */

JS同步和异步:

 /*
     js中的同步和异步?
     浏览器是多线程的,js是单线程的
     1.js为什么是单线程的?
     因为浏览器只分配了一个线程给js

     单线程:同一时间,只能执行一个任务,同一时间,只能放一件事,同一时间只能放一件事情
           去主栈中运行

    多线程的浏览器体现在哪里?
    浏览器打开一个页面,就是开启了一个进程,
    进程大线程小:一个进程中又包含了多个线程,例如在浏览器中打开一个html页面(有去加载html的,有去加载css的...)
    
    
    浏览器加载一个html页面:
    当去加载html的时候,浏览器分配一个线程加载html结构,分配其他线程去加载对应的资源文件,最后再分配一个线程去
    自上而下执行js文件(所以有的时候,js文件加head中运行的时候,dom元素获取不到)

     
    2.js为什么没有设计成单线程的?
    假如有2个方法,a方法改变了xxx变量的内容,同时b方法也改变了xxx变量的内容,同时进行,按照哪个执行
     
    3.js的同步编程:在一个线程上(主栈、主任务队列),同一时间,只能做一件事情,当前事情完成
    才能进行下一事情、

    先把一个任务进栈执行,执行完出栈,再把下一个任务进栈,上一个任务出栈...
    进栈出栈的过程


    4.js的同步编程:首先它不是同时执行
    主栈上执行任务的时候,发现这个任务是异步任务的操作的时候,会把它移出主栈,放到等待任务队列中,
    (浏览器会再分配一个线程,来监听等待任务队列中的任务是否达到指定的运行时间),而对于事件监听,
    就是监听是否被触发了
    如果主栈执行完,监听者会把到达时间的任务重新放到主栈中执行,执行完成后,主栈就空闲下来了
    再去拿异步任务队列中去拿最先到达时间的任务,到主栈中运行...

    4-1:js中的异步操作:
    定时器,事件绑定,回调函数,ajax,promise(async/await),process.nextTick
    node中的fs异步的I/O操作


    所有js中的异步编程仅仅是根据异步机制来管控任务的执行顺序,不存在同时执行两个任务一说


    扩展:
    console.time('s');//记录执行的开始时间
    console.timeEnd('s');//记录执行的结束时间


    定时器的最小等待时间:谷歌 4ms

    如果主栈的任务执行的时间超过了等待任务,也要等待主栈中的任务执行完成,才能去执行等待中的任务
    等待任务队列中,谁先到达时间,就把谁先执行,微任务除外
    如果同时达到时间的,先放的先执行


    宏任务,微任务:
    等待队列中的任务:分为宏任务和微任务,先执行微任务,在执行宏任务
    Promise的then
    Promise(async/await)

     */

    //1.例子:
    //  setTimeout(()=>{
    //    console.log(1);//
    //  },1000);

    //  console.time('a');
    //  for(let i=0;i<10;i++){
    //  }
    //  console.timeEnd('a');
    //  console.log(2);//同步

    //  setTimeout(()=>{
    //   console.log(3);//定时器到时间执行
    //  },0)
    //执行顺序a:: 0.010986328125 ms      2     3   1 
   
    //2.例子:
    //  let p=new Promise((s,j)=>{//promise第一个函数代表成功,第二个代表失败
    //    console.log(4);//2.同步
    //    setTimeout(()=>{
    //      console.log(5);
    //    },1000)
    //    s();//任务队列
    //  })
    //  p.then(()=>{
    //    console.log(6);//3.任务队列执行微任务
    //  },()=>{
    //    console.log(7);
     //  })
     //1例子.和2例子.同时执行时运行结果:
    //执行顺序 a: 0.02099609375 ms  2  4  6  3  1  5
  
   
     /*
     同步执行,再异步执行:又分为(微任务和宏任务),先执行微任务再执行宏任务

     异步分为以下几种:
     1.Promise.then是微任务,async和awaity也是微任务
     2.定时器是宏任务
     3.ajax
     */
     

  //1.1例子:
  //    function a(){
  //      return new Promise((resolve,reject)=>{
  //        //方法执行必须调用后才会执行:例如resolve成功和失败reject
  //          setTimeout(()=>{
  //            console.log(9);
  //            resolve();
  //        },1000);
  //      })
  //    }
  
  //  function b(){
  //       a();//异步
  //      console.log(8);
  //    }
  //    b();
     //执行顺序 8  9


    //1.2例子:改变执行顺序为9  8的操作如下
       function a(){
       return new Promise((resolve,reject)=>{
         //方法执行必须调用后才会执行:例如resolve成功和失败reject
           setTimeout(()=>{
             console.log(9);
             resolve();
         },1000);
       })
     }
   
   
   //异步:ajax
  async function b(){//同时使用async await搭配使用才会改变
       await a();//解析为await执行完成后其它才会执行(await会把下边的执行加入到异步队列中,直到await执行完再执行异步队列任务)
       console.log(8);
     }
     b();

  /*
  说一说事件循环(event loop)过程?
  1.js执行的时候会判断当前代码是同步还是异步,同步就进入同步消息队列中立即执行
  异步就推进异步消息队列中等待执行
 
  2.当所有同步任务执行完毕后,主线程空闲下来就会去到异步消息队列中
  看是否有异步任务达到可执行条件的,就将其移到主栈中去执行(先微任务再宏任务以及队列先进先出机制)
  上面操作循环就形成了事件循环(event loop)
  (例子:主栈空闲时,当两个队列同时有任务时,谁先进来就执行谁)
  */

闭包的作用:

/*
     闭包的作用,优点和缺点。
     闭包:是js的一个重要机制。通过函数执行形成一个不销毁的私有作用域,保护和保存里面的私有变量不受外界的干扰
     保护:之前项目中,现实功能的时候,防止和别人的变量名冲突,就是把功能代码封装到一个闭包中
     保护起来,防止全局变量的污染
     保存:循环的事件绑定的时候,此时的用到它索引的时候有可能变成全局的了,用闭包形成一个不销毁的作用域
     把每次的索引都保存了起来,后面使用的时候直接拿出来用
     缺点:真是项目为了保证js性能,堆栈内存的性能优化,应该尽可能的减少闭包的使用,不销毁的堆栈内存是
     消耗性能的
    //闭包的表现形式 :
    //柯理化函数
    function fn(){//形成的作用域不销毁
      return function(){

      }
    }//调用外面的函数的返回的都是return的函数
    //惰性函数=>单例模式
    var untis=(function(){//自执行函数执行,形成一个不销毁的作用域,返回了一个对象
    return{

    }
    })()
     
     */

DOM重绘和回流:

 /*
     dom的重绘和回流
     1.html加载时发生了什么?
     浏览器会把html解析成DOM数,把css解析成cssom树,DOM和CSSOM合并就产生了
     渲染树(Render Tree)有了render three,浏览器根据render tree节点绘制
     到页面上

     2.回流:
     DOM树和CSSOM树结合后的render tree后,将可见Dom节点以及它对应的样式结合起来
     可是我们还需要计算它们在设备视口(viewport)内的确切位置和大小,这个计算的阶段就是回流
     width、height、bottom、left、top


     3.重绘:
     通过构造render tree和回流阶段,我们知道了那些节点是可见的,以及可见节点的样式
     和具体的几何信息(位置、大小),那么我们就可以将render tree的每个节点都
     转换为屏幕上的实际像素,这个阶段就叫做重绘节点
     例如background-color、color、outline等(改变一些样式就是重绘)


     注:重绘不一定会引起回流,回流一定引起重绘,任何对render tree中元素的操作都会引起回流
     或重绘


     4.什么操作会引起重绘、回流
     1.页面一开始渲染的时候
     2.添加或删除可见的dom元素
     3.元素的位置发生变化
     4.元素的尺寸发生变化(包括外边距、内边框、边框大小、高度和宽度等)
     5.内容发生变化,比如文本变化或图片被另一个不同尺寸的图片所替代
     6.用户操作浏览器的窗口尺寸变化(因为回流是根据视口的大小来计算元素的位置和大小的)
     


    5.如何减少回流、重绘
    1).浏览器的优化机制
    现代的浏览器都是很聪明的,由于每次重排都会造成额外的计算消耗
    因此大多数浏览器都会通过队列化修改并批量执行来优化重排过程。浏览器
    会将修改操作放入到队列里,直到过了一段时间或者操作达到了一个阀值(界限),才清空队列
    但是,当你获取布局信息的操作的时候,会强制队列刷新
    比如当你访问以下属性或者使用以下方法:
    offsetTop、offsetLeft、offsetWidth、offsetHeight
    scrollTop、scrollLeft、scrollWidth、scrollHeight
    clientTop、clientLeft、clientWidth、clientHeight
    以上属性和方法都需要返回最新的布局信息,因此浏览器不得不清空队列
    触发回流重绘来返回正确的值。
    因此,我们在修改样式的时候,最好避免使用上面列出属性,他们都会刷新渲染
    队列。

    2)尽可能的减少回流和重绘
    1.尽可能在DOM树的最末端改变class
    原因:回流可以自上而下,或者自下而上的回流的信息传递给周围的节点的,但可以减少其影响。
        尽可能在Dom树的里面改变class,可以限制了回流的范围,使其影响尽可能少的节点
        总结就是减少了回流的影响范围
    2.避免设置多层内联样式,改成使用外部类统一修改
     原因:通过style属性设置样式,每个dom元素都会造成回流
          样式应该合并在一个外部类,这样当该元素的class属性可被操控时仅会产生一次回流
   3).动画效果应用到position属性为absolute或flex的元素上
     原因:脱离文档流,减少回流的render tree的规模
     */

原型和原型链:

/*
     原型和原型链?
     1.每一个函数都天生自带一个prototype属性(原型),它的值是个对象类型的,作用是储存供给它的
     实例使用的属性和方法
     2.每个prototype上都有一个constuctor属性,指向当前函数本身
     3.每个对象天生自带一个_proto_的属性,指向它的所属类prototype(原型)
     4.所有的内置类的基类都是object对象


     原型链:当操作一个对象属性或者方法的时候,首先会找私有的,有就使用,私有的没有
            会通过_proto_属性,找它所属类原型(prototype)中的公共的方法和属性,一直找到基类object位置,
            这种一级级向上查找的机制叫做原型链机制
     */

猜你喜欢

转载自blog.csdn.net/weixin_46409887/article/details/114298257