记2019的一次面试

237 阅读13分钟

CSS3常用属性

  • border-radius 圆角
  • box-shadow 阴影:X轴偏移值 Y轴偏移值 X轴阴影模糊半径 Y轴阴影模糊半径 阴影颜色
  • box-sizing 定义盒模型
    • 属性值为content-box时,宽高的值为content的宽高
    • 属性值为border-box时, 宽高的值为border+padding+content也就是整个盒模型的宽高;
  • linear-gradient 背景颜色线性渐变
  • radial-gradient 背景颜色径向渐变
  • text-shadow 文本阴影
  • background-size 设置背景图像的高度和宽度
  • @keyframs 动画名称 定义动画序列
  • animation: 1s keyname infinite 时间 动画名 次数
  • transform 变换

display有哪些属性,作用

  • none 元素不显示
  • block 显示为块级元素
  • inline 显示为内联元素
  • inline-block 行内块元素
  • flex 设置为伸缩盒子
  • inherit 从父元素继承 display 属性的值

CSS实现垂直水平居中

  • 定位方式
1. absolute + 负margin
.father {
    position: relative,
}
.son {
    position: absolute;
    width: 50px;
    height: 50px;
    margin-top: -25px;
    margin-left: -25px;
}
2. absolute + margin auto
.father {
    position: relative,
}
.son {
    position: absolute;;
    top: 0;
    left: 0;
    right: 0;
    bottom: 0;
    margin: auto;
}
3. absolute + transform
.father {
    position: relative,
}
.son {
    position: absolute;;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
}
  • flex方式
.father {
    display: flex;
    justify-content: center;
    align-items: center;
}
  • grid方式
.father {
    display: grid;
}
.son {
    aligin-self: center;
    justify-self: center;
}

对象的浅拷贝和深拷贝,有哪些实现方式。

  • JS 中的浅拷贝与深拷贝,只是针对复杂数据类型(Object,Array)的复制问题。浅拷贝与深拷贝都可以实现在已有对象上再生出一份的作用。但是对象的实例是存储在堆内存中然后通过一个引用值去操作对象,由此拷贝的时候就存在两种情况了:拷贝引用和拷贝实例,这也是浅拷贝和深拷贝的区别。

  • 浅拷贝: 浅拷贝是拷贝引用,拷贝后的引用都是指向同一个对象的实例,彼此之间的操作会互相影响

  • 浅拷贝实现方式

  • 1.拷贝原对象的引用

var a = {c:1};
var b = a;
console.log(a === b); // 输出true。
a.c = 2;
console.log(b.c); // 输出 2
  • 2.源对象拷贝实例,其属性对象拷贝引用
    • 这种情况,外层源对象是拷贝实例,如果其属性元素为复杂杂数据类型时,内层元素拷贝引用。 对源对象直接操作,不影响另外一个对象,但是对其属性操作时候,会改变另外一个对象的属性;常用方法为:Array.prototype.slice(), Array.prototype.concat(), jQury的$.extend({},obj)
var a = [{c:1}, {d:2}];
var b = a.slice();
console.log(a === b); // 输出false,说明外层数组拷贝的是实例
a[0].c = 3;
console.log(b[0].c); // 输出 3,说明其元素拷贝的是引用
  • Object.assign()实现对象的浅拷贝
  • 深拷贝: 在堆中重新分配内存,并且把源对象所有属性都进行新建拷贝,以保证深拷贝的对象的引用图不包含任何原有对象或对象图上的任何对象,拷贝后的对象与原来的对象是完全隔离,互不影响。
    • 实现方式:
      • JSON.stringify(),JSON.parse()
      • 使用Object.create()的方法
      • jQury的$.extend(true,{},obj)
  • ...展开运算符实现浅拷贝

