面试题目总结

什么是作用域链和闭包

当执行一段JavaScript代码(全局代码或函数)时,JavaScript引擎会为其创建一个作用域又称为执行上下文(Execution Context),在页面加载后会首先创建一个全局的作用域,然后每执行一个函数,会建立一个对应的作用域,从而形成了一条作用域链。每个作用域都有一条对应的作用域链,链头是全局作用域,链尾是当前函数作用域。

作用域链的作用是用于解析标识符,当函数被创建时(不是执行),会将this、arguments、命名参数和该函数中的所有局部变量添加到该当前作用域中,当JavaScript需要查找变量X的时候(这个过程称为变量解析),它首先会从作用域链中的链尾也就是当前作用域进行查找是否有X属性,如果没有找到就顺着作用域链继续查找,直到查找到链头,也就是全局作用域链,仍未找到该变量的话,就认为这段代码的作用域链上不存在x变量,并抛出一个引用错误(ReferenceError)的异常。

闭包

1
2
3
4
5
6
7
8
9
function foo(){
var a=2;
function bar(){
console.log(a);
}
return bar;
}
var baz = foo();
baz(); //2 --这就是闭包的效果

结果:在外层作用域拿到了函数内部作用域定义的值
解释:因为bar()嵌套在foo()内部,bar()封闭(涵盖)了foo()的作用域;相当于在外层调用bar函数,在自己定义的词法作用域以外的地方执行。
这个例子有三层作用域,即外层、foo函数、bar函数。在外层作用域执行baz方法,最后返回值指向bar函数;bar封闭在foo函数内部,因此能获取到foo作用域;这样就在外层拿到了内部函数的作用域。
闭包的应用场景,避免污染全局变量

理解JavaScript的原型链以及JavaScript的继承方式

JavaScript中的每个对象都有一个prototype属性,我们称之为原型,而原型的值也是一个对象,因此它也有自己的原型,这样就串联起来了一条原型链,原型链的链头是object,它的prototype比较特殊,值为null。
当访问对象的一个属性时, 首先查找对象本身, 找到则返回; 若未找到, 则继续查找其原型对象的属性(如果还找不到实际上还会沿着原型链向上查找, 直至到根). 只要没有被覆盖的话, 对象原型的属性就能在所有的实例中找到,若整个原型链未找到则返回undefined
原型链的作用是用于对象继承,函数A的原型属性(prototype property)是一个对象,当这个函数被用作构造函数来创建实例时,该函数的原型属性将被作为原型赋值给所有对象实例,比如我们新建一个数组,数组的方法便从数组的原型上继承而来。

  • instanceof-确定原型和实例之间的关系
    用来判断某个构造函数的prototype属性是否存在另外一个要检测对象的原型链上

  • isPrototypeOf
    用于测试一个对象是否存在于另一个对象的原型链上。

父类:

1
2
3
4
5
6
7
8
9
10
11
12
13
// 定义一个动物类
function Animal (name) {
// 属性
this.name = name || 'Animal';
// 实例方法
this.sleep = function(){
console.log(this.name + '正在睡觉!');
}
}
// 原型方法
Animal.prototype.eat = function(food) {
console.log(this.name + '正在吃:' + food);
};
  • 原型链继承
    将父类的实例作为子类的原型
1
2
3
4
5
6
7
8
9
10
11
12
function Cat(){
}
Cat.prototype = new Animal();
Cat.prototype.name = 'cat';
// Test Code
var cat = new Cat();
console.log(cat.name);
console.log(cat.eat('fish'));
console.log(cat.sleep());
console.log(cat instanceof Animal); //true
console.log(cat instanceof Cat); //true
  • 构造继承
    使用父类的构造函数来增强子类实例,等于是复制父类的实例属性给子类(没用到原型)
1
2
3
4
5
6
7
8
9
10
11
function Cat(name){
Animal.call(this);
this.name = name || 'Tom';
}
// Test Code
var cat = new Cat();
console.log(cat.name);
console.log(cat.sleep());
console.log(cat instanceof Animal); // false
console.log(cat instanceof Cat); // true
  • 组合继承
    通过调用父类构造,继承父类的属性并保留传参的优点,然后通过将父类实例作为子类原型,实现函数复用
1
2
3
4
5
6
7
8
9
10
11
12
function Cat(name){
Animal.call(this);
this.name = name || 'Tom';
}
Cat.prototype = new Animal();
// Test Code
var cat = new Cat();
console.log(cat.name);
console.log(cat.sleep());
console.log(cat instanceof Animal); // true
console.log(cat instanceof Cat); // true

特点:

