javaScript 琐碎

闭包的理解

  (1)、闭包的概念: 简单理解就是定义在一个函数内部的函数,内部函数持有外部函数内变量的引用;

  (2)、闭包的优点:

    1)、读取函数内部的变量;2)、方便调用上下文的局部变量,利于函数封装;

  (3)、闭包的缺点:

    1)、由于闭包会使得函数中的变量都被保存在内存中,内存消耗很大,所有已不能滥用闭包,否则会造成网页性能的问题,在 IE 中可能导致内存泄漏的问题;解决的办法是,在退出之前,将不使用的局部变量全部删掉;

    2)、闭包会在父函数外部,改变父函数内部变量的值;

  

new 一个对象的过程中发生了什么?

  (1)、创建一个空对象;

  (2)、设置新对象的 constructor 属性为构造函数的名称,设置新对象的 __proto__属性指向构造杉树的 prototype;

  (3)、使用新对象调用函数,函数中的 this 被指向新实例对象;

  (4)、将初始化完毕的新对象地址,保存到等号左边的变量中;  

js 原型和原型链

  简单的来讲,原型其实就是对象Object或者引用类型的 prototype 属性;当我们访问一个对象的属性的时候,如果对象里没有这个属性的时候,那么他就回去 prototype 中去寻找,如果 prototype 中没有的话,就会接着再 prototype 中的 prototype 中去寻找,这个寻找的链路就是原型链;

  javaScript 的对象是通过引用类型来传递的,我们创建的每个新对象实体中并没有一份属于自己的原型副本,当我们修改原型时,与之相关的对象也会继承这一改变;当我们需要获取一个属性的值的时候,javaScript 引擎会先在当前对象中寻找,如果找不到的话就会去的 prototype 中寻找,并逐级递推;

set 数据结构

  set 是 es6 中新添加的数据结构,类似于伪数组,但是这种结构中的所有成员都是唯一的;可以通过 Affay.from 转换成真是的数组;

  set 结构虽然是一种类似数组的结构数据,但是要想获取它的长度,不能使用 length 属性,要用 size 属性;

  除了 size 属性外,set 数据还具有 keys、values、entries、forEach 方法;而且还具有 add、has、delete、clear 等方法;

    add:添加某个值,返回 Set 结构本身;

    has:返回一个布尔值,检测是否是 Set 数据的成员;

    delete:删除某个值,返回一个布尔值,表示删除是否成功;

    clear:清除所有的成员,没有返回值;

  

map 数据结构

  map 数据结构是 es6 新增的 key--value 类型的数据结构;其中的 key 和 value 可以是任意的值;

  在 javaScript 中 NaN  != NaN ;但是在 map 数据结构中,如果 键是 NaN 的话,则多个 NaN 指向的同一个键;

  map 数据的创建:

    方法一: let map = new Map()   map.set('a', 1)

    方法二:let map = new Map([['a', 1]])

  同样的要想获取 map 数据结构的键的长度是不能用 length 属性的,要用 size 属性;

  map 结构数据具有的方法:clear、delete、entries、get、keys、has、set、values、forEach;

  需要注意的是 map 结构并不是一种真实的对象,并不能通过 obj.key 去拿到键值,

  map 和 对象的对比:

    1)、通常对象都是有自己的原型的,但是 es5 开始可以通过 Object.create(null) 来创建一个没有原型的对象;

    2)、对象的键只能是字符串或者 symboles;但是 map 结构数据的键可以是任意值;

    3)、map 结构的数据可以通过 size 来获取键的个数,但是对象只能通过遍历去计算获取;

import && require 的区别

  require 的基本语法:在导出的文件中定义 module.export ,导出的对象的类型不予限制,可以是任何类型:对象,字符串,变量,方法等;在引入的文件中调用 require() 方法引入对象即可;

  import 的基本语法:导出的对象必须与模块中的值一一对应,也就是导出的对象与整个模块进行结构赋值;

  import 和 require 的区别:

    1)、require 是赋值过程并且是运行时才执行,import 是结构过程并且是编译时执行,require 可以认为是一个全局的方法,所以它设置可以进行一些运算操作,import 必须写在文件的顶部;

    2)、require 的性能相对于 import 稍微低一点,因为 require 是在运行的时候才引入模块并且还赋值给某个变量,而 import 只需要依赖 import 中的接口在编译时引入指定模块所以性能稍微高点;

    3)、在 commom.js 中 module.export 之后,导出的值就不在发生改变了,但是在 es6 的 export 中是可以的;

