JavaScript 的组成
ES,DOM,BOMjavascript
转Boolean
在条件判断时,除了 undefined
, null
, false
, NaN
, ''
, 0
, -0
,其余全部值都转为 true
,包括全部对象。css
对象转基本类型
对象在转换基本类型时,首先会调用 valueOf
而后调用 toString
。java
JS 的基本数据类型和引用数据类型
基本:null,underfined,number,string,symbol,booleanajax
引用:Array,Object,Functionexpress
检测浏览器版本版本有哪些方式?
- 根据 navigator.userAgent
- 根据 window 对象的成员 // 'ActiveXObject' in window
介绍 JS 有哪些内置对象?
- 数据封装类对象:Object、Array、Boolean、Number、String
- 其余对象:Function、Arguments、Math、Date、RegExp、Error
- ES6 新增对象:Symbol、Map、Set、Promises、Proxy、Reflect
如何编写高性能的 JavaScript?
- 遵循严格模式:"use strict";
- 将 js 脚本放在页面底部,加快渲染页面
- 将 js 脚本将脚本成组打包,减小请求
- 尽可能使用局部变量来保存全局变量
- 尽可能减小使用闭包
- 缓存 DOM 节点的访问
- 给 setTimeout() 和 setInterval() 传递函数而不是字符串做为参数
- 最小化重绘(repaint)和回流(reflow)
offsetWidth/offsetHeight,clientWidth/clientHeight 与 scrollWidth/scrollHeight 的区别
- offsetWidth/offsetHeight 返回值包含 content + padding + border,效果与 e.getBoundingClientRect()相同
- clientWidth/clientHeight 返回值只包含 content + padding,若是有滚动条,也不包含滚动条
- scrollWidth/scrollHeight 返回值包含 content + padding + 溢出内容的尺寸
描述浏览器的渲染过程
- 解析 HTML 构建 DOM(DOM 树),并行请求 css/image/js
- CSS 文件下载完成,开始构建 CSSOM(CSS 树)
- CSSOM 构建结束后,和 DOM 一块儿生成 Render Tree(渲染树)
- 布局(Layout):计算出每一个节点在屏幕中的位置
- 显示(Painting):经过显卡把页面画到屏幕上
DOM 树 和 渲染树 的区别:设计模式
- DOM 树与 HTML 标签一一对应,包括 head 和隐藏元素
- 渲染树不包括 head 和隐藏元素,每个节点都有对应的 css 属性
重绘和回流(重排)的区别和关系?
- 重绘:当渲染树中的元素外观(如:颜色)发生改变,不影响布局时,产生重绘
- 回流:当渲染树中的元素的布局(如:尺寸、位置、隐藏/状态状态)发生改变时,产生重绘回流
- 注意:JS 获取 Layout 属性值(如:offsetLeft、scrollTop、getComputedStyle 等)也会引发回流。由于浏览器须要经过回流计算最新值
- 回流必将引发重绘,而重绘不必定会引发回流
如何最小化重绘(repaint)和回流(reflow)?
- 须要要对元素进行复杂的操做时,能够先隐藏(display:"none"),操做完成后再显示
- 须要建立多个 DOM 节点时,使用 DocumentFragment 建立完后一次性的加入 document
- 缓存 Layout 属性值,如:var left = elem.offsetLeft; 这样,屡次使用 left 只产生一次回流
- 尽可能避免用 table 布局(table 元素一旦触发回流就会致使 table 里全部的其它元素回流)
- 避免使用 css 表达式(expression),由于每次调用都会从新计算值(包括加载页面)
- 尽可能使用 css 属性简写,如:用 border 代替 border-width, border-style, border-color 批量修改元素样式:elem.className 和 elem.style.cssText 代替 elem.style.xxx
script 的位置是否会影响首屏显示时间?
- 浏览器解析 HTML 是自上而下的线性过程,script 做为 HTML 的一部分一样遵循这个原则
- 所以,script 会延迟 DomContentLoad,只显示其上部分首屏内容,从而影响首屏显示的完成时间
解释 JavaScript 中的做用域与变量声明提高?
Js中做用域是函数做用域,浏览器
函数声明与变量声明常常被 JavaScript 引擎隐式地提高到当前做用域的顶部。缓存
函数声明的优先级高于变量安全
JavaScript 的原型,原型链?
原型链:多线程
- 当一个对象调用的属性/方法自身不存在时,就会去本身 [proto] 关联的前辈 prototype 对象上去找
- 若是没找到,就会去该 prototype 原型 [proto] 关联的前辈 prototype 去找。依次类推,直到找到属性/方法或 undefined 为止。从而造成了所谓的“原型链”
原型特色:
- JavaScript 对象是经过引用来传递的,当修改原型时,与之相关的对象也会继承这一改变
JavaScript 如何实现一个类,怎么实例化这个类?
1.new
2.Object.create
3.class
javascript 建立对象的几种方式?
- 对象字面量的方式
- 构造函数
- 工厂模式
- 混合方式
Javascript 如何实现继承?
- 构造函数绑定:使用 call 或 apply 方法,将父对象的构造函数绑定在子对象上
- 实例继承:将子对象的 prototype 指向父对象的一个实例
- 拷贝继承:若是把父对象的全部属性和方法,拷贝进子对象
- 原型继承:将子对象的 prototype 指向父对象的 prototype
- ES6 语法糖 extends:class ColorPoint extends Point {}
js 继承方式及其优缺点
原型链继承的缺点
- 一是字面量重写原型会中断关系,使用引用类型的原型,而且子类型还没法给超类型传递参数。
借用构造函数(类式继承)
- 借用构造函数虽然解决了刚才两种问题,但没有原型,则复用无从谈起。因此咱们须要原型链+借用构造函数的模式,这种模式称为组合继承
组合式继承
- 组合式继承是比较经常使用的一种继承方法,其背后的思路是使用原型链实现对原型属性和方法的继承,而经过借用构造函数来实现对实例属性的继承。这样,既经过在原型上定义方法实现了函数复用,又保证每一个实例都有它本身的属性。
Javascript 做用链域?
- 若是当前做用域没有找到属性或方法,会向上层做用域查找,直至全局函数,这种形式就是做用域链
在一个 DOM 上同时绑定两个点击事件:一个用捕获,一个用冒泡。事件会执行几回,先执行冒泡仍是捕获?
- 该 DOM 上的事件若是被触发,会执行两次(执行次数等于绑定次数)
- 若是该 DOM 是目标元素,则按事件绑定顺序执行,不区分冒泡/捕获
- 若是该 DOM 是处于事件流中的非目标元素,则先执行捕获,后执行冒泡
谈谈 this 对象的理解
1.是否在new中调用,this=>新建立的对象
2.时候经过apply,call或者硬绑定,this=>指定对象
3.时候有某个上下文对象中调用obj.foo(),this=>obj
4.this=>window(underfined)
事件的代理/委托
事件委托是指将事件绑定目标元素的到父元素上,利用冒泡机制触发该事件
优势:
- 能够减小事件注册,节省大量内存占用
- 能够将事件应用于动态添加的子元素上
如何派发事件(dispatchEvent)?(如何进行事件广播?)
- W3C: 使用 dispatchEvent 方法
- IE: 使用 fireEvent 方法
var fireEvent = function(element, event){ if (document.createEventObject){ var mockEvent = document.createEventObject(); return element.fireEvent('on' + event, mockEvent) }else{ var mockEvent = document.createEvent('HTMLEvents'); mockEvent.initEvent(event, true, true); return !element.dispatchEvent(mockEvent); } }
什么是函数节流?介绍一下应用场景和原理?
- 函数节流(throttle)是指阻止一个函数在很短期间隔内连续调用。 只有当上一次函数执行后达到规定的时间间隔,才能进行下一次调用。 但要保证一个累计最小调用间隔(不然拖拽类的节流都将无连续效果)
- 函数节流用于 onresize, onscroll 等短期内会屡次触发的事件
- 函数节流的原理:使用定时器作时间节流。 当触发一个事件时,先用 setTimout 让这个事件延迟一小段时间再执行。 若是在这个时间间隔内又触发了事件,就 clearTimeout 原来的定时器, 再 setTimeout 一个新的定时器重复以上流程。
函数节流简单实现:
function throttle(method, context) { clearTimeout(methor.tId); method.tId = setTimeout(function(){ method.call(context); }, 100); // 两次调用至少间隔 100ms } // 调用 window.onresize = function(){ throttle(myFunc, window); }
区分什么是“客户区坐标”、“页面坐标”、“屏幕坐标”?
- 客户区坐标:鼠标指针在可视区中的水平坐标(clientX)和垂直坐标(clientY)
- 页面坐标:鼠标指针在页面布局中的水平坐标(pageX)和垂直坐标(pageY)
- 屏幕坐标:设备物理屏幕的水平坐标(screenX)和垂直坐标(screenY)
如何得到一个 DOM 元素的绝对位置?
- elem.offsetLeft:返回元素相对于其定位父级左侧的距离
- elem.offsetTop:返回元素相对于其定位父级顶部的距离
- elem.getBoundingClientRect():返回一个 DOMRect 对象,包含一组描述边框的只读属性,单位像素
new 操做符具体干了什么?
1.创造一个全新的对象
2.这个新对象会被执行[[Prototype]]链接
3.这个新对象会绑定到函数调用的this
4.若是函数没有返回其余对象,自动返回这个新对象
new会改变硬绑定函数的this,使用new硬绑定函数主要是为了预先设置函数的一些参数
function create() {
// 建立一个空的对象
let obj = new Object()
// 得到构造函数
let Con = [].shift.call(arguments)
// 连接到原型
obj.__proto__ = Con.prototype
// 绑定 this,执行构造函数
let result = Con.apply(obj, arguments)
// 确保 new 出来的是个对象
return typeof result === 'object' ? result : obj
}
什么是闭包(closure),为何要用它?
闭包是指有权访问另外一个函数做用域中变量的函数,建立闭包的最多见的方式就是在一个函数内建立另外一个函数,经过另外一个函数访问这个函数的局部变量,利用闭包能够突破做用链域
闭包的特性:
- 函数内再嵌套函数
- 内部函数能够引用外层的参数和变量
- 参数和变量不会被垃圾回收机制回收
用过哪些设计模式?
- 工厂模式:
- 主要好处就是能够消除对象间的耦合,经过使用工程方法而不是 new 关键字。将全部实例化的代码集中在一个位置防止代码重复
- 工厂模式解决了重复实例化的问题 ,但还有一个问题,那就是识别问题,由于根本没法 搞清楚他们究竟是哪一个对象的实例
- 构造函数模式
请解释一下 JavaScript 的同源策略
这里的同源策略指的是:协议,域名,端口相同,同源策略是一种安全协议
实现一个函数 clone,能够对 JavaScript 中的 5 种主要的数据类型(包括 Number、String、Object、Array、Boolean)进行值复制(常考)
function deepClone(obj) { if (!isObject(obj)) { throw new Error('obj 不是一个对象!') } let isArray = Array.isArray(obj) let cloneObj = isArray ? [] : {} for (let key in obj) { cloneObj[key] = isObject(obj[key]) ? deepClone(obj[key]) : obj[key] } return cloneObj }
哪些操做会形成内存泄漏?
- JavaScript 内存泄露指对象在不须要使用它时仍然存在,致使占用的内存不能使用或回收
- 未使用 var 声明的全局变量
- 闭包函数(Closures)
- 循环引用(两个对象相互引用)
- 控制台日志(console.log)
- 移除存在绑定事件的 DOM 元素(IE)
为何 JS 是单线程,而不是多线程 [常考]
- 单线程是指 JavaScript 在执行的时候,有且只有一个主线程来处理全部的任务。
- 目的是为了实现与浏览器交互。
- 咱们设想一下,若是 JavaScript 是多线程的,如今咱们在浏览器中同时操做一个 DOM,一个线程要求浏览器在这个 DOM 中添加节点,而另外一个线程却要求浏览器删掉这个 DOM 节点,那这个时候浏览器就会很郁闷,他不知道应该以哪一个线程为准。因此为了不此类现象的发生,下降复杂度,JavaScript 选择只用一个主线程来执行代码,以此来保证程序执行的一致性。
浏览器中的 Event Loop

- 主线程运行的时候会生成堆(heap)和栈(stack);
- js 从上到下解析方法,将其中的同步任务按照执行顺序排列到执行栈中;
- 当程序调用外部的 API 时,好比 ajax、setTimeout 等,会将此类异步任务挂起,继续执行执行栈中的任务,等异步任务返回结果后,再按照执行顺序排列到事件队列中;
- 主线程先将执行栈中的同步任务清空,而后检查事件队列中是否有任务,若是有,就将第一个事件对应的回调推到执行栈中执行,若在执行过程当中遇到异步任务,则继续将这个异步任务排列到事件队列中。
- 主线程每次将执行栈清空后,就去事件队列中检查是否有任务,若是有,就每次取出一个推到执行栈中执行,这个过程是循环往复的... ...,这个过程被称为“Event Loop 事件循环”