WEB前端面试题--js面试题(基础)总结题目

JavaScript 基础面试题

  1. 介绍 JavaScript 的基本数据类型?
    基本数据类型: Number、String、Boolean、Null、Undefined
    object 是 Javascript 中所有对象的父对象。数据封装类对象: object 、 Array 、 Boolean 、 Number 和 String 。
    其他对象: Function 、 Arguments 、 Math 、 Date 、 Error 和 RegExp 。
    其他 数据类型 : Symbol
  2. 浅谈 JavaScript 中变量和函数声明的提升?
    在 JavaScript 中变量和函数的声明会提升到最顶部执行
    函数的提升高于变量的提升。
    函数内部如果用 var 声明了相同名称的外部变量,函数将不再向上寻找。
    匿名函数不会提升。
    不同

function creatPerson(name, age) {
var obj = new Object();
obj.name = name;
obj.age = age;
obj.sayName = function () {
window.alert(this.name);
};
return obj;
}

构造函数方法:

function Person(name, age) {
this.name = name;
this.age = age;
this.sayName = function () {
window.alert(this.name);
};
}

原型方法:

function Person() {}
Person.prototype = {
constructor: Person,
name: “Ning”,
age: “23”,
sayName: function () {
window.alert(this.name);
}
};
组合使用构造函数和原型方法:

function Person(name, age) {
this.name = name;
this.age = age;
}
Person.prototype = {
constructor: Person,
sayName: function () {
window.alert(this.name);
}
};

  1. JavaScript 实现继承的 3 种方法
    借用构造函数法:

function SuperType(name) {
this.name = name;
this.sayName = function () {
window.alert(this.name);
};
}
function SubType(name, age) {
SuperType.call(this, name); //在这里借用了父类的构造函数
this.age = age;
}
对象冒充:

function SuperType(name) {
this.name = name;
this.sayName = function () {
window.alert(this.name);
};
}
function SubType(name, age) {
this.supertype = SuperType; //在这里使用了对象冒充
this.supertype(name);
this.age = age;
}
组合继承:

function SuperType(name) {
this.name = name;
}

SuperType.prototype = {
sayName: function () {
window.alert(this.name);
}
};