清理缓存的方法

  1)、meta 方法

    <meta http-equiv='pragma' content='no-cache'>

    <meta http-equiv='cache -control' content='no-cache, must-revalidate'>

    <meta http-equiv='expires' content='0'>

  2)、清理 form 表单的临时缓存

    <body onLoad='javascript: document.formname.reset()'>

  3)、用 http head 清理,比如 expires 和 cache-control

从输入url到页面加载发生了什么?

  我们在输入 url 地址之后,浏览器并不能直接去访问浏览器,因为每台服务器都是通过 IP 地址去进行标识的,但是 IP 地址记忆起来又比较的繁琐,因此我们在访问的时候总是去访问域名,然后根据 DNS 进行解析出来的地址去找寻到我们要访问的服务器,DNS 在寻找到这个 IP 进行访问到这个服务器的过程一般会利用缓存然后进行递归的查询,这里的缓存不仅是浏览器的缓存,还有操作系统以及路由的缓存,这样就大大的节省了时间,提高了查找和响应的效率;而且我们每次访问的时候,也并不是访问的同一个 IP 的服务器,每个服务同时访问的数量有可能是成千上万的,这样的话如果同时访问一台服务器的话就会加大服务器的承载,因此大多都会绑定多台服务器,DNS 在解析域名查找服务器的时候就会根据负载均衡为我们查找分配合理的 IP;当我们查找到服务器之后首先要跟服务器建立 TCP 三次握手,在这个过程中,会对协议等进行一些处理,比如我们的 http 协议和 https 协议,相对 http 协议,https 协议又多了跟 SSL 层的处理;在进行 http 报文请求的时候,包括请求行、请求报头、请求正文的请求;然后服务器处理请求报文,返回相应的 http 报文,相应报文包括状态码、相应报头、相应报文;状态码其实就是我们常说的 ajax 的状态码,1xx,2xx,3xx,4xx,5xx,其中 1xx 是指我们的请求已经被接收;2xx 是指请求的报文信息已经被接受而且被处理;3xx 是重定向的一个过程,会进一步的对请求进行一些处理,在这里有一般会有 304 这样的请求,这是因为浏览器缓存,一般是因为两次请求,浏览器浏览器并没有发生什么改变,因此一般接口在处理的时候会加上时间戳,保证每次的请求都是不一样的;4xx 是指发生了一些语法或者其他的错误,例如最常见的 404 就是找不到地址,以及 401 未被授权,没有权限访问;405 方法被禁用;410 请求资源被删除;5xx 是指服务器内部的一些错误,最多的就是网管错误,例如 502 就是网管错误;响应报文什么的处理完毕之后,浏览器就拿到文档资源就可以进行页面的加载了,在渲染页面的时候,浏览器一般是边解析边渲染的一个过程,解析 html 文件的时候一般是先解析 DOM 树,然后再去解析 css 渲染树,浏览器并将渲染树进行布局映射到 页面屏幕上;文件的加载一般是从上到下的,先 html --> header --> body ;在渲染的过程中,会有两个概念那就是 重绘(replain) 和 回流(reflow);回流一般是指由于空间位置等的改变,浏览器要重新去计算 DOM 的大小等,对文档流进行重构,而 重绘是指重新的渲染 DOM 的布局,比如颜色背景等等;因此说重绘的过程中不一定会引起回流,但是回流肯定会引起重绘的;为了提高页面的渲染过程和提高性能,一般都是将 css 文件放在最上边,这样在渲染 DOM 树的时候就可以直接根据 css 进行绘制,而浏览器在加载 js 的时候,会让 html 文档暂时的挂起,不仅要等到 js 加载完毕还要等他其解析完成,才会重新的渲染 html ;因此 js 代码一般都是放在最下边的,在里边也尽量的避免动态的去对 DOM 进行操作,引起页面的回流。