弥补了方式2的缺陷,可以继承实例属性/方法,也可以继承原型属性/方法
既是子类的实例,也是父类的实例
不存在引用属性共享问题
可传参
函数可复用
缺点:

调用了两次父类构造函数,生成了两份实例(子类实例将子类原型上的那份屏蔽了)

  • 拷贝继承
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
function Cat(){
var animal = new Animal();
for(var p in animal){
Cat.prototype[p]=animal[p];
}
Cat.prototype.name= name || "cat";
}
// Test Code
var cat = new Cat();
console.log(cat.name);
console.log(cat.sleep());
console.log(cat instanceof Animal); // false
console.log(cat instanceof Cat); // true
  • 实例继承
    为父类实例添加新特性,作为子类实例返回
1
2
3
4
5
6
7
8
9
10
11
12
function Cat(){
var animal=new Animal;
animal.prototype.name= name || "cat";
return animal;
}
// Test Code
var cat = new Cat();
console.log(cat.name);
console.log(cat.sleep());
console.log(cat instanceof Animal); // true
console.log(cat instanceof Cat); // false

ES6的语法

  • var let const
    var:不需要初始化 //var b 变量可重新赋值 //var b=2;b=4;
    let:ES6语法,块级作用域(暂时性死区),函数内部使用let定以后,对函数外部无影响(必须先声明后使用原则)
    const:ES6语法,必须初始化,不可重新修改(只是保证变量名指向的地址不变,不保证地址的数据不变,可在多个模块间共享)

  • 箭头函数
    没有独立的上下文,没有this;也没有argument,super;
    书写简洁,风格与其他语言统一

  • Set Map Symbol
    Map保存键值对;Set是保存值的集合,唯一值;Symbols是一种特殊的、不可变得数据类型,可以作为对象属性的标识符使用;
    for…of可以用来遍历数组,类数组对象,argument,字符串,Map和set
    for…in用来遍历对象
    foreach

跨域的解决策略

  • jsonp方式
    iframe img script style等标签自带src属性,可以引入外部文件
    通过请求,动态的添加script标签,改变src的路径
  • postmessage
    完成有限制的页面间通信,解决包括弹窗与父页面之间的通信/iframe嵌套页面之间的通信/标签页面之间的通信

  • CORS(Cross Origin Resource Share)对方服务端设置响应头
    CORS请求默认不发送Cookie和HTTP认证信息。如果要把Cookie发到服务器,一方面要服务器同意,指定Access-Control-Allow-Credentials字段

xss劫持(跨站攻击)

通过客户端执行一段自己的js代码,达到攻击效果
源头:input输入框,Ajax的onerror的返回信息
解决:加上一段验证代码,过滤掉诸如:style iframe script javascript html等关键字段

cookie:容量小,4K左右 保存在浏览器端,重复请求时,消耗带宽
sessionstorage:存储在服务器端,并发访问的时候消耗服务器资源 5M左右
localstorage除非强制清浏览器缓存,否则一直存在 sessionstorage随着浏览器关闭消失

webpack打包的原理

将所有模块代码放在一个数组里,通过不同的数组id来访问不同的模块

  • webpack 和 gulp 的区别
    webpack 是一种打包工具,用于模块化方案,预编译模块化方案
    gulp 是一种构建工具 工作流程代替手工操作,集成压缩js/css ;less/sass编译等自动化操作

域名输入URL之后,页面发生了什么

1.域名解析
2.TCP/IP的三次握手
3.向服务器发送http请求下载资源
4.将远程服务器资源下载到本地
5.浏览器加载,计算和渲染
6.绘制到屏幕上面

this

指代当前函数作用域

BFC问题(块级格式上下文)

块格式化上下文(block formatting context) 是页面上的一个独立的渲染区域,容器里面的子元素不会在布局上影响到外面的元素。它是决定块盒子的布局及浮动元素相互影响的一个因素。

水平垂直居中实现

行内元素:
text-algin:center;vertical-algin:middle;
块级元素:
margin:0 auto;
margin-top:50%;
translate:-50%;

网络/性能优化

使用CDN,让用户访问最近的资源,减少来回传输时间
合并压缩CSS/Js/图片/静态资源
css放顶部,js放底部
图片做预加载
首屏之外的做懒加载
做http缓存,用户可以重复使用本地缓存,减少对服务器的压力
大小超过10KB的css/img建议外链引用,以细化缓存粒度
小于10K的图片base64 DNS预解析

少用全局变量,减少作用域链查找,缓存DOM查找结果
多个变量声明合并;
减少DOM操作次数
尽量避免在HTML标签中写style属性
不滥用float
用css3动画,避免css3渐变阴影效果
使用link来替代@import

谢谢你请我吃糖果!