正规的彩票网站怎么做,安徽省建筑业信息一体化平台网,深圳均安网站制作,本地怎样做网站31、http 的理解 ?
HTTP 协议是超文本传输协议#xff0c;是客户端浏览器或其他程序“请求”与 Web 服务器响应之间的应用层通信协议。HTTPS主要是由HTTPSSL构建的可进行加密传输、身份认证的一种安全通信通道。
32、http 和 https 的区别 ? 1、https协议需要到ca申请证书…31、http 的理解 ?
HTTP 协议是超文本传输协议是客户端浏览器或其他程序“请求”与 Web 服务器响应之间的应用层通信协议。HTTPS主要是由HTTPSSL构建的可进行加密传输、身份认证的一种安全通信通道。
32、http 和 https 的区别 ? 1、https协议需要到ca申请证书一般免费证书较少因而需要一定费用。 2、http是超文本传输协议信息是明文传输https则是具有安全性的ssl加密传输协议。 3、http和https使用的是完全不同的连接方式用的端口也不一样前者是80后者是443。 4、http的连接很简单是无状态的HTTPS协议是由SSLHTTP协议构建的可进行加密传输、身份认证的网络协议比http协议安全。
33、git 的常用指令有哪些 ?
git branch 分支查看git branch branch_1 增加分支git checkout branch 分支切换git merge branch_1 合并分支(合并前要切换当前分支至master)git branch -d branch_1 删除分支git remote 查看当前仓库管理的远程仓库信息git remote show origin 查看指定的远程仓库的详细信息git push --set-upstream origin branch_1 第一次将本地分支推到远程仓库git push 远程主机名 本地分支名:远程分支名 将本地分支推到远程分支git pull 远程主机名 远程分支:本地分支 将远程分支拉到本地分支git branch -d branch_0 删除本地合并后分支git brench -D branch_0 删除本地未合并分支it push origin --delete branch_0 删除远程分支git restore [filename] 进行清除工作区的改变git tag 查看标签git tag v1.0.0 打标签git push origin v1.0.0 将tag同步到远程服务器
34、平时是使用 git 指令还是图形化工具 ?
repositorygit库相关操作基本意思就是字面意思。 1资源管理器中浏览该Git库工作空间文件省去查找路径不断点击鼠标的操作。 2启动Git bash工具命令行工具。 3查看当前分支文件状态不包括未提交的信息。 4查看某个分支的文件弹出框中可选择需要查看的版本、分支或标签跟上一条差不多用的比较少可能是没有这方面的额需求。 5可视化当前分支历史、可视化所有分支历史弹出分支操作历史也就是gitk工具放到gitk工具中介绍。 edit用于操作commit时操作信息输入只能操作文字输入部分你没有看错。常用的快捷键大家都知道何必要单独做成基本没啥用的。本来以为对变更的文件进行批量操作、本来以为可以对未版本跟踪的文件批量删除、本来、、、都说了是本来。 Branch新建分支需要选择其实版本可以根据版本号、其他分支或标签来选择、检出分支觉得切换分支更合适、重命名分支、删除分支、当前分支Reset操作会丢弃所有未提交的变更包括工作区和索引区当然了有弹出框提示危险操作。
35、Promsie.all() 使用过吗, 它是怎么使用的 ? promise.all()用于一个异步操作需要在几个异步操作完成后再进行时使用。promise.all()接受一个promise对象组成的数组参数返回promise对象。当数组中所有promise都完成了就执行当前promise对象的then方法如果数组中有一个promise执行失败了就执行当前promise对象的catch方法。
36、什么是三次握手和四次挥手 ? 三次握手是网络客户端跟网络服务器之间建立连接并进行通信的过程。相当于客户端和服务器之间你来我往的3个步骤。 第一次握手是建立连接客户端发送连接请求报文并传送规定的数据包 第二次握手是服务器端表示接收到连接请求报文并回传规定的数据包 第三次握手是客户端接收到服务器回传的数据包后给服务器端再次发送数据包。这样就完成了客户端跟服务器的连接和数据传送。 四次挥手表示当前这次连接请求已经结束要断开这次连接。 第一次挥手是客户端对服务器发起断开请求 第二次挥手是服务器表示收到这次断开请求 第三次挥手是服务器表示已经断开连接 第四次挥手是客户端断开连接。
37、for in 和 for of 循环的区别 ? for in 用于遍历对象的键(key)for in会遍历所有自身的和原型链上的可枚举属性。如果是数组for in会将数组的索引(index)当做对象的key来遍历其他的object也是一样的。 for of是es6引入的语法用于遍历 所有迭代器iterator其中包括HTMLCollection,NodeList,ArrayMapSetStringTypedArrayarguments等对象的值(item)。
38、async/await 怎么抛出错误异常 ?
如果可能出错的代码比较少的时候可以使用try/catch结构来了处理如果可能出错的代码比较多的时候可以利用async函数返回一个promise对象的原理来处理给async修饰的函数调用后返回的promise对象调用catch方法来处理异常。
39、 函数式编程和命令式编程的区别 ? 命令式编程(过程式编程) : 专注于”如何去做”这样不管”做什么”都会按照你的命令去做。解决某一问题的具体算法实现。 函数式编程把运算过程尽量写成一系列嵌套的函数调用。 函数式编程强调没有”副作用”意味着函数要保持独立所有功能就是返回一个新的值没有其他行为尤其是不得修改外部变量的值。所谓”副作用”指的是函数内部与外部交互最典型的情况就是修改全局变量的值产生运算以外的其他结果。
40、http 常见的响应状态码 ? 100——客户必须继续发出请求101——客户要求服务器根据请求转换HTTP协议版本200——交易成功201——提示知道新文件的URL202——接受和处理、但处理未完成203——返回信息不确定或不完整204——请求收到但返回信息为空205——服务器完成了请求用户代理必须复位当前已经浏览过的文件206——服务器已经完成了部分用户的GET请求300——请求的资源可在多处得到301——删除请求数据302——在其他地址发现了请求数据303——建议客户访问其他URL或访问方式304——客户端已经执行了GET但文件未变化305——请求的资源必须从服务器指定的地址得到306——前一版本HTTP中使用的代码现行版本中不再使用307——申明请求的资源临时性删除400——错误请求如语法错误401——请求授权失败402——保留有效ChargeTo头响应403——请求不允许404——没有发现文件、查询或URl405——用户在Request-Line字段定义的方法不允许406——根据用户发送的Accept拖请求资源不可访问407——类似401用户必须首先在代理服务器上得到授权408——客户端没有在用户指定的饿时间内完成请求409——对当前资源状态请求不能完成410——服务器上不再有此资源且无进一步的参考地址411——服务器拒绝用户定义的Content-Length属性请求412——一个或多个请求头字段在当前请求中错误413——请求的资源大于服务器允许的大小414——请求的资源URL长于服务器允许的长度415——请求资源不支持请求项目格式416——请求中包含Range请求头字段在当前请求资源范围内没有range指示值请求也不包含If-Range请求头字段417——服务器不满足请求Expect头字段指定的期望值如果是代理服务器可能是下一级服务器不能满足请求500——服务器产生内部错误501——服务器不支持请求的函数502——服务器暂时不可用有时是为了防止发生系统过载503——服务器过载或暂停维修504——关口过载服务器使用另一个关口或服务来响应用户等待时间设定值较长505——服务器不支持或拒绝支请求头中指定的HTTP版本
41、 什么是事件流以及事件流的传播机制 ? 事件触发后从开始找目标元素然后执行目标元素的事件再到离开目标元素的整个过程称之为事件流。 W3C标准浏览器事件流的传播分为3个阶段捕获阶段、目标阶段、冒泡阶段 捕获阶段指找目标元素的过程这个找的过程是从最大的document对象到html再到body。。。直到目标元素。 找到目标元素后调用执行他绑定事件时对应的处理函数这个过程被称之为目标阶段。 当目标元素的事件执行结束后再从目标元素到他的父元素。。。body、html再到document的过程是冒泡阶段。
42、模块化语法 ? commonJS AMD CMD ES6 Module commonJS是nodejs自带的一种模块化语法将一个文件看做是一个模块可以将文件中导出的时候被另一个文件导入使用。导出使用module.exports导出。导入使用require函数导入。 AMD是社区开发的模块化语法需要依赖require.js实现分为定义模块导出数据和导入模块使用数据。AMD语法的导入是依赖前置的也就是说需要用到的文件需要在第一次打开页面全部加载完成造成的后果就是首屏加载很慢后续操作会很流畅。 CMD是玉伯开发的模块化语法需要依赖sea.js实现也分为模块定义导出和模块导入使用数据。CMD语法可以依赖前置也可以按需导入缓解了AMD语法的依赖前置。 ES6的模块化语法类似于commonJS的语法分为数据导出和数据导入导入导出更加灵活。
43、 什么是懒加载和预加载 ? 懒加载懒加载也叫延迟加载延迟加载网络资源或符合某些条件时才加载资源。常见的就是图片延时加载。懒加载的意义懒加载的主要目的是作为服务器前端的优化减少请求数或延迟请求数。懒惰实现方式 1.第一种是纯粹的延迟加载使用setTimeOut或setInterval进行加载延迟. 2.第二种是条件加载符合某些条件或触发了某些事件才开始异步下载。 3.第三种是可视区加载即仅加载用户可以看到的区域这个主要由监控滚动条来实现一般会在距用户看到某图片前一定距离便开始加载这样能保证用户拉下时正好能看到图片。 预加载提前加载图片当用户需要查看时可直接从本地缓存中渲染。 两者的行为是相反的一个是提前加载一个是迟缓甚至不加载。懒加载对服务器前端有一定的缓解压力作用预加载则会增加服务器前端压力。预加载应用如广告弹窗等。
44、token 一般存放在哪里 ? 为什么不存放在 cookie 内 ?
token一般放在本地存储中。token的存在本身只关心请求的安全性而不关心token本身的安全因为token是服务器端生成的可以理解为一种加密技术。但如果存在cookie内的话浏览器的请求默认会自动在请求头中携带cookie所以容易受到csrf攻击。
45、 less 和 sass 的区别 ? 编译环境不一样sass是服务器端处理的可以用Ruby、node-sass来编译less需要引入less.js来处理输出也可以使用工具在服务器端处理成css也有在线编译的。 变量定义符不一样less用的是而sass用$。 sass支持分支语句less不支持
44、浏览器的同源策略机制 ?
同源策略又称SOP全称Same Origin Policy是浏览器最基本的安全功能。站在浏览器的较短看网页如果网络上的接口可以不受限制、无需授权随意被人调用那将是一个非常严重的混乱场景。浏览器为了安全有序内部实现了同源策略。同源策略指的是浏览器限制当前网页只能访问同源的接口资源。所谓同源指当前页面和请求的接口两方必须是同协议、且同域名、且同端口。只要有一个不相同则会受到浏览器约束不允许请求。但当一个项目变的很大的时候将所有内容放在一个网站或一个服务器中会让网站变的臃肿且性能低下所以在一些场景中我们需要跨过同源策略请求到不同源的接口资源这种场景叫跨域。跨域大致有3种方案 jsonp 这种方式是利用浏览器不限制某些标签发送跨域请求例如link、img、iframe、script。通常请求请求回来的资源要在js中进行处理所以jsonp跨域是利用script标签进行发送且这种请求方式只能是get请求。 cors 这种方式是让接口资源方面进行授权授权允许访问。在接口资源处添加响应头即可通过浏览器的同源策略响应头具体的键值对如下 {Access-Control-Allow-Origin: *} proxy 这种方式属于找外援的一种方式浏览器只能限制当前正在打开的web页面发送请求但无法限制服务器端请求接口资源。所以我们可以将请求发送到自己服务器然后自己服务器去请求目标接口资源最后自己服务器将接口资源返回给当前页面类似于找外援代替自己请求目标接口资源。 这种方式通常要对服务器进行代理配置需要对apache服务器、nginx服务器、nodejs服务器进行配置。
45、 浏览器的缓存有哪些 ? 什么时候使用强制缓存 ? 什么时候使用协商缓存 ?
当我们访问同一个页面时请求资源、数据都是需要一定的耗时如果可以将一些资源缓存下来那么从第二次访问开始就可以减少加载时间提高用户体验也能减轻服务器的压力。浏览器缓存分为强缓存和协商缓存当存在缓存时客户端第一次向服务器请求数据时客户端会缓存到内存或者硬盘当中当第二次获取相同的资源强缓存和协商缓存的应对方式有所不同。强缓存当客户端第二次向服务器请求相同的资源时不会向服务器发送请求而是直接从内存/硬盘中间读取。缓存由服务器的响应头里 cache-control 和 expires 两个字段决定协商缓存当客户端第二次向服务器请求相同的资源时先向服务器发送请求询问该请求的文件缓存在bend与服务器相比是否更改如果更改则更新文件如果没有就从内存/硬盘中读取。协商缓存由 last-modified 和 etag两个字段决定
46、 数组方法 forEach 和 map 的区别 ?
forEach和map都是循环遍历数组中的每一项。forEach() 和 map() 里面每一次执行匿名函数都支持3个参数数组中的当前项item,当前项的索引index,原始数组input。匿名函数中的this都是指Window。只能遍历数组。他们的区别是forEach没有返回值但map中要有返回值返回处理后的所有新元素组成的数组。
47、 什么是函数作用域 ? 什么是作用域链 ?
作用域就是在代码执行过程中形成一个独立的空间让空间内的变量不会泄露在空间外也让独立空间内的变量函数在独立空间内运行而不会影响到外部的环境。作用域分为全局作用域和局部作用域也就是本来有一个巨大的空间空间内定义的函数内部就形成了一个独立的小空间全局作用域是最大的作用域。但是当独立空间内的数据不能满足需求时是可以从外部获取数据的也就是说这样的独立空间之间是可以有层级关系的外部的空间不可以从内部的空间获取数据但内部的空间可以。当子级空间在父级空间中获取数据的时父级空间没有的话父级空间也会到他的父级空间中查找数据这样形成的链式结构叫作用域链。当将一个变量当做值使用时会先在当前作用域中查找这个变量的定义和数据如果没有定义的话就会去父级作用域中查找如果父级作用域中有的话就使用这个值如果父级作用域中也没有的话就通过父级作用域查找他的父级作用域直到找到最大的作用域-全局如果全局也没有就报错。当将一个变量当做数据容器存储也就是给变量赋值的时候也要先在自己作用域中查找变量的定义如果没有就在上一级作用域中查找直到全局如果全局作用域中也没有这个变量的定义就在全局定义这个变量并赋值。
48、 ES6 中 Set 和 Map 的原理 ?
Set 是无重复值的有序列表。根据 Object.is()方法来判断其中的值不相等以保证无重复。Set 会自动移除重复的值因此你可以使用它来过滤数组中的重复值并返回结果。Set并不是数组的子类型所以你无法随机访问其中的值。但你可以使用has() 方法来判断某个值是否存在于 Set 中或通过 size 属性来查看其中有多少个值。Set 类型还拥有forEach()方法用于处理每个值Map 是有序的键值对其中的键允许是任何类型。与 Set 相似通过调用 Object.is()方法来判断重复的键这意味着能将数值 5 与字符串 5 作为两个相对独立的键。使用set() 方法能将任何类型的值关联到某个键上并且该值此后能用 get() 方法提取出来。Map 也拥有一个 size 属性与一个 forEach() 方法让项目访问更容易。
49、 0.1 0.2 为什么不等于 0.3, 在项目中遇到要怎么处理 ?
计算机内部存储数据使用2进制存储两个数字进行的数学运算首先是将这两个数字以2进制形式存储在计算机内部然后在计算机内部使用两个2进制数字进行计算最后将计算结果的2进制数字转为10进制展示出来。由于10进制的小数在转2进制的时候规则是小数部分乘以2判断是否得到一个整数如果得到整数转换完成如果没有得到整数则继续乘以2判断。所以0.1和0.2在转换2进制的时候其实是一个无限死循环也就是一直乘以2没有得到整数的时候但计算机内部对于无限死循环的数据会根据一个标准保留52位。也就是说计算机内部在存储0.1和0.2的时候本来就不精准两个不精准的小数在计算后距离精准的结果是有一定误差的。项目中碰到这种情况有3种处理方法 将小数乘以10的倍数转为整数然后计算计算完成后再缩小10的倍数例如 var result ((0.1 * 10) (0.2 * 10)) / 10 // result 0.3 使用数字的toFixed方法强制保留小数点后多少位例 var result (0.1 0.2).toFixed(2) // result 0.30 自定义数字运算方法当需要进行数学运算的时候不直接进行调用自定义的方法进行例加法封装 function add(...args){ var num args.find(item { if(item ! 0 !item){ throw new Error(数学运算要使用数字) } }) var arr args.map(item { var index (item).indexOf(.) if(index 0){ return (item).split(.)[1].length } }) arr arr.filter(item item) if(arr.length){ var max Math.max(...arr) var data args.map(item item * Math.pow(10, max)) var data.reduce((a, b) a b) / Math.pow(10, max) }else{ var data args return data.reduce((a, b) a b) } } // 调用使用 var num1 add(0.1, 0.2) console.log(num1); // 0.3 var num2 add(1, 2) console.log(num2); // 3 var num3 add(1, 2.1) console.log(num3); // 3.1
50、 什么是模块化思想 ?
就是JS中将不同功能的代码封装在不同的文件中, 互相引用时不会发生命名冲突的一种思想, 大多数情况下, 一个文件就是一个模块模块化的实现有多种方案 CommonJS CommonJS是nodejs中使用的模块化规范在 nodejs 应用中每个文件就是一个模块拥有自己的作用域文件中的变量、函数都是私有的与其他文件相隔离。模块导出module.exports数据模块导入require(模块文件路径) ES6的模块化 模块功能主要由两个命令构成export和import。export命令用于规定模块的对外接口import命令用于输入其他模块提供的功能。 一个模块就是一个独立的文件。该文件内部的所有变量外部无法获取。如果你希望外部能够读取模块内部的某个变量就必须使用export关键字输出该变量。下面是一个 JS 文件里面使用export命令输出变量。 AMD Asynchronous Module Definition 特点: 提倡依赖前置在定义模块的时候就要声明其依赖的模块导入模块require([module],callback);定义模块define(模块名称, 函数)。 CMD (Common Module Definition) CMD规范是国内SeaJS的推广过程中产生的。提倡就近依赖按需加载在用到某个模块的时候再去require。定义模块define(function (require, exports, module) {})使用模块seajs.use()
51、 说说怎么用js 写无缝轮播图
将所有需要轮播的内容动态复制一份放在原本的容器中加定时器让整个容器中的内容滚动轮播当内容轮播到left值为-原本的内容宽度时快速将内容切换到left值为0的状态。
52、 JS 如何实现多线程 ?
我们都知道JS是一种单线程语言即使是一些异步的事件也是在JS的主线程上运行的具体是怎么运行的可以看我另一篇博客JS代码运行机制。像setTimeout、ajax的异步请求或者是dom元素的一些事件都是在JS主线程执行的这些操作并没有在浏览器中开辟新的线程去执行而是当这些异步操作被操作时或者是被触发时才进入事件队列然后在JS主线程中开始运行。首先说一下浏览器的线程浏览器中主要的线程包括UI渲染线程JS主线程GUI事件触发线程http请求线程。JS作为脚本语言它的主要用途是与用户互动以及操作DOM。这决定了它只能是单线程否则会带来很复杂的同步问题。这里这些问题我们不做研究但是单线程的语言有一个很致命的确定。如果说一个脚本语言在执行时其中某一块的功能在执行时耗费了大量的时间那么就会造成阻塞。这样的项目用户体验是非常差的所以这种现象在项目的开发过程中是不允许存在的。其实JS为我们提供了一个Worker的类它的作用就是为了解决这种阻塞的现象。当我们使用这个类的时候它就会向浏览器申请一个新的线程。这个线程就用来单独执行一个js文件。 var worker new Worker(js文件路径);
那么这个语句就会申请一个线程用来执行这个js文件。这样也就实现了js的多线程。
53、 闭包的使用场景 ?
一个函数被当作值返回时也就相当于返回了一个通道这个通道可以访问这个函数词法作用域中的变量即函数所需要的数据结构保存了下来数据结构中的值在外层函数执行时创建外层函数执行完毕时理因销毁但由于内部函数作为值返回出去这些值得以保存下来。而且无法直接访问必须通过返回的函数。这也就是私有性。本来执行过程和词法作用域是封闭的这种返回的函数就好比是一个虫洞开了挂。闭包的形成很简单在执行过程完毕后返回函数或者将函数得以保留下来即形成闭包。 防抖 function debounce(fn, interval) { let timer null; // 定时器 return function() { // 清除上一次的定时器 clearTimeout(timer); // 拿到当前的函数作用域 let _this this; // 拿到当前函数的参数数组 let args Array.prototype.slice.call(arguments, 0); // 开启倒计时定时器 timer setTimeout(function() { // 通过apply传递当前函数this以及参数 fn.apply(_this, args); // 默认300ms执行 }, interval || 300) } } 节流 function throttle(fn, interval) { let timer null; // 定时器 let firstTime true; // 判断是否是第一次执行 // 利用闭包 return function() { // 拿到函数的参数数组 let args Array.prototype.slice.call(arguments, 0); // 拿到当前的函数作用域 let _this this; // 如果是第一次执行的话需要立即执行该函数 if(firstTime) { // 通过apply绑定当前函数的作用域以及传递参数 fn.apply(_this, args); // 修改标识为null释放内存 firstTime null; } // 如果当前有正在等待执行的函数则直接返回 if(timer) return; // 开启一个倒计时定时器 timer setTimeout(function() { // 通过apply绑定当前函数的作用域以及传递参数 fn.apply(_this, args); // 清除之前的定时器 timer null; // 默认300ms执行一次 }, interval || 300) } } 迭代器 var arr [aa,bb,cc]; function incre(arr){ var i0; return function(){ //这个函数每次被执行都返回数组arr中 i下标对应的元素 return arr[i] || 数组值已经遍历完; } } var next incre(arr); console.log(next());//aa console.log(next());//bb console.log(next());//cc console.log(next());//数组值已经遍历完 缓存 var fn(function(){ var cache{};//缓存对象 var calcfunction(arr){//计算函数 var sum0; //求和 for(var i0;iarr.length;i){ sumarr[i]; } return sum; } return function(){ var args Array.prototype.slice.call(arguments,0);//arguments转换成数组 var keyargs.join(,);//将args用逗号连接成字符串 var result , tSum cache[key]; if(tSum){//如果缓存有 console.log(从缓存中取,cache)//打印方便查看 result tSum; }else{ //重新计算并存入缓存同时赋值给result result cache[key]calc(args); console.log(存入缓存,cache)//打印方便查看 } return result; } })(); fn(1,2,3,4,5); fn(1,2,3,4,5); fn(1,2,3,4,5,6); fn(1,2,3,4,5,8); fn(1,2,3,4,5,6); getter和setter function fn(){ var namehello setNamefunction(n){ name n; } getNamefunction(){ return name; } //将setNamegetName作为对象的属性返回 return { setName:setName, getName:getName } } var fn1 fn();//返回对象属性setName和getName是两个函数 console.log(fn1.getName());//getter fn1.setName(world);//setter修改闭包里面的name console.log(fn1.getName());//getter 柯里化 function curryingCheck(reg) { return function(txt) { return reg.test(txt) } } var hasNumber curryingCheck(/\d/g) var hasLetter curryingCheck(/[a-z]/g) hasNumber(test1) // true hasNumber(testtest) // false hasLetter(21212) // false 循环中绑定事件或执行异步代码 var p1 ss; var p2 jj; function testSetTime(para1,para2){ return (function(){ console.log(para1 - para2); }) } var test testSetTime(p1, p2); setTimeout(test, 1000); setTimeout(function(){ console.log(p1 - p2) },1000) 单例模式 var Singleton (function () { var instance; function createInstance() { return new Object(I am the instance); } return { getInstance: function () { if (!instance) { instance createInstance(); } return instance; } }; })();
54、 常见的兼容问题有哪些 ? 获取标签节点 document.getElementsByClassName(类名)在低版本ie中不兼容。解决方法是使用其他方式获取 document.getElementById(id名) document.getElementsByTagName(标签名) document.getElementsByName(name属性值) document.querySelector(css选择器) document.querySelectorAll(css选择器)
获取卷去的高度 // 当有文档声明的时候 document.documentElement.scrollTop document.documentElement.srollLeft // 没有文档声明的时候 document.body.scrollTop document.body.scrollLeft 解决办法使用兼容写法
// 获取 var t document.documentElement.scrollTop || document.body.scrollTop var l document.documentElement.srollLeft || document.body.scrollLeft // 设置 document.documentElement.scrollTop document.body.scrollTop 数值 document.documentElement.srollLeft document.body.scrollLeft 数值 获取样式 // W3C标准浏览器 window.getComputedStyle(元素) // 低版本IE中 元素.currentStyle 使用函数封装的方式兼容 function getStyle(ele,attr){ if(window.getComputedStyle){ return getComputedStyle(ele)[attr] }else{ return ele.currentStyle[attr] } } 事件侦听器 // W3C浏览器 ele.addEventListener(事件类型,函数) // 低版本Ie ele.attachEvent(on事件类型,函数) 使用函数封装的方式解决 function bindEvent(ele,type,handler){ if(ele.addEventListener){ ele.addEventListener(type,handler) }else if(ele.attachEvent){ ele.attachEvent(ontype,handler) }else{ ele[ontype] handler } } 事件解绑 // W3C浏览器 ele.removeEventListener(事件类型,函数) // 低版本Ie ele.detachEvent(on事件类型,函数) 使用函数封装的方式解决 function unBind(ele,type,handler){ if(ele.removeEventListener){ ele.removeEventListener(type,handler) }else if(ele.detachEvent){ ele.detachEvent(ontype,handler) }else{ ele[ontype] null } } 事件对象的获取 // W3C浏览器 元素.on事件类型 function(e){} 元素.addEventListener(事件类型,fn) function fn(e){ } // 在低版本IE中 元素.on事件类型 function(){ window.event } 元素.addEventListener(事件类型,fn) function fn(){ window.event } 使用短路运算符解决 元素.on事件类型 function(e){ var e e || window.event } 元素.addEventListener(事件类型,fn) function fn(e){ var e e || window.event } 阻止默认行为 // W3C浏览器 元素.on事件类型 function(e){ e.preventDefault() } // 在低版本IE中 元素.on事件类型 function(){ window.event.returnValue false } 通过封装函数解决 元素.on事件类型 function(e){ var e e || window.event e.preventDefault?e.preventDefault():e.returnValuefalse } 阻止事件冒泡 // W3C浏览器 元素.on事件类型 function(e){ e.stopPropagation() } // 在低版本IE中 元素.on事件类型 function(){ window.event.cancelBubble true } 通过函数封装解决 元素.on事件类型 function(e){ var e e || window.event e.stopPropagation?e.stopPropagation():e.cancelBubbletrue } 获取精准的目标元素 // W3C浏览器 元素.on事件类型 function(e){ e.target } // 在低版本IE中 元素.on事件类型 function(){ window.event.srcElement } 通过短路运算符解决 元素.on事件类型 function(e){ var e e || window.event var target e.target || e.srcElement; } 获取键盘码 // W3C浏览器 元素.on事件类型 function(e){ e.keyCode } // 在低版本火狐中 元素.on事件类型 function(e){ e.which } 通过短路运算符解决 元素.on事件类型 function(e){ var e e || window.event var keycode e.keyCode || e.which; } 55、 在 JS 中如何阻止事件冒泡 ?
使用事件对象阻止事件冒泡以前的w3c浏览器中使用事件对象的方法阻止 事件对象.stopPropagation()
在ie低版本浏览器中使用事件对象的属性阻止 事件对象.cancelBubble true
现在的w3c浏览器也支持ie低版本浏览器中的写法所以以前在阻止事件冒泡的时候需要考虑兼容写法现在就不需要了直接用ie低版本浏览器中的写法即可。
56、两个数组 var A [1, 5, 6]; var B [2, 6, 7]实现一个方法找出仅存在于A 或者 仅 存在于B中的所有数字。
function getDiff(arr, brr){ // 仅存在于arr中的内容 var onlyArr arr.filter(item !brr.some(v item v)) // 仅存在于brr中的内容 var onlyBrr brr.filter(v !arr.some(item v item)) // 需要哪个就返回哪个或者一起返回 return { 仅存在于arr中的内容: onlyArr, 仅存在于brr中的内容: onlyBrr } } 57、 你了解构造函数吗 ? class 是什么 ? 两者有什么区别 ? 在es5中构造函数其实就是在定义一个类可以实例化对象es6中class其实是构造函数的语法糖。但还是有点区别的 在class内部和class的方法内部默认使用严格模式 class类不存在预解析也就是不能先调用class生成实例再定义class类但是构造函数可以。 class中定义的方法默认不能被枚举也就是不能被遍历。 class必须使用new执行但是构造函数没有new也可以执行。 class中的所有方法都没有原型也就不能被new class中继承可以继承静态方法但是构造函数的继承不能。
58、是否存在a的值a0 a1为true 的情况 ?
var value -1 Object.defineProperty(window,a,{ get(){ return value1; } }) if(a0a1){ // true console.log(success) } 59、for (var i 0; i 5; i) { setTimeout(function() { console.log(i); }, 1000); } 要求输出01234
首先这个面试题考察的是对于js中异步代码以及作用域的理解js中常见的异步代码包括定时器和ajax。js执行代码的流程是碰到同步代码就执行碰到异步就交给浏览器的webAPI处理当webAPI中的异步该执行时webAPI会将需要执行的回调函数放在任务队列中等候执行所以js中所有的异步代码总会在所有同步代码执行结束后再执行任务队列中的代码。在这个问题中循环是同步代码定时器是异步代码所以整个循环都执行结束以后才会执行定时器代码。for循环中使用var定义的变量是全局变量定时器回调函数中输出变量的时候根据作用域规则先在当前作用域中变量i的定义表达式如果没有找到就去上一级作用域中找此时在局部作用域中没有找到去上级作用域中也就是全局找到了全局中的i因为循环已经执行结束了所以i的值是5。最终会输出5个5。其次考察的是对于类似问题的解决方式间接性判断你是否有过类似情况的开发这个问题的解决思路就是让回调函数中输出i的时候不要去全局中找i因为全局的i在循环执行结束后已经变成5了根据这个思路有2种解决办法 在异步代码外面嵌套一层函数作用域 for(var i 0;i 5; i){ (function(i) { setTimeout(function() { console.log(i) }, 1000) })(i) }
原理是自调用函数会产生作用域循环5次就会产生5个作用域每个作用域代码在执行的时候都有形参i传递。所以每个作用域中的i都是不同的分别是0 1 2 3 4。当作用域中的异步代码执行的时候自己作用域中没有i变量的定义然后上级作用域就是自调用函数的作用域找到了单独的i。最终可以输出0 1 2 3 4 将循环代码中的var换成es6的let for(let i 0;i 5; i){ setTimeout(function() { console.log(i) }, 1000) }
es6的let自带块级作用域原理跟第一种解决思路是一样的转成es5后代码是一样的。
60、实现一个 add 方法 使计算结果能够满足如下预期 - add(1)(2)(3)() 6 - add(1,2,3)(4)() 10
function add (...args) { if(args.length 3){ return -(args[0] * args[1] * 2 args[2] * 2) }else{ return -args[args.length-1] } } function currying (fn) { let args [] return function _c (...newArgs) { if (newArgs.length) { args [ ...args, ...newArgs ] return _c } else { return fn.apply(this, args) } } } let addCurry currying(add) var a addCurry(1)(2)(3)() console.log(-a); // 10 var b addCurry(1,2,3)(4)() console.log(6 - b); // 10