for...in 和 for...of 的区别

  for...in 一般是用来遍历对象的,遍历没有顺序的对象而且是对象可枚举的所有的属性,包括原型链上的属性,在这里其实 in 是一个操作符,是用来判断属性是否是对象上的或者是从原型链上继承得到的,如果是返回true ,否则返回 false;for...of 是es6 中新增的方法,主要是遍历有顺序的对象的,例如数组对象;

 

[‘1’,‘2’,‘3’].map(parseInt)的输出结果

  正确的输出结果时:[1, NaN,NaN];首先 map 是数组的一个方法,该方法的回调函数有三个参数,item, inde, arr;第一个是数组每一项的值,第二个是索引值,第三个是数组本身,在这里 parseInt 就是一个函数,即充当了回调函数的角色,但是 parseInt 只接收两个参数,第一个参数是字符串,第二个参数是解析时候的基数,且解析出来的结果不能等于或者大于基数,所以当索引为 0 时即基数为 0 时,这时候是按 10 作为基数的,因此返回了 1,当索引为 1,2 的时候,值都大于基数了,因此返回 NaN;

set、map、weakSet 和 weakMap 的区别?

  set:成员是唯一的、无序且不重复,而且键值和键名是一致的,或者说不存在键名只有键值;可以进行遍历;

  weakSet:成员都是对象;而且成员都是弱引用,可以被垃圾回收机制回收,一般用来存储 DOM 节点,这样不容易造成内存的泄漏;不能遍历;

  map:本质上是键值对的集合,有点类似于集合;可以编辑;

  weakSet:只接受对象最为键名除了 null ;不接受其他类型的值作为键名;而且键名是若引用,键值可以是任意的,键名所指向的对象可以被垃圾回收机制进行回收,回收之后这个键名就无效了;不能遍历;

 

setTimeout、Promise、Async/Await 的区别

  这三个方法的区别其实主要是在事件循环的时候,所在的队列不同;事件循环中分了两种队列:宏任务队列和微任务队列;其中,setTimeout 的回到是在宏任务队列中,等到执行栈清空以后执行;而 Promise 在执行的时候其实 then、catch 的回调都是在微任务队列中的,当执行promise 方法的时候,在 executor 中刻个方法也是一个宏任务队列,是一个同步的过程,当遇到 resolve 或者 reject 的时候并不会立即的去执行相对应的微任务队列中的 then 或者 catch 回调,而是等 ececutor 中的同步任务执行完毕了,才来执行相应的微任务;async 表示函数里边可能会有异步的操作,其实跟 promis 类似,只不过遇到 await 之后,会立即执行 await 后边的代码,执行完了再接着执行下边的任务队列中的任务,其实 async/await 就是一个 自动执行的 generate 函数,利用 generate 的特性把异步的任务变成了同步的执行顺序;

 

简单描述一下 http2.x 中的多路复用

  在 http1.x 中,浏览器的每次请求都会建立一个 http 连接,也就是我们常说的3次握手和4次挥手,这个过程是在一次请求构成中占用了相当长的一段时间,即使使用了 keep-alive ,解决了多次连接的问题,但是依然会有问题,在效率上,1)、串行的文本传输;当请求 a 文件时,b 文件只能等待,等待 a 连接到服务器,服务器处理文件、服务器返回文件,这三个步骤执行完毕,才去执行 b 文件;假如,每一步都是 1 秒,那么两个文件就是 6 秒;2)、连接数过多;假如 apache 设置的最大并发是 300,因为浏览器的限制,浏览器发起的最大请求为6,也就是说服务器能承载的最大并发为 50 个人的访问,当第 51 个人访问的时候,就需要等待前面某个请求处理完毕才可以; 

  http2.x 的多路复用就是为了很高的解决这两个效率问题;http2.x 的传输是基于二进制的,每个 TCP 连接中承载了多个双向流通的流,每个流都有一个独一无二的标识和优先级,而流就是有二进制帧组成的,二进制帧的头部信息会标识自己属于哪一个流,所以这些帧是可以交错传输的,然后在接收端通过帧头的信息组装成完整的数据,这样就解决了线头阻塞的问题,同时也提高了网络速度的利用率;

 