数组常用的方法,哪些会改变数组哪些不会

  • Array.from()从一个类似数组或可迭代对象中创建一个新的数组实例

  • Array.isArray()用于确定传递的值是否是一个 Array

  • Array.concat()(不会更改原数组)方法用于合并两个或多个数组。此方法不会更改现有数组,而是返回一个新数组。

  • Array.every测试数组的所有元素是否都通过了指定函数的测试

  • Array.filter()(不会更改原数组)创建一个新数组, 其包含通过所提供函数实现的测试的所有元素

  • Array.find()返回数组中满足提供的测试函数的第一个元素的值。否则返回 undefined。

  • Array.findIndex()返回数组中满足提供的测试函数的第一个元素的索引 ected output: 3

  • Array.includes()判断一个数组是否包含一个指定的值,根据情况,如果包含则返回 true,否则返回false。

  • Array.indexOf()方法返回在数组中可以找到一个给定元素的第一个索引,如果不存在,则返回-1

  • Array.join()将一个数组(或一个类数组对象)的所有元素连接成一个字符串并返回这个字符串。如果数组只有一个项目,那么将返回该项目而不使用分隔符。

  • Array.pop()(改变原数组)从数组中删除最后一个元素,并返回该元素的值

  • Array.push()(改变原数组)将一个或多个元素添加到数组的末尾,并返回该数组的新长度

  • Array.reduce()对数组中的每个元素执行一个由您提供的reducer函数(升序执行),将其结果汇总为单个返回值。

  • Array.reverse()将数组中元素的位置颠倒,第一个数组元素成为最后一个数组元素,最后一个数组元素成为第一个。

  • Array.shift()(改变原数组)从数组中删除第一个元素,并返回该元素的值。

  • Array.unshift()(改变原数组)将一个或多个元素添加到数组的开头,并返回该数组的新长度。

  • Array.slice()(不改变原数组)方法返回一个新的数组对象,这一对象是一个由 begin和 end(不包括end)决定的原数组的浅拷贝

  • Array.sort()用原地算法对数组的元素进行排序,并返回数组。排序算法现在是稳定的

Array.splice()(改变原数组)

  • 方法通过删除现有元素和/或添加新元素来修改数组,并以数组返回原数组中被修改的内容
var months = ['Jan', 'March', 'April', 'June'];
months.splice(1, 0, 'Feb');
// inserts at 1st index position
console.log(months);
// expected output: Array ['Jan', 'Feb', 'March', 'April', 'June']

months.splice(4, 1, 'May');
// replaces 1 element at 4th index
console.log(months);
// expected output: Array ['Jan', 'Feb', 'March', 'April', 'May']

this指向的问题

  • this是运行时绑定的,所以取决于函数的执行上下文
  • 当一个函数被调用时,会创建一个活动记录(执行上下文)。这个记录会包含函数在哪里被调用(调用栈)、函数的调用方法、传入的参数等信息,this也是这里的一个属性。
  • 1.独立函数调用 这种直接调用的方式this指向全局对象,如果是在浏览器就指向window
function foo(){
    console.log(this.a)
}
var a = 2
foo()  // 2
  • 2.对象上下文(隐试绑定)
function foo() { 
    console.log( this.a );
}
var obj = { 
    a: 2,
    foo: foo
};
obj.foo(); // 2
  • foo虽然被定义在全局作用域,但是调用的时候是通过obj上下文引用的,可以理解为在foo调用的那一刻它被obj对象拥有。所以this指向obj
  • 3.显式绑定 通过call、apply、bind显式地更改this指向。
  • 4.new绑定 “构造函数”和原型中的this永远指向new出来的实例
  • 5.箭头函数中的this 而是“继承”外层作用域中的this指向 箭头函数不改变this的指向