function SubType(name, age) {
SuperType.call(this, name); //在这里继承属性
this.age = age;
}
SubType.prototype = new SuperType(); //这里继承方法
14. 对原生 Javascript 了解程度
数据类型、运算、对象、Function、继承、闭包、作用域、原型链、事件、 RegExp 、 JSON 、
Ajax 、 DOM 、 BOM 、内存泄漏、跨域、异步装载、模板引擎、前端 MVC 、路由、模块化、
Canvas 、 ECMAScript。
15. Js 动画与 CSS 动画区别及相应实现
CSS3 的动画的优点
在性能上会稍微好一些,浏览器会对 CSS3 的动画做一些优化
代码相对简单
缺点
在动画控制上不够灵活
兼容性不好
JavaScript 的动画正好弥补了这两个缺点,控制能力很强,可以单帧的控制、变换,同时写
得好完全可以兼容 IE6 ,并且功能强大。对于一些复杂控制的动画,使用 javascript 会比较
靠谱。而在实现一些小的交互动效的时候,就多考虑考虑 CSS 吧
16. 谈一谈你理解的函数式编程
简单说,“函数式编程"是一种"编程范式”(programming paradigm),也就是如何编写程序
的方法论
它具有以下特性:闭包和高阶函数、惰性计算、递归、函数是"第一等公民"、只用"表达式"
17. 说说你对作用域链的理解
作用域链的作用是保证执行环境里有权访问的变量和函数是有序的,作用域链的变量只能向
上访问,变量访问到 window 对象即被终止,作用域链向下访问变量是不被允许的
作用域就是变量与函数的可访问范围,即作用域控制着变量与函数的可见性和生命周期
18. JavaScript 原型,原型链 ? 有什么特点?
每个对象都在其内部初始化一个属性,就是 prototype (原型),当我们访问一个对象的属性时
如果这个对象内部不存在这个属性,那么他就会去 prototype 里找这个属性,这个
prototype 又会有自己的 prototype ,于是就这样一直找下去,也就是我们平时所说的原型
链的概念
关系: instance.constructor.prototype = instance.proto
JavaScript 对象是通过引用来传递的,我们创建的每个新对象实体中并没有一份属于自己的
原型副本。当我们修改原型时,与之相关的对象也会继承这一改变
当我们需要一个属性的时, Javascript 引擎会先看当前对象中是否有这个属性,如果没有的
就会查找他的 Prototype 对象是否有这个属性,如此递推下去,一直检索到 Object 内建对象
19. 说说什么是事件代理?
事件代理( Event Delegation ),又称之为事件委托。是 JavaScript 中常用绑定事件的常技
巧。顾名思义,“事件代理”即是把原本需要绑定的事件委托给父元素,让父元素担当事件监
听的职务。事件代理的原理是 DOM 元素的事件冒泡。使用事件代理的好处是可以提高性
能。
可以大量节省内存占用,减少事件注册,比如在 table 上代理所有 td 的 click 事件就非常
棒。
可以实现当新增子对象时无需再次对其绑定。
20. 说说 jax 原理?
Ajax 的原理简单来说是在用户和服务器之间加了—个中间层( AJAX 引擎),由 XmlHttpRequest
对象来向服务器发异步请求,从服务器获得数据,然后用 javascrip t 来操作 DOM 而更新
页面。使用户操作与服务器响应异步化。这其中最关键的一步就是从服务器获得请求数据。
Ajax 的过程只涉及 JavaScript 、 XMLHttpRequest 和 DOM 。 XMLHttpRequest 是 ajax 的核心
机制。
Ajax 的优点:
通过异步模式,提升了用户体验
优化了浏览器和服务器之间的传输,减少不必要的数据往返,减少了带宽占用
Ajax 在客户端运行,承担了一部分本来由服务器承担的工作,减少了大用户量下的服务器
负载
Ajax 可以实现动态不刷新(局部刷新)
Ajax 的缺点:
安全问题 AJAX 暴露了与服务器交互的细节
对搜索引擎的支持比较弱
不容易调试
Ajax 的请求:

/** 创建连接 /
var xhr = null;
xhr = new XMLHttpRequest()
/
2. 连接服务器 /
xhr.open(‘get’, url, true)
/
3. 发送请求 /
xhr.send(null);
/
4. 接受请求 /
xhr.onreadystatechange = function () {
if (xhr.readyState == 4) {
if (xhr.status == 200) {
success(xhr.responseText);
} else {
/
false **/
fail && fail(xhr.status);
}
}
}

  1. 说说如何解决跨域问题?
    首先了解下浏览器的同源策略 同源策略 / SOP ( Same origin policy ) 是一种约定,由
    Netscape 公司 1995 年引入浏览器,它是浏览器最核心也最基本的安全功能,如果缺少了
    同源策略,浏览器很容易受到 XSS 、 CSFR 等攻击。所谓同源是指"协议+域名+端口"三者相
    同,即便两个不同的域名指向同一个 ip 地址,也非同源。
    通过 jsonp 跨域
    document.domain + iframe 跨域
    nginx 代理跨域
    nodejs 中间件代理跨域
    后端在头部信息里面设置安全域名解决跨域

  2. 异步加载 JS 的方式有哪些?
    defer,只支持 IE
    async :
    创建 script ,插入到 DOM 中,加载完毕后 callBack
    /** 异步加载地图 **/
    export default function MapLoader () {
    return new Promise((resolve, reject) => {
    if (window.AMap) {
    resolve(window.AMap)
    } else {
    var script = document.createElement(‘script’)
    script.type = ‘text/javascript’
    script.async = true
    script.src = ‘’
    script.onerror = reject
    document.head.appendChild(script)
    }
    window.initAMap = () => {
    resolve(window.AMap)
    }
    })
    }

  3. 那些操作会造成内存泄漏?
    内存泄漏指任何对象在您不再拥有或需要它之后仍然存在
    setTimeout 的第一个参数使用字符串而非函数的话,会引发内存泄漏
    闭包使用不当

  4. 介绍 JS 有哪些内置对象?
    Object 是 JavaScript 中所有对象的父对象
    数据封装类对象 Object 、 Array 、 Boolean 、 Number 和 String
    其他对象: Function 、 Arguments 、 Math 、 Date 、 RegExp 、 Error

  5. 说几条写 JavaScript 的基本规范
    不要在同一行声明多个变量
    请使用 =/! 来比较 true/false 或者数值
    使用对象字面量替代 new Array 这种形式
    不要使用全局函数
    Switch 语句必须带有 default 分支
    If 语句必须使用大括号
    for-in 循环中的变量 应该使用 var 关键字明确限定作用域,从而避免作用域污

  6. eval 是做什么的?
    它的功能是把对应的字符串解析成 JS 代码并运行
    应该避免使用 eval ,不安全,非常耗性能( 2 次,一次解析成 js 语句,一次执行)
    由 JSON 字符串转换为 JSON 对象的时候可以用 eval,var obj =eval(’(’+ str +’)’)

  7. null 和 undefined 的区别
    undefined 表示不存在这个值。
    undefined 是一个表示"无"的原始值或者说表示"缺少值",就是此处应该有一个值,但是还没
    有定义。当尝试读取时会返回 undefined
    例如变量被声明了,但没有赋值时,就等于 undefined
    null 表示一个对象被定义了,值为“空值”
    null 是一个对象(空对象, 没有任何属性和方法)
    例如作为函数的参数,表示该函数的参数不是对象;
    在验证 null 时,一定要使用 === ,因为 == 无法分别 null 和 undefined

  8. 说说同步和异步的区别?
    同步:浏览器访问服务器请求,用户看得到页面刷新,重新发请求,等请求完,页面刷新,新
    内容出现,用户看到新内容,进行下一步操作
    异步:浏览器访问服务器请求,用户正常操作,浏览器后端进行请求。等请求完,页面不刷
    新,新内容也会出现,用户看到新内容

  9. defer 和 async ?
    defer 并行加载 js 文件,会按照页面上 script 标签的顺序执行
    async 并行加载 js 文件,下载完成立即执行,不会按照页面上 script 标签的顺序执行

  10. [“1”, “2”, “3”].map(parseInt) 答案是多少?
    [1, NaN, NaN] 因为 parseInt 需要两个参数 (val, radix) ,其中 radix 表示解时用的基数。
    map 传了 3 个 (element, index, array) ,对应的 radix 不合法导致解析失败。

  11. use strict 的理解和作用?
    use strict 是一种 ECMAscript 5 添加的(严格)运行模式,这种模式使得 Javascript 在更严
    格的条件下运行,使 JS 编码更加规范化的模式,消除 Javascript 语法的一些不合理、不严谨之
    处,减少一些怪异行为

  12. 说说严格模式的限制?
    变量必须声明后再使用
    函数的参数不能有同名属性,否则报错
    不能使用 with 语句
    禁止 this 指向全局对象

  13. 说说严格模式的限制?
    新增模板字符串(为 JavaScript 提供了简单的字符串插值功能)
    箭头函数
    for-of (用来遍历数据—例如数组中的值。)
    arguments 对象可被不定参数和默认参数完美代替。
    ES6 将 Promise 对象纳入规范,提供了原生的 Promise 对象。
    增加了 let 和 const 命令,用来声明变量。
    增加了块级作用域。
    let 命令实际上就增加了块级作用域。
    还有就是引入 module 模块的概念

  14. 说说 JSON 的了解?
    JSON(JavaScript Object Notation) 是一种轻量级的数据交换格式
    它是基于 JavaScript 的一个子集。数据格式简单, 易于读写, 占用带宽小
    JSON 字符串转换为 JSON 对象:

var obj =eval(’(’+ str +’)’);
var obj = str.parseJSON();
var obj = JSON.parse(str);
JSON 对象转换为 JSON 字符串:

var last=obj.toJSONString();
var last=JSON.stringify(obj);

  1. 说说 JS 延迟加载的方式有哪些?
    defer 和 async 、动态创建 DOM 方式(用得最多)、按需异步载入 js
  2. 说说 attribute 和 property 的区别是什么?
    attribute 是 dom 元素在文档中作为 html 标签拥有的属性;
    property 就是 dom 元素在 js 中作为对象拥有的属性。
    对于 html 的标准属性来说, attribute 和 property 是同步的,是会自动更新的
    但是对于自定义的属性来说,他们是不同步的
  3. 说说 let 的区别是什么?
    let 命令不存在变量提升,如果在 let 前使用,会导致报错
    如果块区中存在 let 和 const 命令,就会形成封闭作用域
    不允许重复声明,因此,不能在函数内部重新声明参数
  4. 如何通过 JS 判断一个数组?
    instanceof 方法
    instanceof 运算符是用来测试一个对象是否在其原型链原型构造函数的属性

var arr = []; js
arr instanceof Array; // true

constructor 方法
constructor 属性返回对创建此对象的数组函数的引用,就是返回对象相对应的构造函数
var arr = []; js
arr.constructor == Array; //true

ES5 新增方法 isArray()

var a = new Array(123); js
var b = new Date();
console.log(Array.isArray(a)); //true
console.log(Array.isArray(b)); //false

  1. 说说 let、var 、 const 的理解
    let :
    允许你声明一个作用域被限制在块级中的变量、语句或者表达式
    let 绑定不受变量提升的约束,这意味着 let 声明不会被提升到当前
    该变量处于从块开始到初始化处理的“暂存死区”
    var :
    声明变量的作用域限制在其声明位置的上下文中,而非声明变量总是全局的
    由于变量声明(以及其他声明)总是在任意代码执行之前处理的,所以在代码中的任意位
    置声明变量总是等效于在代码开头声明
    const :
    声明创建一个值的只读引用 (即指针)
    基本数据当值发生改变时,那么其对应的指针也将发生改变,故造成 const 申明基本数
    据类型时
    再将其值改变时,将会造成报错, 例如 const a = 3 ; a = 5 时 将会报错
    但是如果是复合类型时,如果只改变复合类型的其中某个 Value 项时, 将还是正常使用
  2. 正则表达式的使用
    当使用 RegExp() 构造函数的时候,不仅需要转义引号(即 \ ”表示”),并且还需要双反
    斜杠(即 \ 表示一个 \ )。使用正则表达字面量的效率更高
  3. Javascript 中 callee 和 caller 的作用
    caller 是返回一个对函数的引用,该函数调用了当前函数;
    callee 是返回正在被执行的 function 函数,也就是所指定的 function 对象的正文
  4. 说说 window.onload 和$(document).ready 的区别?
    window.onload() 方法是必须等到页面内包括图片的所有元素加载完毕后才能执行
    $(document).ready() 是 DOM 结构绘制完毕后就执行,不必等到加载完毕
    浏览器的兼容性

