前端面试题JavaScript(一)
JavaScript的组成javascript
-
JavaScript 由如下三部分组成:css
- ECMAScript(核心):JavaScript 语言基础
- DOM(文档对象模型):规定了访问HTML和XML的接口
- BOM(浏览器对象模型):提供了浏览器窗口之间进行交互的对象和方法
JS的基本数据类型和引用数据类型html
- 基本数据类型:undefined、null、boolean、number、string、symbol
- 引用数据类型:object、array、function
检测浏览器版本版本有哪些方式?前端
- 根据 navigator.userAgent // UA.toLowerCase().indexOf('chrome')
- 根据 window 对象的成员 // 'ActiveXObject' in window
介绍JS有哪些内置对象?java
- 数据封装类对象:Object、Array、Boolean、Number、String
- 其余对象:Function、Arguments、Math、Date、RegExp、Error
- ES6新增对象:Symbol、Map、Set、Promises、Proxy、Reflect
说几条写JavaScript的基本规范?node
- 代码缩进,建议使用“四个空格”缩进
- 代码段使用花括号{}包裹
- 语句结束使用分号;
- 变量和函数在使用前进行声明
- 以大写字母开头命名构造函数,全大写命名常量
- 规范定义JSON对象,补全双引号
- 用{}和[]声明对象和数组
如何编写高性能的JavaScript?git
- 遵循严格模式:"use strict";
- 将js脚本放在页面底部,加快渲染页面
- 将js脚本将脚本成组打包,减小请求
- 使用非阻塞方式下载js脚本
- 尽可能使用局部变量来保存全局变量
- 尽可能减小使用闭包
- 使用 window 对象属性方法时,省略 window
- 尽可能减小对象成员嵌套
- 缓存 DOM 节点的访问
- 经过避免使用 eval() 和 Function() 构造器
- 给 setTimeout() 和 setInterval() 传递函数而不是字符串做为参数
- 尽可能使用直接量建立对象和数组
- 最小化重绘(repaint)和回流(reflow)
描述浏览器的渲染过程,DOM树和渲染树的区别?程序员
-
浏览器的渲染过程:github
- 解析HTML构建 DOM(DOM树),并行请求 css/image/js
- CSS 文件下载完成,开始构建 CSSOM(CSS树)
- CSSOM 构建结束后,和 DOM 一块儿生成 Render Tree(渲染树)
- 布局(Layout):计算出每一个节点在屏幕中的位置
- 显示(Painting):经过显卡把页面画到屏幕上
-
DOM树 和 渲染树 的区别:web
- 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 生成 DOM 过程当中,js 文件的下载是并行的,不须要 DOM 处理到 script 节点。所以,script的位置不影响首屏显示的开始时间。
- 浏览器解析 HTML 是自上而下的线性过程,script做为 HTML 的一部分一样遵循这个原则
- 所以,script 会延迟 DomContentLoad,只显示其上部分首屏内容,从而影响首屏显示的完成时间
解释JavaScript中的做用域与变量声明提高?
-
JavaScript做用域:
- 在Java、C等语言中,做用域为for语句、if语句或{}内的一块区域,称为做用域;
- 而在 JavaScript 中,做用域为function(){}内的区域,称为函数做用域。
-
JavaScript变量声明提高:
- 在JavaScript中,函数声明与变量声明常常被JavaScript引擎隐式地提高到当前做用域的顶部。
- 声明语句中的赋值部分并不会被提高,只有名称被提高
- 函数声明的优先级高于变量,若是变量名跟函数名相同且未赋值,则函数声明会覆盖变量声明
- 若是函数有多个同名参数,那么最后一个参数(即便没有定义)会覆盖前面的同名参数
介绍JavaScript的原型,原型链?有什么特色?
-
原型:
- JavaScript的全部对象中都包含了一个 [__proto__] 内部属性,这个属性所对应的就是该对象的原型
- JavaScript的函数对象,除了原型 [__proto__] 以外,还预置了 prototype 属性
- 当函数对象做为构造函数建立实例时,该 prototype 属性值将被做为实例对象的原型 [__proto__]。
-
原型链:
- 当一个对象调用的属性/方法自身不存在时,就会去本身 [__proto__] 关联的前辈 prototype 对象上去找
- 若是没找到,就会去该 prototype 原型 [__proto__] 关联的前辈 prototype 去找。依次类推,直到找到属性/方法或 undefined 为止。从而造成了所谓的“原型链”
-
原型特色:
- JavaScript对象是经过引用来传递的,当修改原型时,与之相关的对象也会继承这一改变
JavaScript有几种类型的值
- 原始数据类型(Undefined,Null,Boolean,Number、String)-- 栈
- 引用数据类型(对象、数组和函数)-- 堆
- 两种类型的区别是:存储位置不一样:
- 原始数据类型是直接存储在栈(stack)中的简单数据段,占据空间小、大小固定,属于被频繁使用数据;
- 引用数据类型存储在堆(heap)中的对象,占据空间大、大小不固定,若是存储在栈中,将会影响程序运行的性能;
- 引用数据类型在栈中存储了指针,该指针指向堆中该实体的起始地址。
- 当解释器寻找引用值时,会首先检索其在栈中的地址,取得地址后从堆中得到实体。
JavaScript如何实现一个类,怎么实例化这个类?
-
构造函数法(this + prototype) -- 用 new 关键字 生成实例对象
- 缺点:用到了 this 和 prototype,编写复杂,可读性差
function Mobile(name, price){ this.name = name; this.price = price; } Mobile.prototype.sell = function(){ alert(this.name + ",售价 $" + this.price); } var iPhone7 = new Mobile("iPhone7", 1000); iPhone7.sell();
- Object.create 法 -- 用 Object.create() 生成实例对象
- 缺点:不能实现私有属性和私有方法,实例对象之间也不能共享数据
var Person = { firstname: "Mark", lastname: "Yun", age: 25, introduce: function(){ alert('I am ' + Person.firstname + ' ' + Person.lastname); } }; var person = Object.create(Person); person.introduce(); // Object.create 要求 IE9+,低版本浏览器能够自行部署: if (!Object.create) { Object.create = function (o) { function F() {} F.prototype = o; return new F(); }; }
-
极简主义法(消除 this 和 prototype) -- 调用 createNew() 获得实例对象
- 优势:容易理解,结构清晰优雅,符合传统的"面向对象编程"的构造
var Cat = { age: 3, // 共享数据 -- 定义在类对象内,createNew() 外 createNew: function () { var cat = {}; // var cat = Animal.createNew(); // 继承 Animal 类 cat.name = "小咪"; var sound = "喵喵喵"; // 私有属性--定义在 createNew() 内,输出对象外 cat.makeSound = function () { alert(sound); // 暴露私有属性 }; cat.changeAge = function(num){ Cat.age = num; // 修改共享数据 }; return cat; // 输出对象 } }; var cat = Cat.createNew(); cat.makeSound();
- ES6 语法糖 class -- 用 new 关键字 生成实例对象
class Point { constructor(x, y) { this.x = x; this.y = y; } toString() { return '(' + this.x + ', ' + this.y + ')'; } } var point = new Point(2, 3);
Javascript如何实现继承?
- 构造函数绑定:使用 call 或 apply 方法,将父对象的构造函数绑定在子对象上
function Cat(name,color){ Animal.apply(this, arguments); this.name = name; this.color = color; }
- 实例继承:将子对象的 prototype 指向父对象的一个实例
Cat.prototype = new Animal(); Cat.prototype.constructor = Cat;
- 拷贝继承:若是把父对象的全部属性和方法,拷贝进子对象
function extend(Child, Parent) { var p = Parent.prototype; var c = Child.prototype; for (var i in p) { c[i] = p[i]; } c.uber = p; }
- 原型继承:将子对象的 prototype 指向父对象的 prototype
function extend(Child, Parent) { var F = function(){}; F.prototype = Parent.prototype; Child.prototype = new F(); Child.prototype.constructor = Child; Child.uber = Parent.prototype; }
- ES6 语法糖 extends:class ColorPoint extends Point {}
class ColorPoint extends Point { constructor(x, y, color) { super(x, y); // 调用父类的constructor(x, y) this.color = color; } toString() { return this.color + ' ' + super.toString(); // 调用父类的toString() } }
谈谈this对象的理解
- this 老是指向函数的直接调用者
- 若是有 new 关键字,this 指向 new 出来的实例对象
- 在事件中,this指向触发这个事件的对象
- IE下 attachEvent 中的this老是指向全局对象Window
eval是作什么的?
eval的功能是把对应的字符串解析成JS代码并运行
- 应该避免使用eval,不安全,很是耗性能(先解析成js语句,再执行)
- 由JSON字符串转换为JSON对象的时候能够用 eval('('+ str +')');
什么是 Window 对象? 什么是 Document 对象?
- Window 对象表示当前浏览器的窗口,是JavaScript的顶级对象。
- 咱们建立的全部对象、函数、变量都是 Window 对象的成员。
- Window 对象的方法和属性是在全局范围内有效的。
- Document 对象是 HTML 文档的根节点与全部其余节点(元素节点,文本节点,属性节点, 注释节点)
- Document 对象使咱们能够经过脚本对 HTML 页面中的全部元素进行访问
- Document 对象是 Window 对象的一部分,可经过 window.document 属性对其进行访问
介绍 DOM 的发展
- DOM:文档对象模型(Document Object Model),定义了访问HTML和XML文档的标准,与编程语言及平台无关
- DOM0:提供了查询和操做Web文档的内容API。未造成标准,实现混乱。如:document.forms['login']
- DOM1:W3C提出标准化的DOM,简化了对文档中任意部分的访问和操做。如:JavaScript中的Document对象
- DOM2:原来DOM基础上扩充了鼠标事件等细分模块,增长了对CSS的支持。如:getComputedStyle(elem, pseudo)
- DOM3:增长了XPath模块和加载与保存(Load and Save)模块。如:XPathEvaluator
介绍DOM0,DOM2,DOM3事件处理方式区别
-
DOM0级事件处理方式:
btn.onclick = func;
btn.onclick = null;
-
DOM2级事件处理方式:
btn.addEventListener('click', func, false);
btn.removeEventListener('click', func, false);
btn.attachEvent("onclick", func);
btn.detachEvent("onclick", func);
-
DOM3级事件处理方式:
eventUtil.addListener(input, "textInput", func);
-
eventUtil
是自定义对象,textInput
是DOM3级事件
事件的三个阶段
- 捕获、目标、冒泡
介绍事件“捕获”和“冒泡”执行顺序和事件的执行次数?
- 按照W3C标准的事件:首是进入捕获阶段,直到达到目标元素,再进入冒泡阶段
-
事件执行次数(DOM2-addEventListener):元素上绑定事件的个数
- 注意1:前提是事件被确实触发
- 注意2:事件绑定几回就算几个事件,即便类型和功能彻底同样也不会“覆盖”
-
事件执行顺序:判断的关键是否目标元素
- 非目标元素:根据W3C的标准执行:捕获->目标元素->冒泡(不依据事件绑定顺序)
- 目标元素:依据事件绑定顺序:先绑定的事件先执行(不依据捕获冒泡标准)
- 最终顺序:父元素捕获->目标元素事件1->目标元素事件2->子元素捕获->子元素冒泡->父元素冒泡
- 注意:子元素事件执行前提 事件确实“落”到子元素布局区域上,而不是简单的具备嵌套关系
在一个DOM上同时绑定两个点击事件:一个用捕获,一个用冒泡。事件会执行几回,先执行冒泡仍是捕获?
- 该DOM上的事件若是被触发,会执行两次(执行次数等于绑定次数)
- 若是该DOM是目标元素,则按事件绑定顺序执行,不区分冒泡/捕获
- 若是该DOM是处于事件流中的非目标元素,则先执行捕获,后执行冒泡
事件的代理/委托
-
事件委托是指将事件绑定目标元素的到父元素上,利用冒泡机制触发该事件
-
优势:
- 能够减小事件注册,节省大量内存占用
- 能够将事件应用于动态添加的子元素上
- 缺点:
使用不当会形成事件在不该该触发时触发 - 示例:
-
ulEl.addEventListener('click', function(e){ var target = event.target || event.srcElement; if(!!target && target.nodeName.toUpperCase() === "LI"){ console.log(target.innerHTML); } }, false);
IE与火狐的事件机制有什么区别? 如何阻止冒泡?
- IE只事件冒泡,不支持事件捕获;火狐同时支持件冒泡和事件捕获
IE的事件处理和W3C的事件处理有哪些区别?
-
绑定事件
- W3C: targetEl.addEventListener('click', handler, false);
- IE: targetEl.attachEvent('onclick', handler);
-
删除事件
- W3C: targetEl.removeEventListener('click', handler, false);
- IE: targetEl.detachEvent(event, handler);
-
事件对象
- W3C: var e = arguments.callee.caller.arguments[0]
- IE: window.event
-
事件目标
- W3C: e.target
- IE: window.event.srcElement
-
阻止事件默认行为
- W3C: e.preventDefault()
- IE: window.event.returnValue = false
-
阻止事件传播
- W3C: e.stopPropagation()
- IE: window.event.cancelBubble = true
W3C事件的 target 与 currentTarget 的区别?
- target 只会出如今事件流的目标阶段
- currentTarget 可能出如今事件流的任何阶段
- 当事件流处在目标阶段时,两者的指向相同
- 当事件流处于捕获或冒泡阶段时:currentTarget 指向当前事件活动的对象(通常为父级)
如何派发事件(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对象,包含一组描述边框的只读属性,单位像素
分析 ['1', '2', '3'].map(parseInt) 答案是多少?
- 答案:[1, NaN, NaN]
- parseInt(string, radix) 第2个参数 radix 表示进制。省略 radix 或 radix = 0,则数字将以十进制解析
- map 每次为 parseInt 传3个参数(elem, index, array),其中 index 为数组索引
- 所以,map 遍历 ["1", "2", "3"],相应 parseInt 接收参数以下
parseInt('1', 0); // 1 parseInt('2', 1); // NaN parseInt('3', 2); // NaN
- 因此,parseInt 参数 radix 不合法,致使返回值为 NaN
new 操做符具体干了什么?
- 建立实例对象,this 变量引用该对象,同时还继承了构造函数的原型
- 属性和方法被加入到 this 引用的对象中
- 新建立的对象由 this 所引用,而且最后隐式的返回 this
用原生JavaScript的实现过什么功能吗?
- 封装选择器、调用第三方API、设置和获取样式
解释一下这段代码的意思吗?
[].forEach.call($$("*"), function(el){ el.style.outline = "1px solid #" + (~~(Math.random()*(1<<24))).toString(16); })
- 解释:获取页面全部的元素,遍历这些元素,为它们添加1像素随机颜色的轮廓(outline)
- $$(sel)// $$函数被许多现代浏览器命令行支持,等价于 document.querySelectorAll(sel)
-
[].forEach.call(NodeLists)
// 使用 call 函数将数组遍历函数 forEach 应到节点元素列表 -
el.style.outline = "1px solid #333"
// 样式 outline 位于盒模型以外,不影响元素布局位置 -
(1<<24)
// parseInt("ffffff", 16) == 16777215 == 2^24 - 1 // 1<<24 == 2^24 == 16777216 -
Math.random()*(1<<24)
// 表示一个位于 0 到 16777216 之间的随机浮点数 -
~~Math.random()*(1<<24)
//~~
做用至关于 parseInt 取整 -
(~~(Math.random()*(1<<24))).toString(16)
// 转换为一个十六进制-
JavaScript实现异步编程的方法?
- 回调函数
- 事件监听
- 发布/订阅
- Promises对象
- Async函数[ES7]
web开发中会话跟踪的方法有哪些
- cookie
- session
- url重写
- 隐藏input
- ip地址
说几条写JavaScript的基本规范?
- 不要在同一行声明多个变量
- 请使用 ===/!==来比较true/false或者数值
- 使用对象字面量替代new Array这种形式
- 不要使用全局函数
- Switch语句必须带有default分支
- 函数不该该有时候有返回值,有时候没有返回值
- If语句必须使用大括号
- for-in循环中的变量 应该使用var关键字明确限定做用域,从而避免做用域污
Javascript如何实现继承?
- 构造继承
- 原型继承
- 实例继承
- 拷贝继承
- 原型prototype机制或apply和call方法去实现较简单,建议使用构造函数与原型混合方式
function Parent(){ this.name = 'wang'; } function Child(){ this.age = 28; } Child.prototype = new Parent();//继承了Parent,经过原型 var demo = new Child(); alert(demo.age); alert(demo.name);//获得被继承的属性 }
javascript建立对象的几种方式?
javascript建立对象简单的说,无非就是使用内置对象或各类自定义对象,固然还能够用JSON;但写法有不少种,也能混合使用
- 对象字面量的方式
person={firstname:"Mark",lastname:"Yun",age:25,eyecolor:"black"};
- 用function来模拟无参的构造函数
function Person(){} var person=new Person();//定义一个function,若是使用new"实例化",该function能够看做是一个Class person.name="Mark"; person.age="25"; person.work=function(){ alert(person.name+" hello..."); } person.work();
- 用function来模拟参构造函数来实现(用this关键字定义构造的上下文属性)
function Pet(name,age,hobby){ this.name=name;//this做用域:当前对象 this.age=age; this.hobby=hobby; this.eat=function(){ alert("我叫"+this.name+",我喜欢"+this.hobby+",是个程序员"); } } var maidou =new Pet("麦兜",25,"coding");//实例化、建立对象 maidou.eat();//调用eat方法
- 用工厂方式来建立(内置对象)
var wcDog =new Object(); wcDog.name="旺财"; wcDog.age=3; wcDog.work=function(){ alert("我是"+wcDog.name+",汪汪汪......"); } wcDog.work();
- 用原型方式来建立
function Dog(){ } Dog.prototype.name="旺财"; Dog.prototype.eat=function(){ alert(this.name+"是个吃货"); } var wangcai =new Dog(); wangcai.eat();
- 用混合方式来建立
function Car(name,price){ this.name=name; this.price=price; } Car.prototype.sell=function(){ alert("我是"+this.name+",我如今卖"+this.price+"万元"); } var camry =new Car("凯美瑞",27); camry.sell();
null,undefined 的区别?
- undefined 表示不存在这个值。
- undefined :是一个表示"无"的原始值或者说表示"缺乏值",就是此处应该有一个值,可是尚未定义。当尝试读取时会返回 undefined
- 例如变量被声明了,但没有赋值时,就等于undefined
- null 表示一个对象被定义了,值为“空值”
- null : 是一个对象(空对象, 没有任何属性和方法)
- 例如做为函数的参数,表示该函数的参数不是对象;
- 在验证null时,必定要使用 === ,由于 == 没法分别 null 和 undefined
写一个通用的事件侦听器函数
// event(事件)工具集,来源:github.com/markyun markyun.Event = { // 页面加载完成后 readyEvent : function(fn) { if (fn==null) { fn=document; } var oldonload = window.onload; if (typeof window.onload != 'function') { window.onload = fn; } else { window.onload = function() { oldonload(); fn(); }; } }, // 视能力分别使用dom0||dom2||IE方式 来绑定事件 // 参数: 操做的元素,事件名称 ,事件处理程序 addEvent : function(element, type, handler) { if (element.addEventListener) { //事件类型、须要执行的函数、是否捕捉 element.addEventListener(type, handler, false); } else if (element.attachEvent) { element.attachEvent('on' + type, function() { handler.call(element); }); } else { element['on' + type] = handler; } }, // 移除事件 removeEvent : function(element, type, handler) { if (element.removeEventListener) { element.removeEventListener(type, handler, false); } else if (element.datachEvent) { element.detachEvent('on' + type, handler); } else { element['on' + type] = null; } }, // 阻止事件 (主要是事件冒泡,由于IE不支持事件捕获) stopPropagation : function(ev) { if (ev.stopPropagation) { ev.stopPropagation(); } else { ev.cancelBubble = true; } }, // 取消事件的默认行为 preventDefault : function(event) { if (event.preventDefault) { event.preventDefault(); } else { event.returnValue = false; } }, // 获取事件目标 getTarget : function(event) { return event.target || event.srcElement; }, // 获取event对象的引用,取到事件的全部信息,确保随时能使用event; getEvent : function(e) { var ev = e || window.event; if (!ev) { var c = this.getEvent.caller; while (c) { ev = c.arguments[0]; if (ev && Event == ev.constructor) { break; } c = c.caller; } } return ev; } };
什么是闭包(closure),为何要用它?
- 闭包是指有权访问另外一个函数做用域中变量的函数,建立闭包的最多见的方式就是在一个函数内建立另外一个函数,经过另外一个函数访问这个函数的局部变量,利用闭包能够突破做用链域
-
闭包的特性:
- 函数内再嵌套函数
- 内部函数能够引用外层的参数和变量
- 参数和变量不会被垃圾回收机制回收
javascript 代码中的"use strict";是什么意思 ? 使用它区别是什么?
- use strict是一种ECMAscript 5 添加的(严格)运行模式,这种模式使得 Javascript 在更严格的条件下运行,使JS编码更加规范化的模式,消除Javascript语法的一些不合理、不严谨之处,减小一些怪异行为
如何判断一个对象是否属于某个类?
// 使用instanceof (待完善) if(a instanceof Person){ alert('yes'); }
new操做符具体干了什么呢?
- 建立一个空对象,而且 this 变量引用该对象,同时还继承了该函数的原型
- 属性和方法被加入到 this 引用的对象中
- 新建立的对象由 this 所引用,而且最后隐式的返回 this
var obj = {}; obj.__proto__ = Base.prototype; Base.call(obj);
js延迟加载的方式有哪些?
- defer和async、动态建立DOM方式(用得最多)、按需异步载入js
Ajax 是什么? 如何建立一个Ajax?
ajax的全称:Asynchronous Javascript And XML
- 异步传输+js+xml
- 所谓异步,在这里简单地解释就是:向服务器发送请求的时候,咱们没必要等待结果,而是能够同时作其余的事情,等到有告终果它本身会根据设定进行后续操做,与此同时,页面是不会发生整页刷新的,提升了用户体验
- 建立XMLHttpRequest对象,也就是建立一个异步调用对象
- 建一个新的HTTP请求,并指定该HTTP请求的方法、URL及验证信息
- 设置响应HTTP请求状态变化的函数
- 发送HTTP请求
- 获取异步调用返回的数据
- 用JavaScript和DOM实现局部刷新
同步和异步的区别?
- 同步:浏览器访问服务器请求,用户看获得页面刷新,从新发请求,等请求完,页面刷新,新内容出现,用户看到新内容,进行下一步操做
- 异步:浏览器访问服务器请求,用户正常操做,浏览器后端进行请求。等请求完,页面不刷新,新内容也会出现,用户看到新内容
documen.write和 innerHTML的区别
- document.write只能重绘整个页面
- innerHTML能够重绘页面的一部分
DOM操做——怎样添加、移除、移动、复制、建立和查找节点?
-
(1)建立新节点
- createDocumentFragment() //建立一个DOM片断
- createElement() //建立一个具体的元素
- createTextNode() //建立一个文本节点
-
(2)添加、移除、替换、插入
- appendChild()
- removeChild()
- replaceChild()
- insertBefore() //在已有的子节点前插入一个新的子节点
-
(3)查找
- getElementsByTagName() //经过标签名称
- getElementsByName() // 经过元素的Name属性的值(IE容错能力较强,会获得一个数组,其中包括id等于name值的)
- getElementById() //经过元素Id,惟一性
那些操做会形成内存泄漏?
- 内存泄漏指任何对象在您再也不拥有或须要它以后仍然存在
- 垃圾回收器按期扫描对象,并计算引用了每一个对象的其余对象的数量。若是一个对象的引用数量为 0(没有其余对象引用过该对象),或对该对象的唯一引用是循环的,那么该对象的内存便可回收
- setTimeout 的第一个参数使用字符串而非函数的话,会引起内存泄漏
- 闭包、控制台日志、循环(在两个对象彼此引用且彼此保留时,就会产生一个循环)
渐进加强和优雅降级
- 渐进加强 :针对低版本浏览器进行构建页面,保证最基本的功能,而后再针对高级浏览器进行效果、交互等改进和追加功能达到更好的用户体验。
- 优雅降级 :一开始就构建完整的功能,而后再针对低版本浏览器进行兼容
Javascript垃圾回收方法
- 标记清除(mark and sweep)
- 这是JavaScript最多见的垃圾回收方式,当变量进入执行环境的时候,好比函数中声明一个变量,垃圾回收器将其标记为“进入环境”,当变量离开环境的时候(函数执行结束)将其标记为“离开环境”
- 垃圾回收器会在运行的时候给存储在内存中的全部变量加上标记,而后去掉环境中的变量以及被环境中变量所引用的变量(闭包),在这些完成以后仍存在标记的就是要删除的变量了
引用计数(reference counting)
在低版本IE中常常会出现内存泄露,不少时候就是由于其采用引用计数方式进行垃圾回收。引用计数的策略是跟踪记录每一个值被使用的次数,当声明了一个 变量并将一个引用类型赋值给该变量的时候这个值的引用次数就加1,若是该变量的值变成了另一个,则这个值得引用次数减1,当这个值的引用次数变为0的时 候,说明没有变量在使用,这个值无法被访问了,所以能够将其占用的空间回收,这样垃圾回收器会在运行的时候清理掉引用次数为0的值占用的空间
js继承方式及其优缺点
-
原型链继承的缺点
- 一是字面量重写原型会中断关系,使用引用类型的原型,而且子类型还没法给超类型传递参数。
-
借用构造函数(类式继承)
- 借用构造函数虽然解决了刚才两种问题,但没有原型,则复用无从谈起。因此咱们须要原型链+借用构造函数的模式,这种模式称为组合继承
-
组合式继承
- 组合式继承是比较经常使用的一种继承方法,其背后的思路是使用原型链实现对原型属性和方法的继承,而经过借用构造函数来实现对实例属性的继承。这样,既经过在原型上定义方法实现了函数复用,又保证每一个实例都有它本身的属性。
defer和async
- defer并行加载js文件,会按照页面上script标签的顺序执行async并行加载js文件,下载完成当即执行,不会按照页面上script标签的顺序执行
用过哪些设计模式?
-
工厂模式:
- 主要好处就是能够消除对象间的耦合,经过使用工程方法而不是new关键字。将全部实例化的代码集中在一个位置防止代码重复
- 工厂模式解决了重复实例化的问题 ,但还有一个问题,那就是识别问题,由于根本没法 搞清楚他们究竟是哪一个对象的实例
-
function createObject(name,age,profession){//集中实例化的函数var obj = new Object(); obj.name = name; obj.age = age; obj.profession = profession; obj.move = function () { return this.name + ' at ' + this.age + ' engaged in ' + this.profession; }; return obj; } var test1 = createObject('trigkit4',22,'programmer');//第一个实例var test2 = createObject('mike',25,'engineer');//第二个实例
-
构造函数模式
- 使用构造函数的方法 ,即解决了重复实例化的问题 ,又解决了对象识别的问题,该模式与工厂模式的不一样之处在于
- 构造函数方法没有显示的建立对象 (new Object());
- 直接将属性和方法赋值给 this 对象;
- 没有 renturn 语句
请解释一下 JavaScript 的同源策略
- 概念:同源策略是客户端脚本(尤为是Javascript)的重要的安全度量标准。它最先出自Netscape Navigator2.0,其目的是防止某个文档或脚本从多个不一样源装载。这里的同源策略指的是:协议,域名,端口相同,同源策略是一种安全协议
- 指一段脚本只能读取来自同一来源的窗口和文档的属性
为何要有同源限制?
- 咱们举例说明:好比一个黑客程序,他利用Iframe把真正的银行登陆页面嵌到他的页面上,当你使用真实的用户名,密码登陆时,他的页面就能够经过Javascript读取到你的表单中input中的内容,这样用户名,密码就轻松到手了。
-
缺点
- 如今网站的JS都会进行压缩,一些文件用了严格模式,而另外一些没有。这时这些原本是严格模式的文件,被 merge后,这个串就到了文件的中间,不只没有指示严格模式,反而在压缩后浪费了字节
实现一个函数clone,能够对JavaScript中的5种主要的数据类型(包括Number、String、Object、Array、Boolean)进行值复制
Object.prototype.clone = function(){ var o = this.constructor === Array ? [] : {}; for(var e in this){ o[e] = typeof this[e] === "object" ? this[e].clone() : this[e]; } return o; }
说说严格模式的限制
- 严格模式主要有如下限制:
- 变量必须声明后再使用
- 函数的参数不能有同名属性,不然报错
- 不能使用with语句
- 不能对只读属性赋值,不然报错
- 不能使用前缀0表示八进制数,不然报错
- 不能删除不可删除的属性,不然报错
- 不能删除变量delete prop,会报错,只能删除属性delete global[prop]
- eval不会在它的外层做用域引入变量
- eval和arguments不能被从新赋值
- arguments不会自动反映函数参数的变化
- 不能使用arguments.callee
- 不能使用arguments.caller
- 禁止this指向全局对象
- 不能使用fn.caller和fn.arguments获取函数调用的堆栈
- 增长了保留字(好比protected、static和interface)
如何删除一个cookie
- 将时间设为当前时间往前一点
var date = new Date(); date.setDate(date.getDate() - 1);//真正的删除
setDate()方法用于设置一个月的某一天
- expires的设置
document.cookie = 'user='+ encodeURIComponent('name') + ';expires = ' + new Date(0)
编写一个方法 求一个字符串的字节长度
- 假设:一个英文字符占用一个字节,一个中文字符占用两个字节
function GetBytes(str){ var len = str.length; var bytes = len; for(var i=0; i<len; i++){ if (str.charCodeAt(i) > 255) bytes++; } return bytes; } alert(GetBytes("你好,as"));
请解释什么是事件代理
- 事件代理(Event Delegation),又称之为事件委托。是 JavaScript 中经常使用绑定事件的经常使用技巧。顾名思义,“事件代理”便是把本来须要绑定的事件委托给父元素,让父元素担当事件监听的职务。事件代理的原理是DOM元素的事件冒泡。使用事件代理的好处是能够提升性能
attribute和property的区别是什么?
- attribute是dom元素在文档中做为html标签拥有的属性;
- property就是dom元素在js中做为对象拥有的属性。
- 对于html的标准属性来讲,attribute和property是同步的,是会自动更新的
- 可是对于自定义的属性来讲,他们是不一样步的
页面编码和被请求的资源编码若是不一致如何处理?
- 后端响应头设置 charset
- 前端页面
<meta>
设置 charset
把<script>
放在</body>
以前和以后有什么区别?浏览器会如何解析它们?
- 按照HTML标准,在
</body>
结束后出现<script>
或任何元素的开始标签,都是解析错误 - 虽然不符合HTML标准,但浏览器会自动容错,使实际效果与写在
</body>
以前没有区别 - 浏览器的容错机制会忽略<script>以前的
</body>
,视做<script>
仍在 body 体内。省略</body>
和</html>
闭合标签符合HTML标准,服务器能够利用这一标准尽量少输出内容
延迟加载JS的方式有哪些?
- 设置
<script>
属性 defer="defer" (脚本将在页面完成解析时执行) - 动态建立 script DOM:document.createElement('script');
- XmlHttpRequest 脚本注入
- 延迟加载工具 LazyLoad
异步加载JS的方式有哪些?
- 设置
<script>
属性 async="async" (一旦脚本可用,则会异步执行) - 动态建立 script DOM:document.createElement('script');
- XmlHttpRequest 脚本注入
- 异步加载库 LABjs
- 模块加载器 Sea.js
JavaScript 中,调用函数有哪几种方式?
- 方法调用模式 Foo.foo(arg1, arg2);
- 函数调用模式 foo(arg1, arg2);
- 构造器调用模式 (new Foo())(arg1, arg2);
- call/applay调用模式 Foo.foo.call(that, arg1, arg2);
- bind调用模式 Foo.foo.bind(that)(arg1, arg2)();
简单实现 Function.bind 函数?
if (!Function.prototype.bind) { Function.prototype.bind = function(that) { var func = this, args = arguments; return function() { return func.apply(that, Array.prototype.slice.call(args, 1)); } } } // 只支持 bind 阶段的默认参数: func.bind(that, arg1, arg2)(); // 不支持如下调用阶段传入的参数: func.bind(that)(arg1, arg2);
列举一下JavaScript数组和对象有哪些原生方法?
-
数组:
- arr.concat(arr1, arr2, arrn);
- arr.join(",");
- arr.sort(func);
- arr.pop();
- arr.push(e1, e2, en);
- arr.shift();
- unshift(e1, e2, en);
- arr.reverse();
- arr.slice(start, end);
- arr.splice(index, count, e1, e2, en);
- arr.indexOf(el);
- arr.includes(el); // ES6
-
对象:
- object.hasOwnProperty(prop);
- object.propertyIsEnumerable(prop);
- object.valueOf();
- object.toString();
- object.toLocaleString();
- Class.prototype.isPropertyOf(object);
Array.splice() 与 Array.splice() 的区别?
slice -- “读取”数组指定的元素,不会对原数组进行修改
-
- 语法:arr.slice(start, end)
- start 指定选取开始位置(含)
- end 指定选取结束位置(不含)
-
splice
- “操做”数组指定的元素,会修改原数组,返回被删除的元素
- 语法:arr.splice(index, count, [insert Elements])
- index 是操做的起始位置
- count = 0 插入元素,count > 0 删除元素
- [insert Elements] 向数组新插入的元素
JavaScript 对象生命周期的理解?
- 当建立一个对象时,JavaScript 会自动为该对象分配适当的内存
- 垃圾回收器按期扫描对象,并计算引用了该对象的其余对象的数量
- 若是被引用数量为 0,或唯一引用是循环的,那么该对象的内存便可回收
哪些操做会形成内存泄漏?
- JavaScript 内存泄露指对象在不须要使用它时仍然存在,致使占用的内存不能使用或回收
- 未使用 var 声明的全局变量
- 闭包函数(Closures)
- 循环引用(两个对象相互引用)
- 控制台日志(console.log)
- 移除存在绑定事件的DOM元素(IE)
- 上期经典前端面试题(3)现代技术
- 往期经典深刻理解——URL加载过程
持续更新中……喜欢请点个赞哦~