Vue的常用指令

  • 指令都是行内属性
  • v-model放在input、textarea、select>option上的,实现双向数据绑定
  • v-text 展示对应的文本
  • v-once 对应的标签只渲染一次
  • v-show=布尔 是否能显示,true能显示,false不能显示(存在隐式转化)
  • v-html 把值中的标签渲染出来
  • v-for 循环显示元素 可以循环数组、对象、数字、字符串 最好加:key='a+i'
  • v-bind 用于绑定行内属性 简写成:
  • v-if 控制是否渲染该元素 值是true,则渲染该元素;false则不渲染 与v-else v-else-if连着使用 可以使用template标签,就不会出现多余标签

Vue的v-if和v-show的区别

  • v-showv-if都是用来显示隐藏元素,v-if还有一个v-else配合使用
  • v-show
    • 不管条件是真还是假,第一次渲染的时候都会编译出来,也就是标签都会添加到DOM中。之后切换的时候,通过display: none;样式来显示隐藏元素。可以说只是改变css的样式,几乎不会影响什么性能。
  • v-if
    • 在首次渲染的时候,如果条件为假,什么也不操作,页面当作没有这些元素。当条件为真的时候,开始局部编译,动态的向DOM元素里面添加元素。当条件从真变为假的时候,开始局部编译,卸载这些元素,也就是删除。
  • 性能方面
    • v-if绝对是更消耗性能的,因为v-if在显示隐藏过程中有DOM的添加和删除,v-show就简单多了,只是操作css。

Vue双向数据绑定的原理

微信小程序开发中遇到的问题

  • 小程序不支持background使用本体图片,只能使用base64图片,或者是用网络图片; 可以使用字体图标等。
  • 定义事件无法传值,在组件上定义自定义属性 通过event.currentTarget.dataset

jquery遍历的方法,jquery时间绑定怎么做

  • 便利方法$()
  • bind()函数只能针对已经存在的元素进行事件的设置;但是live(),on(),delegate()均支持未来新添加元素的事件设置;
  • on()方法可以绑定动态添加到页面元素的事件,on()方法绑定事件可以提升效率

js实现异步的方式,详细讲解ES发展实现异步的途径

前端安全性措施

  • 防止XSS攻击(跨网站指令码),
    • 是一种网站应用程式的安全漏洞攻击,是代码注入的一种
    • 防御:转义控制用户输入输出的内容,对于引号,尖括号,斜杠进行转义。
  • 采用CSP(内容安全策略)
    • 用于检测并削弱某些特定类型的攻击,包括跨站脚本 (XSS) 和数据注入攻击等。无论是数据盗取、网站内容污染还是散发恶意软件,这些攻击都是主要的手段。
    • 通过 HTTP Header 中的 Content-Security-Policy 来开启 CSP
    • 只允许加载本站资源Content-Security-Policy: default-src ‘self’
    • 只允许加载 HTTPS 协议图片Content-Security-Policy: img-src https://*
  • 防止CSRF(跨站请求伪造)
    • 利用用户的登录态发起恶意请求
    • 防御:
      • Get 请求不对数据进行修改
      • 不让第三方网站访问到用户 Cookie
      • 阻止第三方网站请求接口
      • 请求时附带验证信息,比如验证码或者 token
  • 对密码加盐,然后进行几次不同加密算法的加密。
// 加盐也就是给原密码添加字符串,增加原密码长度
sha256(sha1(md5(salt + password + salt)))

前端性能优化

选择合适的缓存策略

  • 对于某些不需要缓存的资源,可以使用Cache-control: no-store ,表示该资源不需要缓存。
  • 对于频繁变动的资源,可以使用Cache-Control: no-cache 并配合 ETag 使用,表示该资源已被缓存,但是每次都会发送请求询问资源是否更新。
  • 对于代码文件来说,通常使用 Cache-Control: max-age=31536000 并配合策略缓存使用,然后对文件进行指纹处理,一旦文件名变动就会立刻下载新的文件。

使用HTTP2.0

  • 在 HTTP / 2.0 中引入了多路复用,能够让多个请求使用同一个 TCP 链接,极大的加快了网页的加载速度。并且还支持 Header 压缩,进一步的减少了请求的数据大小