react 中 setState 什么时候是同步的,什么时候是异步的?

  在 react 中,如果是由 react 引发的事件,比如通过 onClick 引发的事件处理,调用 setState 不会同步更新 this.state,除此之外的 setState 调用会同步执行 this.state ,也就是绕过 react 通过 addEventListener 直接添加的事件处理函数,还有通过 setTimeout、setInterval 产生的异步调用;

  在 react 中的 setState 函数的实现中,会根据一个变量 isBatchingUpdates 判断是直接更新 this.state 还是放到队列中,而 isBatchingUpdates 的默认值是 false,表示 setState 会同步更新 this.state,但是,有一个函数 batchedUpdates 会把 isBatchingUpdates 修改成 true,而当 react 在调用事件处理函数之前就会调用这个 batchedUpdates,造成的后果,就是由 react 控制的事件处理过程 setState 不会同步跟新 this.state;

  其实这里的同步和异步并不是像 async/await 所知的那种异步,而是 多个 state 合并到一起进行批量的更新,就像 vue 中的 $nextTick,页面在渲染之前会等所有的 data 数据改变处理完毕了再去进行渲染; 

vue 中,子组件为何不可以修改父组件传递的 prop,如果修改了,vue 是如何控制到属性并给出警告的?

  不能修改时为了保证数据的单向流动,便于对数据进行追踪,避免数据混乱;官网的解释是:所有的 prop 都使得其父子 prop 之间形成了一个 单向下行绑定,父组件 prop 的更新会向下流动到子组件中,但是反过来则不行,这样会防止从子组件意外改变父级组件的状态,从而导致你的应用的数据流向难以理解;但并不是所有的 prop 都不能修改,修改了就给警告,修改不成功;如果出入的 prop 是引用类型的,那么修改引用数据类型的某个属性值的时候,对应的 props 也会修改,并且 vue 不会给警告;同一个组件,对 data 的数据监听是深度的监听,对 props 是浅度的监听;

  

call、apply 和 bind 的区别

  call 和 apply 都是为了改变某个函数运行时的上下文而存在的,简单的说就是为了改变函数体内部 this 指向;二者的区别在于 call 一般用于传递餐阿叔较少,可以罗列的,多个参数之间用逗号隔开;apply 要传一个数组进去;他们的作用都是一样的,而且底层的实现原理也是相同的,都是通过新建了一个新的对象然后赋值,实现的;

  bind 跟 call、apply 相似都是可以改变函数体内 this 的指向,但是一般用于事件的绑定,因此也称之为绑定函数;在使用这个方法的时候会先创建一个新的函数,然后第一个参数也是所要指向的 this 本身;bind 的实现其实是相当于在内部包了一个 call/apply ,因此如果是多个 bind 连续使用的话是无效的;

  总的来讲:1、call、apply、bind 都是用来改变函数的 this 对象的指向的;2、call、apply、bind 三者第一个参数都是 this 要指向的对象,也就是上下文;3、call、apply、bind 三者都可以利用后续的传参;4、bind 返回的是对应的函数,便于后续的调用;而 call 和 apply 是会立即执行的;

基本数据类型和引用类型

  js 基本数据类型包括:undefined、null、member、boolean、string;基本类型是直接访问的值;特点:1、基本数据类型的值是不可改变的,除非重新赋值;2、基本数据类型不可以添加属性和方法;3、基本数据类型的赋值是简单的赋值;4、基本数据类型的比较是值的比较;5、基本数据类型是存放在栈区的;

  js 引用类型包括:对象(数组对象等等)、function 等;特点:1、引用类型的值是可以改变的;2、引用类型可以添加属性和方法;3、引用类型的赋值是对象引用;4、引用类型的比较是引用的比较;5、引用类型是同事保存在栈区和堆区中的;

  null 和 undefined 的异同: 1、null 是被赋值了的;undefined 是一个变量声明了但是没有赋值;2、null 和 undefined 都是否定值;3、null 和 undefined 都是原始值,但是 typeof null = Object;4、null !== undefined 但是 null == undefined;5、Number(null) = 0;Number(undefined) = NAN

原文地址:https://www.cnblogs.com/mufc/p/11301971.html