function ready(fn) {
if (document.addEventListener) { //标准浏览器
document.addEventListener(‘DOMContentLoaded’, function () {
//注销事件, 避免反复触发
document.removeEventListener(‘DOMContentLoaded’, arguments.callee, fa
fn(); //执行函数
}, false);
} else if (document.attachEvent) { //IE
document.attachEvent(‘onreadystatechange’, function () {
if (document.readyState == ‘complete’) {
document.detachEvent(‘onreadystatechange’, arguments.callee);
fn(); //函数执行
}
});
}
};
42. Javascript 数组去重方法汇总
利用 for 嵌套 for,然后 splice 去重(ES5 中最常用)

function unique(arr) {
for (var i = 0; i < arr.length; i++) {
for (var j = i + 1; j < arr.length; j++) {
if (arr[i] == arr[j]) { //第一个等同于第二个,splice 方法删除第二个
arr.splice(j, 1);
j–;
}
}
}
return arr;
}
var arr = [1, 1, ‘true’, ‘true’, true, true, 15, false, undefined, undefined, null]
console.log(unique(arr))
利用 ES6 Set 去重(ES6 中最常用)

function unique(arr) {
return Array.from(new Set(arr))
}
var arr = [1, 1, ‘true’, ‘true’, true, true, 15, undefined, undefined, null]
console.log(unique(arr))

利用 indexOf 去重

function unique(arr) {
if (!Array.isArray(arr)) {
console.log(‘type error!’)
return
}
var array = [];
for (var i = 0; i < arr.length; i++) {
if (array.indexOf(arr[i]) === -1) {
array.push(arr[i])
}
}
return array;
}
var arr = [1, 1, ‘true’, ‘true’, true, true, 15, undefined, undefined, null]
console.log(unique(arr))

利用 sort()去重

function unique(arr) {
if (!Array.isArray(arr)) {
console.log(‘type error!’)
return;
}
arr = arr.sort()
var arrry = [arr[0]];
for (var i = 1; i < arr.length; i++) {
if (arr[i] !== arr[i - 1]) {
arrry.push(arr[i]);
}
}
return arrry;
}
var arr = [1, 1, ‘true’, ‘true’, true, true, 15, undefined, undefined, null]
console.log(unique(arr))

利用对象的属性不能相同的特点进行去重

function unique(arr) {
if (!Array.isArray(arr)) {
console.log(‘type error!’)
return
}
var arrry = [];
var obj = {};
for (var i = 0; i < arr.length; i++) {
if (!obj[arr[i]]) {
arrry.push(arr[i])
obj[arr[i]] = 1
} else {
obj[arr[i]]++
}
}
return arrry;
}
var arr = [1, 1, ‘true’, ‘true’, true, true, 15, undefined, undefined, null]
console.log(unique(arr))

利用 includes 去重

function unique(arr) {
if (!Array.isArray(arr)) {
console.log(‘type error!’)
return
}
var array = [];
for (var i = 0; i < arr.length; i++) {
if (!array.includes(arr[i])) {//includes 检测数组是否有某个值
array.push(arr[i]);
}
}
return array
}
var arr = [1, 1, ‘true’, ‘true’, true, true, 15, undefined, undefined, null]
console.log(unique(arr))
43. 浏览器缓存
览器缓存分为强缓存和协商缓存,当客户端请求某个资源时,获取缓存的流程如下
先根据这个资源的一些 http header 判断它是否命中强缓存,如果命中,则直接从本地获取
缓存资源,不会发请求到服务器。
强缓存没有命中时,客户端会发送请求到服务器,服务器通过另一些 request header 验
证这个资源是否命中协商缓存,称为 http 再验证,如果命中,服务器将请求返回,但不
返回资源,而是告诉客户端直接从缓存中获取,客户端收到返回后就会从缓存中获取源。
强缓存和协商缓存共同之处在于,如果命中缓存,服务器都不会返回资源; 区别是,强缓
存不对发送请求到服务器,但协商缓存会。
当协商缓存也没命中时,服务器就会将资源发送回客户端。
当 ctrl+f5 强制刷新网页时,直接从服务器加载,跳过强缓存和协商缓存。
当 f5 刷新网页时,跳过强缓存,但是会检查协商缓存。
强缓存
Expires 该字段是 http1.0 时的规范,值为一个绝对时间的 GMT 格式的时间字串,代表
缓存资源的过期时间
Cache-Control:max-age 该字段是 http1.1 的规范,强缓存利用其 max-age 值来判缓存资
源的最大生命周期,它的值单位为秒
协商缓存
Last-Modified 值为资源最后更新时间,随服务器 response 返回
If-Modified-Since 通过比较两个时间来判断资源在两次请求期间是否有过修改,如果没有
修改,则命中协商缓存
ETag 表示资源内容的唯一标识,随服务器 response 返回
If-None-Match 服务器通过比较请求头部的 If-None-Match 与当前资源的 ETag 是否一致
来判断资源是否在两次请求之间有过修改,如果没有修改,则命中协商缓存
44. 防抖/节流的理解
防抖: 在滚动事件中需要做个复杂计算或者实现一个按钮的防二次点击操作。可以通过函数
防抖动来实现
开始一个定时器,只要我定时器还在,不管你怎么点击都不会执行回调函数。一旦定时器结
束并设置为 null,就可以再次点击了
对于延时执行函数来说的实现:每次调用防抖动函数都会判断本次调用和之前的时间间隔,
如果小于需要的时间间隔,就会重新创建一个定时器,并且定时器的延时为设定时间减去之
前的时间间隔。一旦时间到了,就会执行相应的回调函数
整体函数实现如下:

// *使用 underscore 的源码来解释防抖动
// *underscore 防抖函数,返回函数连续调用时,空闲时间必须大于或等于 wait,func 才会执行
// * @param { function} func 回调函数
// * @param { number } wait 表示时间窗口的间隔
// * @param { boolean } immediate 设置为 ture 时,是否立即调用函数
// * @return { function} 返回客户调用函数

_.debounce = function (func, wait, immediate) {
var timeout, args, context, timestamp, result;
var later = function () {
// 现在和上一次时间戳比较
var last = _.now() - timestamp;
// 如果当前间隔时间少于设定时间且大于 0 就重新设置定时器
if (last < wait && last >= 0) {
timeout = setTimeout(later, wait - last);
} else {
// 否则的话就是时间到了执行回调函数
timeout = null;
if (!immediate) {
result = func.apply(context, args);
if (!timeout) context = args = null;
}
}
};
return function () {
context = this;
args = arguments;
// 获得时间戳
timestamp = _.now();
// 如果定时器不存在且立即执行函数
var callNow = immediate && !timeout;
// 如果定时器不存在就创建一个
if (!timeout) timeout = setTimeout(later, wait);
if (callNow) {
// 如果需要立即执行函数的话 通过 apply 执行
result = func.apply(context, args);
context = args = null;
}
return result;
};
};

节流: 防抖动和节流本质是不一样的。防抖动是将多次执行变为最后一次执行,节流是将多
次执行变成每隔一段时间执行
/*** underscore 节流函数,返回函数连续调用时,func 执行频率限定为 次 / wait

  • @param {function} func 回调函数
  • @param {number} wait 表示时间窗口的间隔
  • @param {object} options 如果想忽略开始函数的的调用,传入{leading: false}。
  • 如果想忽略结尾函数的调用,传入{trailing: false}
  • 两者不能共存,否则函数不能执行
  • @return {function} 返回客户调用函数*/

_.throttle = function (func, wait, options) {
var context, args, result; var timeout = null;
var previous = 0;
// 如果 options 没传则设为空对象 if (!options) options = {}; // 定时器回调函数
var later = function () {
// 如果设置了 leading,就将 previous 设为 0 // 用于下面函数的第一个 if 判断
previous = options.leading === false ? 0 : _.now();
result = func.apply(context, args);
if (!timeout) context = args = null;
};
return function () {
var now = _.now();
// 首次进入前者肯定为 true
// 如果需要第一次不执行函数
// 就将上次时间戳设为当前的
// 这样在接下来计算 remaining 的值时会大于 0
if (!previous && options.leading === false) previous = now;
// 计算剩余时间
var remaining = wait - (now - previous);
context = this;
args = arguments;
// 如果当前调用已经大于上次调用时间 + wait
// 如果设置了 trailing,只会进入这个条件
// 如果没有设置 leading,那么第一次会进入这个条件
// 还有一点,你可能会觉得开启了定时器那么应该不会进入这个 if 条件了
// 其实还是会进入的,因为定时器的延时
// 并不是准确的时间,很可能你设置了 2 秒
// 但是他需要 2.2 秒才触发,这时候就会进入这个条件
if (remaining <= 0 || remaining > wait) {
// 如果存在定时器就清理掉否则会调用二次回调
if (timeout) {
clearTimeout(timeout);
timeout = null;
}
previous = now;
result = func.apply(context, args);
if (!timeout) context = args = null;
} else if (!timeout && options.trailing !== false) {
// 判断是否设置了定时器和 trailing
// 没有的话就开启一个定时器
// 并且不能不能同时设置 leading 和 trailing
timeout = setTimeout(later, remaining);
}
return result;
};
};
45. JavaScript 变量提升
节当执行 JS 代码时,会生成执行环境,只要代码不是写在函数中的,就是在全局执行环境
中,函数中的代码会产生函数执行环境,只此两种执行环境。
因为函数和变量提升的原因。通常提升的解释是说将声明的代码移动到了顶部,这其实没有
什么错误,便于大家理解。但是更准确的解释应该是:在生成执行环境时,会有两个阶段。
第一个阶段是创建的阶段,JS 解释器会找出需要提升的变量和函数,并且给他们提前在内
存中开辟好空间,函数的话会将整个函数存入内存中,变量只声明并且赋值为 undefined ,
所以在第二个阶段,也就是代码执行阶段,我们可以直接提前使用。
46. 实现 Storage,使得该对象为单例,以及使用方式
var instance = null;
class Storage {
static getInstance() {
if (!instance) {
instance = new Storage();
}
return instance;
}
setItem = (key, value) => localStorage.setItem(key, value),
getItem = key => localStorage.getItem(key)
}
47. 说说你对事件流的理解
事件流分为两种,捕获事件流和冒泡事件流
捕获事件流从根节点开始执行,一直往子节点查找执行,直到查找执行到目标节点
冒泡事件流从目标节点开始执行,一直往父节点冒泡查找执行,直到查到到根节点
48. 说说从输入 URL 到看到页面发生的全过程
首先浏览器主进程接管,开了一个下载线程。
然后进行 HTTP 请求(DNS 查询、IP 寻址等等),中间会有三次捂手,等待响应,开始下载
响应报文。
将下载完的内容转交给 Renderer 进程管理。
Renderer 进程开始解析 css rule tree 和 dom tree,这两个过程是并行的,所以一般我会把
link 标签放在页面顶部。
解析绘制过程中,当浏览器遇到 link 标签或者 script、img 等标签,浏览器会去下载这些内
容,遇到时候缓存的使用缓存,不适用缓存的重新下载资源。
css rule tree 和 dom tree 生成完了之后,开始合成 render tree,这个时候浏览器会进行
layout,开始计算每一个节点的位置,然后进行绘制。
绘制结束后,关闭 TCP 连接,过程有四次挥手
49. 做一个 Dialog 组件,说说你设计的思路?它应该有什么功能?
该组件需要提供 hook 指定渲染位置,默认渲染在 body 下面。
然后改组件可以指定外层样式,如宽度等
组件外层还需要一层 mask 来遮住底层内容,点击 mask 可以执行传进来的 onCancel 函数关
闭 Dialog 。
另外组件是可控的,需要外层传入 visible 表示是否可见。
然后 Dialog 可能需要自定义头 head 和底部 footer ,默认有头部和底部,底部有一个确
认按钮和取消按钮,确认按钮会执行外部传进来的 onOk 事件,然后取消按钮会执行外部传进
来的 onCancel 事件。
当组件的 visible 为 true 时候,设置 body 的 overflow 为 hidden ,隐藏 body 的滚动条,
反之显示滚动条。
组件高度可能大于页面高度,组件内部需要滚动条。
只有组件的 visible 有变化且为 ture 时候,才重渲染组件内的所有内容
50. 说说 ajax、fetch、axios 之间的区别
Ajax 请求
$.ajax({
type: ‘POST’,
url: url,
data: data,
dataType: dataType,
success: function () { },
error: function () { }
});

本身是针对 MVC 的编程,不符合现在前端 MVVM 的浪潮
基于原生的 XHR 开发, XHR 本身的架构不清晰,已经有了 fetch 的替代方案
JQuery 整个项目太大,单纯使用 ajax 却要引入整个 JQuery 非常的不合理(采取个性
化打包的方案又不能享受 CDN 服务)
fetch 请求
fetcht 只对网络请求报错,对 400 , 500 都当做成功的请求,需要封装去处理
fetch 默认不会带 cookie ,需要添加配置项
fetch 不支持 abort ,不支持超时控制,使用 setTimeout 及 Promise.reject 的实的
超时控制并不能阻止请求过程继续在后台运行,造成了量的浪费
fetch 没有办法原生监测请求的进度,而 XHR 可以
try {
js
let response = await fetch(url);
let data = response.json();
console.log(data);
} catch (e) {
console.log(“Oops, error”, e);
}

axios 请求
从浏览器中创建 XMLHttpRequest
从 node.js 发出 http 请求
支持 Promise API
拦截请求和响应
转换请求和响应数据
取消请求
自动转换 JSON 数据
客户端支持防止 CSRF/XSRF

axios({
method: ‘post’,
url: ‘/user/12345’,
data: {
firstName: ‘Fred’,
lastName: ‘Flintstone’
}
}).then(function (response) {
console.log(response);
}).catch(function (error) {
console.log(error);
});
50. 说说内存泄漏
定义:程序中己动态分配的堆内存由于某种原因程序未释放或无法释放引发的各种问题。
Javascript 中可能出现的内存泄漏情况:结果:变慢,崩溃,延迟大等
Javascript 中可能出现的内存泄漏原因:
全局变量
dom 清空时,还存在引用
ie 中使用闭包
定时器未清除
子元素存在引起的内存泄露
51. JavaScript 自定义事件
document.createEvent()
event.initEvent()
element.dispatchEvent()

window.onload = function () {
var demo = document.getElementById(“demo”);
demo.addEvent(“test”, function () { console.log(“handler1”) });
demo.addEvent(“test”, function () { console.log(“handler2”) });
demo.onclick = function () {
this.triggerEvent(“test”);
}
}

Element.prototype.addEvent = function (en, fn) {
this.pools = this.pools || {};
if (en in this.pools) {
this.pools[en].push(fn);
} else {
this.pools[en] = [];
this.pools[en].push(fn);
}
}

Element.prototype.triggerEvent = function (en) {
if (en in this.pools) {
var fns = this.pools[en];
for (var i = 0, il = fns.length; i < il; i++) {
fnsi;
}
} else { return; }
}

  1. JavaScript 数组排序的几种方式?
    冒泡排序:每次比较相邻的两个数,如果后一个比前一个小,换位置

var arr = [3, 1, 4, 6, 5, 7, 2]; js
function bubbleSort(arr) {
for (var i = 0; i < arr.length - 1; i++) {
for (var j = 0; j < arr.length - i - 1; j++) {
if (arr[j + 1] < arr[j]) {
var temp;
temp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = temp;
}
}
}
return arr;
}
console.log(bubbleSort(arr));

快速排序:采用二分法,取出中间数,数组每次和中间数比较,小的放到左边,大的放到右

var arr = [3, 1, 4, 6, 5, 7, 2]; js
function quickSort(arr) {
if (arr.length == 0) {
return []; // 返回空数组
}
var cIndex = Math.floor(arr.length / 2);
var c = arr.splice(cIndex, 1);
var l = [];
var r = [];
for (var i = 0; i < arr.length; i++) {
if (arr[i] < c) {
l.push(arr[i]);
} else {
r.push(arr[i]);
}
}
return quickSort(l).concat(c, quickSort®);
}
console.log(quickSort(arr));

  1. JavaScript 数组一行代码去重方法?
    Set 方法去重:

var arr = [1,2,3,4,2,1,23,543,3]
Array.prototype.uniq = function(){
return […new Set(this)];
}
console.log(arr.uniq())或者 console.log([…new Set(arr)])
54. JavaScript 如何判断一个对象是否为数组?
function isArray(arg) {
if (typeof arg === ‘object’) {
return Object.prototype.toString.call(arg) === ‘[object Array]’;
}
return false;
}
55. script 引入方式?
html 静态

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值