预加载

  • 资源不需要马上用到,但是希望尽早获取,这时候就可以使用预加载。预加载其实是声明式的 fetch ,强制浏览器请求资源,并且不会阻塞 onload 事件,可以使用以下代码开启预加载
<link rel="preload" href="http://example.com" />

静态资源使用CDN加载

  • 静态资源尽量使用 CDN 加载,由于浏览器对于单个域名有并发请求上限,可以考虑使用多个 CDN 域名。对于 CDN 加载静态资源需要注意 CDN 域名要与主站不同,否则每次请求都会带上主站的 Cookie。

优化渲染过程

懒加载

  • 懒加载的原理就是只加载自定义区域(通常是可视区域,但也可以是即将进入可视区域)内需要加载的东西。对于图片来说,先设置图片标签的 src 属性为一张占位图,将真实的图片资源放入一个自定义属性中,当进入自定义区域时,就将自定义属性替换为 src 属性,这样图片就会去下载资源,实现了图片懒加载
  • 懒加载不仅可以用于图片,也可以使用在别的资源上。比如进入可视区域才开始播放视频等等。

图片加载优化

  • 不用图片。很多时候会使用到很多修饰类图片,其实这类修饰图片完全可以用 CSS 去代替
  • 对于移动端来说,屏幕宽度就那么点,完全没有必要去加载原图浪费带宽。一般图片都用 CDN 加载,可以计算出适配屏幕的宽度,然后去请求相应裁剪好的图片
  • 小图使用 base64 格式
  • 将多个图标文件整合到一张图片中(雪碧图)
  • 选择正确的图片格式:
    • 对于能够显示 WebP 格式的浏览器尽量使用 WebP 格式。因为 WebP 格式具有更好的图像数据压缩算法,能带来更小的图片体积,而且拥有肉眼识别无差异的图像质量,缺点就是兼容性并不好
    • 小图使用 PNG,其实对于大部分图标这类图片,完全可以使用 SVG 代替
    • 照片使用 JPEG

服务器端开启GZIP压缩

webpack编译打包时间的优化

  • 组件按需引入,借助插件babel-plugin-import实现按需加载组件,减少文件体积,修改.babelrc文件。
  • 启用happypack多进程构建项目:happypack 的原理是让loader可以多进程去处理文件,它把任务分解给多个子进程去并发的执行,子进程处理完后再把结果发送给主进程
  • 修改source-map配置
  • 启用DllPlugin和DllReferencePlugin预编译库文件

Hybrid app 原生和H5通信

设计模式有哪些

  • 设计模式的定义:在面向对象软件设计过程中针对特定问题的简洁而优雅的解决方案

单体模式:

  • 单体模式思想在于保证一个特定类仅有一个实例,意味着当你第二次使用同一个类创建信对象时,应得到和第一次创建对象完全相同。

工厂模式:

  • 工厂模式是为了创建对象。

中介者模式

  • 通过一个中介者对象,其他所有的相关对象都通过该中介者对象来通信,而不是相互引用,当其中的一个对象发生改变时,只需要通知中介者对象即可。通过中介者模式可以解除对象与对象之间的紧耦合关系。
  • 中介者模式适用的场景:例如购物车需求,存在商品选择表单、颜色选择表单、购买数量表单等等,都会触发change事件,那么可以通过中介者来转发处理这些事件,实现各个事件间的解耦,仅仅维护中介者对象即可。

观察者模式

  • 观察者模式( 又叫发布者-订阅者模式 )应该是最常用的模式之一. 在很多语言里都得到大量应用.
  • 包括我们平时接触的dom事件. 也是js和dom之间实现的一种观察者模式.只要订阅了div的click事件. 当点击div的时候, function click就会被触发.

代理模式

  • 通过包装一个对象从而控制对它的访问,其中主要方法是将方位聚集为租或者 仅当真正必要时侯才执行访问,从未避免高昂的操作开销。