前端笔试题涉及html、css、js、Vue 等

综合题

你觉得前端工程师的价值体现在哪?

  • 为简化用户使用提供技术支持(交互部分)
  • 为多个浏览器兼容性提供支持
  • 为提高用户浏览速度(浏览器性能)提供支持
  • 为跨平台或者其他基于webkit或者其他渲染引擎的应用提供支持
  • 为展示数据提供支持(数据接口)

什么是w3c标准,谈谈对w3c的理解?

答: 如果从WEB技术角度,可以分为三个方面的标准:结构、表现、行为。结构主要指(X)HTML标准,包括各种标签的名字、属性、语义及其他相关标准。表现主要指CSS,包括各种定位、颜色、大小等方面的标准。行为主要指Javascript,其实主要由ECMA国际制定的标准,但由于在万维网上广泛应用,开发人员也要关注。Javascript的词法、表达式、语句等方面也有一系列的标准。 Javascript没有像Java JDK那样的现成二进制文件,只有文档标准,具体的实现交给了各浏览器,所以在开发过程中,各浏览器的兼容性问题会是一个问题,我们在处理的时候可以遵循鸭式辨型原则去处理。

1.从输入URL到浏览器显示页面发生了什么。(特别注意)

  • 1.在浏览器中输入url(解析IP地址)
  • 2.应用层DNS解析域名
  • 3.应用层客户端发送HTTP请求
  • 4.传输层TCP传输报文(3次握手)
  • 5.网络层IP协议查询MAC地址
  • 6.数据到达数据链路层
  • 7.服务器接收数据
  • 8.服务器响应请求
  • 9.服务器返回相应文件

2.HTTP请求方式GET,POST的区别?

get请求:从服务端获取数据

特点:使用GET方法时,查询字符串(键值对)被附加在URL地址后面一起发送到服 务器: sevice/getValue&name1=value1

    GET请求能够被缓存

    GET请求会保存在浏览器的浏览记录中

    以GET请求的URL能够保存为浏览器书签

    GET请求有长度限制

    GET请求主要用以获取数据

post请求:提交数据给服务端处理,并返回响应

   特点: 使用POST方法时,查询字符串在http请求头中单独存在

    POST请求不能被缓存下来

    POST请求不会保存在浏览器浏览记录中

    以POST请求的URL无法保存为浏览器书签

    POST请求没有长度限制

3.防抖和节流的区别?

防抖:任务频繁触发的情况下,只有任务触发的间隔超过指定间隔的时候,任务才会执行

节流:指定时间间隔内只会执行一次任务。

参考:JS-防抖与节流

4.页面重构怎么操作?

页面重构就是根据原有页面内容和结构的基础上,通过 div+css 写出符合 web 标准的页面结构。

具体实现要达到以下三点:

  • 功能不全页面的重构:页面功能符合用户体验、用户交互结构完整,可通过标准验证,
  • 代码重构:代码质量、SEO 优化、页面性能、更好的语义化、浏览器兼容、CSS 优化
  • 充分考虑到页面在站点中的“作用和重要性”,并对其进行有针对性的优化

5. 谈谈你对SEO的理解?

SEO:搜索引擎优化,其目的是为了使网站能够更好的被搜索引擎抓取,提高在搜索引擎内的自然排名,从而带来更多的免费流量,获取收益

SEO主要有两种方法,站内优化和站外优化

参考:前端SEO优化

6.前端怎么控制管理路由?

路由就是浏览器地址栏中的 url 与所见网页的对应关系

前端路由的实现方式:

基于 hash(ocation.hash+hashchange事件)

展示层面也就是切换 # 后面的内容,呈现给用户不同的页面。现在越来越多的单页面应用,基本都是基于 hash 实现

特性:

  • url 中 hash 值的变化并不会重新加载页面
  • hash 值的改变,都会在浏览器的访问历史中增加一个记录,也就是能通过浏览器的回退、前进按钮控制 hash 的切换
  • 我们可以通过 hashchange 事件,监听到 hash 值的变化,从而响应不同路径的逻辑处理

基于 istory 新 API( history.pushState()+popState 事件)
window.history.pushState(null, null, "http://www.google.com");

这两个 API 的相同之处是都会操作浏览器的历史记录,而不会引起页面的刷新。不同之处在于,pushState 会增加一条新的历史记录,而replaceState 则会替换当前的历史记录

参考:History API -MDN

7.平时如何管理你的项目?

a. 先期团队必须确定好全局样式(globe.css),编码模式(utf-8) 等;

b. 编写习惯必须一致(例如都是采用继承式的写法,单样式都写成一行);

c. 标注样式编写人,各模块都及时标注(标注关键样式调用的地方);

d. 页面进行标注(例如 页面 模块 开始和结束);

e. CSS跟HTML 分文件夹并行存放,命名都得统一(例如style.css);

f. JS 分文件夹存放 命名以该JS功能为准的英文翻译。

g. 图片采用整合的 images.png png8 格式文件使用 尽量整合在一起使用方便将来的管理

H5-CSS3笔试题

1.知道语义化吗?说说你理解的语义化,如果是你,平时会怎么做来保证语义化?

  • 像html5的新的标签header,footer,section等就是语义化
  • 一方面,语义化就是让计算机能够快读的读懂内容,高效的处理信息,可以对搜索引擎更友好
  • 另一方面,便于与他人的协作,他人通过读代码就可以理解你网页标签的意义
  • 去掉或者丢失样式的时候能够让页面呈现出清晰的结构
  • 有利于SEO:和搜索引擎建立良好沟通,有助于爬虫抓取更多有效信息:爬虫依赖于标签来确定上下文和各个关键字的权重
  • 方便其他设备解析(如屏幕阅读器、盲人阅读器、移动设备)以意义方式来渲染网页
  • 便于团队开发和维护,语义化更具有可读性,是下一步把网页的重要动向,遵循W3C标准的团队都要遵循这个标准,减少差异化

2.介绍HTML5的新特性?

  • 语义化标签: header footer nav section article aside 等
  • 增强型表单:date(从一个日期选择器选择一个日期) email(包含 e-mail 地址的输入域) number(数值的输入域) range(一定范围内数字值的输入域) search(用于搜索域) tel(定义输入电话号码字段) 等
  • 视频****和****音频:audio video
  • Canvas****绘图 ****SVG****绘图
  • 地****理定位:Geolocation
  • 拖放API:drag
  • web worker:是运行在后台的 JavaScript,独立于其他脚本,不会影响页面的性能
  • web storage: localStorage sessionStorage
  • WebSocket****: HTML5 开始提供的一种在单个 TCP 连接上进行全双工通讯的协议
  • 新事件如 ondrag onresize

onresize 事件会在窗口或框架被调整大小时发生。

ondrag 事件在元素或者选取的文本被拖动时触发。拖放是 HTML5 中非常常见的功能

3.如何解决ajax无法后退的问题?

  • html5里引入了新的API,即:history.pushState,history.replaceState
  • 可以通过pushState和replaceSate接口浏览器历史,并且改变当前页面的URL
  • onpopstate监听后退

4.websocket和ajax轮询?

  • websocket是html5中提出的新的协议,可以实现客户端与服务器的通信,实现服务器的推送功能
  • 优点是,只要简历一次连接,就可以连续不断的得到服务器推送消息,节省带宽和服务器端的压力。
  • ajax轮询模拟常连接就是每隔一段时间(0.5s)就向服务器发起ajax请求,查询服务器是否有数据更新
  • 缺点就是,每次都要建立HTTP连接,即使需要传输的数据非常少,浪费带宽

5.web worker和websocket?

worker主线程:

  • 通过worker = new worker(url)加载一个js文件来创建一个worker,同时返回一个worker实例
  • 通过worker.postMessage(data)方法来向worker发送数据。
  • 绑定worker.onmessage方法来接收worder发送过来的数据
  • 可以使用worker.terminate()来终止一个worder的执行。

websocket

  • 是web应用程序的传输协议,它提供了双向的,按序到达的数据流。他是一个HTML5协议,websocket链接是持久的,通过在客户端和服务器之间保持双向链接,服务器的更新可以被及时推送给客户端,而不需要客户端以一定的时间去轮询

6.Doctype作用?严格模式与混杂模式如果区分?意义?

  • 声明位于文档的最前面,处于标签之前。告知浏览器以何种模式来渲染文档
  • 严格模式的排版和js运作模式是 以该浏览器支持的最高标准运行
  • 在混杂模式中,页面已宽松的向后兼容的方式显示。模拟老式浏览器的行为以防止站点无法工作
  • DOCTYPE不存在或格式不正确会导致文档以混杂模式呈现

7.Doctype多少种文档类型?

  • 该标签可声明三种DTD类型,分别表示严格版本、过渡版本以及基于框架的HTML文档
  • HTML4.01规定了三种文档类型:Strict, Transitional以及Frameset
  • XHTML 1.0规定了三种XML文档类型:Strict, Transitional以及Franmeset
  • Standards(标准)模式(也就是严格呈现模式)用于呈现遵循最新标签的网页,而Quirks(包容)模式(也就是松散呈现模式或者兼容模式)用于呈现为传统浏览器而设计的网页

8.HTML与XHTML,有什么区别?

  • 所有的标签必须要有一个相应的结束标签
  • 所有标签的元素和属性的名字都必须使用小写
  • 所有的XML标记都必须合理嵌套
  • 所有的属性必须引号“”括起来
  • 把所有的<和&特殊符号用编码表示
  • 给所有属性赋一个值
  • 不要在注释内容使用'--'
  • 图片必须要有说明文字

9.行内元素有哪些,块级元素有哪些,空(void)元素有那些?

行内元素:a span i img input select b 等

块级元素:div ul ol li h1~h6 p table 等

空元素: br hr link 等

10.常见的浏览器内核有哪些,介绍一下你对浏览器内核的理解?

Trident 内核:IE

Gecko 内核:NETSCAPE6 及以上版本,火狐

Presto 内核:Opera7 及以上。[Opera 内核原为:Presto,现为:Blink;]

Webkit内核:Safari,Chrome等。[Chrome的:Blink(WebKit的分支)]

浏览器内核又可以分成两部分:渲染引擎和JS引擎****。 渲染引擎主要负责取得网页的内容、整理讯息、计算网页的显示方式等,JS引擎则是解析 Javascript 语言,执行 javascript 语言来实现网页的动态效果。

11.如何实现浏览器内多个标签页之间的通信?

  • 使用 localStorage: localStorage.setItem(key,value)、localStorage.getItem(key)
  • websocket协议
  • webworker

参考链接:多个标签页之间的通信

12.HTML5的离线存储怎么使用,解释一下工作原理

参考链接:HTML5的离线存储

13.src与href的区别

区别:src 用于替代这个元素,而 href 用于建立这个标签与外部资源之间的关系

浏览器加载到这里的时候,html 的渲染和解析不会暂停,css 文件的加载是同时进行的

当浏览器解析到这句代码时,页面的加载和解析都会暂停直到浏览器拿到并执行完这个js文件

14.表单提交中Get和Post方式的区别

  • Get 一般用于从服务器上获取数据,Post 向服务器传送数据
  • Get 传输的数据是拼接在Url之后的,对用户是可见的;Post 的传输数据对用户是不可见的
  • Get 传送的数据量较小,不能大于 2KB。Post 传送的数据量较大,一般被默认为不受限制
  • Get 安全性非常低,Post 安全性较高
  • 在 FORM 提交的时候,如果不指定 Method,则默认为 Get 请求

CSS方面:

1.flex属性值是多少?

  • flex属性是flex-grow,flex-shrinkflex-basis的简写
  • flex-grow属性定义项目的放大比例,默认为0
  • flex-shrink属性定义了项目的缩小比例,默认为1
  • flex-basis属性定义了项目的固定空间

2.垂直居中

  • 单行行内元素

  • 可以设置padding-top,padding-bottom

  • 将height和line-height设为相等

  • 多行行内元素

  • 可以将元素转为tabel样式,再设置vertical-align:middle;

  • 使用flex布局

  • 块级元素

  • 已知高度绝对定位负边距

  • 未知高度transform:translateY(-50%);

flex布局

display: flex;
justify-content: center;
aligin-items: center;

3.清除浮动

浮动的元素是脱离文档标准流的,如果我们不清楚浮动,那么就会造成父元素高度塌陷,影响页面布局。

  • 利用clear属性进行清理

1. 父容器结尾插入空标签

 
  1. 利用css伪元素:

使用伪元素的好处:不增加冗余的 DOM 节点,符合语义化

.clearfix:after {
    content: ".";
    height: 0;
    visibility: hidden;
    display: block;
    clear: both;
}

3.将父容器形成BFC

  • BFC能清理浮动主要运用的是它的布局规则:

  • 内部的Box会在垂直方向,一个接一个的放置

  • box垂直方向的距离由margin决定。属于同一个BFC的两个相邻box的margin会发生重叠

  • 每个元素margin box的左边,与包含快border box的左边相接触(对于从左往右的格式化,否则相反)。即使存在浮动也是如此

  • BFC的区域不会与float box重叠

  • BFC就是页面上的一个隔离的独立容器,容器里面的子元素不会影响到外面的元素。反之也是如此

  • 计算BFC的高度时,浮动元素也参与计算

  • 浮动清理利用的主要是第六条规则,只要将父容器出发为BFC,就可以实现包含的效果。那么出发BFC有哪种方法?

  • 根元素

  • float属性不为noe

  • positionabsolutefixed

  • display为inline-block,table-cell,table-captionflex,inline-flex

  • overflow不为visible

4.position的值, relative和absolute分别是相对于谁进行定位的?

  • relative:相对定位,相对于自己本身在正常文档流中的位置进行定位。
  • absolute:生成绝对定位,相对于最近一级定位不为static的父元素进行定位。
  • fixed: (老版本IE不支持)生成绝对定位,相对于浏览器窗口或者frame进行定位。
  • static:默认值,没有定位,元素出现在正常的文档流中。
  • sticky:生成粘性定位的元素,容器的位置根据正常文档流计算得出。

5. css盒子模型,box-sizing属性的理解

css 的盒模型由 content(内容)、padding(内边距)、border(边框)、margin(外边距)组成。但盒子的大小由content+padding+border这几部分决定

box-sizing是一个CSS3属性,与盒子模型有着密切联系。即决定元素的宽高如何计算,box-sizing有三个属性:

box-sizing****: content-box|border-box|inherit:

  • content-box 使得元素的宽高即为内容区的宽高(默认模式)
  • border-box****: 计算方式content + padding + border = 本身元素大小,即缩小了content大小
  • inherit 指定 box-sizing 属性的值,应该从父元素继承

6.CSS 选择符有哪些?哪些属性可以继承?优先级算法如何计算? CSS3新增伪类有那些?

  • 选择符:

  • id选择器(#myId)

  • 类选择器(.myClassName)

  • 标签选择器(div,p,h1)

  • 相邻选择器(h1 + p)

  • 子选择器(ul > li)

  • 后代选择器(li a)

  • 通配符选择器(*)

  • 属性选择器(button[disabled="true"])

  • 伪类选择器(a:hover,li:nth-child)

  • 优先级:

  • !important > 行内样式(比重1000) > id(比重100) > class/属性(比重10) > tag / 伪类(比重1);

  • 伪类和伪元素区别:

  • a:hover,li:nth-child

  • 伪元素:li:before、:after,:first-letter,:first-line,:selecton

7.transition 和 margin的百分比根据什么计算?

transition是相对于自身;margin相对于参照物

8.display:none和visibility:hidden的区别?

  • display:none 隐藏对应的元素,在文档布局中不再给它分配空间,它各边的元素会合拢,就当他从来不存在。
  • visibility:hidden 隐藏对应的元素,但是在文档布局中仍保留原来的空间。

9.CSS中link 和@import的区别是?

  • link属于HTML标签,而@import是CSS提供的;
  • 页面被加载的时,link会同时被加载,而@import被引用的CSS会等到引用它的CSS文件被加载完再加载;
  • import只在IE5以上才能识别,而link是HTML标签,无兼容问题;
  • link方式的样式的权重 高于@import的权重.

10.px和em和rem的区别?

px****: 像素,相对长度单位。像素px是相对于显示器屏幕分辨率而言的

em的值并不是固定的,会继承父级元素的字体大小,代表倍数

rem的值并不是固定的,始终是基于根元素 的,也代表倍数

参考链接:px和em和rem的区别

11.什么是响应式设计,响应式设计的基本原理是什么?

响应式网站设计是一个网站能够兼容多个终端,而不是为每一个终端做一个特定的版本。基本原理是通过媒体查询检测不同的设备屏幕尺寸做处理

12.为什么要初始化CSS样式?

因为浏览器的兼容问题,不同浏览器对有些标签的默认值是不同的,如果没对 CSS初始化往往会出现浏览器之间的页面显示差异 初始化样式会对 SEO* 有一定的影响*

13. CSS3有哪些新特性?

  • 实现圆角border-radius,阴影box-shadow,边框图片border-image
  • 对文字加特效text-shadow,强制文本换行word-wrap,线性渐变linear-gradient
  • 实现旋转transform:rotate(90deg),缩放scale(0.85,0.90),translate(0px,-30px)定位,倾斜skew(-9deg,0deg);
  • 增加了更多的CSS选择器、多背景、rgba()
  • 唯一引入的伪元素是::selection;
  • 实现媒体查询@media,弹性布局flex
  • 过渡transition 动画animation

14.::before 和 :after中双冒号和单冒号有什么区别?解释一下这2个伪元素的作用?

单冒号(:)用于CSS3伪类,双冒号(::)用于CSS3伪元素。(伪元素由双冒号和伪元素名称组成),双冒号是在当前规范中引入的,用于区分伪类和伪元素

15. 重绘和回流

参考链接:重绘和回流

16. css预处理器?

提供了一种css的书写方式,常见的就是 SAAS文档 和 LESS文档;

17.CSS优化、提高性能的方法有哪些?

  • 移除空的css规则(Remove empty rules)
  • 正确使用display的属性
  • 不滥用浮动、web字体
  • 不声明过多的font-size
  • 不在选择符中使用ID标识符
  • 遵守盒模型规则
  • 尽量减少页面重排、重绘
  • 抽象提取公共样式,减少代码量

18.对BFC规范的理解?

  • BFC,块级格式化上下文,一个创建了新的BFC的盒子是独立布局的,盒子
  • 里面的子元素的样式不会影响到外面的元素。在同一个BFC中的两个毗邻的块级盒在垂直方向(和布局方向有关系)的margin会发生折叠。
  • (W3C CSS 2.1 规范中的一个概念,它决定了元素如何对其内容进行布局,以及与其他元素的关系和相互作用。

JS笔试题

1.严格模式的特性?

  • 对javascript的语法和行为,都做了一些改变
  • 全局变量必须显式的声明。
  • 对象不能有重名的属性
  • 函数必须声明在顶层
  • 消除js语法的一些不合理,不严谨之处,减少一些怪异行为
  • 消除代码运行的一些不安全之处,保证代码运行的安全
  • 提高编译效率,增加运行速度
  • 为未来新版本的js做好铺垫

2.Promise是什么?

Promise 对象用于表示一个异步操作的最终完成 (或失败), 及其结果值.

语法:new Promise( function(resolve, reject) {...} /* executor */ );

Promise 是异步编程的一种解决方案,比传统的解决方案——回调函数和事件——更合理和更强大.所谓Promise,简单说就是一个容器,里面保存着某个未来才会结束的事件(通常是一个异步操作)的结果 --------ES6****入门-阮一峰

Promise 对象代表一个异步操作,有三种状态:pending(进行中)、fulfilled(已成功)和 rejected(已失败)。只有异步操作的结果,可以决定当前是哪一种状态,任何其他操作都无法改变这个状态

特点:

  • 对象的状态不受外界影响
  • 一旦状态改变,就不会再变,任何时候都可以得到这个结果
  • Promise 新建后就会立即执行
const promise = new Promise(function(resolve, reject) {
  // ... some code
  if (/* 异步操作成功 */){
    resolve(value);
  } else {
    reject(error);
  }
})

Promise实例生成以后,可以用then方法分别指定resolved状态和rejected状态的回调函数

promise.then(function(value) {
  // success
}, function(error) {
  // failure
})

then 方法返回的是一个新的Promise实例

Promise.prototype.catch 用于指定发生错误时的回调函数,具有“冒泡”性质,会一直向后传递,直到被捕获为止。也就是说,错误总是会被下一个catch语句捕获

getJSON('/post/1.json').then(function(post) {
  return getJSON(post.commentURL);
}).then(function(comments) {
  // some code
}).catch(function(error) {
  // 处理前面三个Promise产生的错误
});

catch 方法返回的还是一个 Promise 对象,因此后面还可以接着调用 then 方法

参考:ES6 --Promise 对象

3. JavaScript 有哪些数据类型

6种原始数据类型:

  • Boolean: 布尔表示一个逻辑实体,可以有两个值:true 和 false
  • Number: 用于表示数字类型
  • String: 用于表示文本数据
  • **Null: **Null 类型只有一个值: null,特指对象的值未设置
  • Undefined: 一个没有被赋值的变量会有个默认值undefined
  • Symbol: 符号(Symbols)是ECMAScript第6版新定义的。符号类型是唯一的并且是不可修改的

引用类型:Object、array、function

详见: JavaScript中的数据类型

4. undefined 和 null 有什么区别

null表示"没有对象",即该处不应该有值

典型用法:

  1. 作为函数的参数,表示该函数的参数不是对象
  2. 作为对象原型链的终点

undefined表示"缺少值",就是此处应该有一个值,但是还没有定义

典型用法:

  1. 变量被声明了,但没有赋值时,就等于undefined
  2. 调用函数时,应该提供的参数没有提供,该参数等于undefined
  3. 对象没有赋值的属性,该属性的值为undefined
  4. 函数没有返回值时,默认返回undefined

详见: undefined和null的区别-阮一峰

5.数组对象有哪些常用方法

修改器方法:

  • pop(): 删除数组的最后一个元素,并返回这个元素
  • push():在数组的末尾增加一个或多个元素,并返回数组的新长度
  • reverse(): 颠倒数组中元素的排列顺序
  • shift(): 删除数组的第一个元素,并返回这个元素
  • unshift(): 在数组的开头增加一个或多个元素,并返回数组的新长度
  • sort(): 对数组元素进行排序,并返回当前数组
  • splice(): 在任意的位置给数组添加或删除任意个元素

访问方法:

  • concat(): 返回一个由当前数组和其它若干个数组或者若干个非数组值组合而成的新数组
  • join(): 连接所有数组元素组成一个字符串
  • slice(): 抽取当前数组中的一段元素组合成一个新数组
  • indeOf(): 返回数组中第一个与指定值相等的元素的索引,如果找不到这样的元素,则返回 -1
  • lastIndexOf(): 返回数组中最后一个(从右边数第一个)与指定值相等的元素的索引,如果找不到这样的元素,则返回 -1

迭代方法:

  • forEach(): 为数组中的每个元素执行一次回调函数,最终返回 undefined
  • every(): 如果数组中的每个元素都满足测试函数,则返回 true,否则返回 false
  • some(): 如果数组中至少有一个元素满足测试函数,则返回 true,否则返回 false
  • filter(): 将所有在过滤函数中返回 true 的数组元素放进一个新数组中并返回
  • map(): 返回一个由回调函数的返回值组成的新数组

更多方法请参考 MDN 传送门

6.Js 有哪几种创建对象的方式?

对象字面量

var obj = {}

Object 构造函数

var obj = new Object()

工厂模式

function Person(name, age) {
    var o = new Object()
    o.name = name;
    o.age = age;
    o.say = function() {
        console.log(name)
    }
    return o
}

缺点: 每次通过Person创建对象的时候,所有的say方法都是一样的,但是却存储了多次,浪费资源

构造函数模式

function Person(name, age) {
    this.name = name
    this.age = age
    this.say = function() {
        console.log(name)
    }
}
var person = new Person('hello', 18)

构造函数模式隐试的在最后返回return this 所以在缺少new的情况下,会将属性和方法添加给全局对象,浏览器端就会添加给window对象,可以根据return this 的特性调用call或者apply指定this

原型模式

function Person() {}
Person.prototype.name = 'hanmeimei';
Person.prototype.say = function() {
  alert(this.name);
}
Person.prototype.friends = ['lilei'];
var person = new Person();

实现了方法与属性的共享,可以动态添加对象的属性和方法。但是没有办法创建实例自己的属性和方法,也没有办法传递参数

构造函数和原型组合

function Person(name, age) {
    this.name = name
    this.age = age
}
Person.prototype.say = function() {
    console.log(this.name)
}
var person = new Person('hello')

7.怎么实现对对象的拷贝(浅拷贝与深拷贝)?

浅拷贝

  • 拷贝原对象引用
  • 可以使用Array.prototype.slice()也可以完成对一个数组或者对象的浅拷贝
  • Object.assign()方法

深拷贝

  • 最常用的方式就是 JSON.parse(JSON.stringify(目标对象),缺点就是只能拷贝符合JSON数据标准类型的对象

详见 JavaScript中的浅拷贝与深拷贝

8.什么是闭包,为什么要用它?

简单来说,闭包就是能够读取其他函数内部变量的函数
function Person() {
    var name = 'hello'
    function say () {
        console.log(name)
    }
    return say()
}
Person() // hello

由于 JavaScript 特殊的作用域,函数外部无法直接读取内部的变量,内部可以直接读取外部的变量,从而就产生了闭包的概念

用途:

最大用处有两个,一个是前面提到的可以读取函数内部的变量,另一个就是让这些变量的值始终保持在内存中

注意点:

由于闭包会使得函数中的变量都被保存在内存中,内存消耗很大,所以不能滥用闭包,否则会造成网页的性能问题,在IE中可能导致内存泄露

详见 JavaScript 中的闭包

9.介绍一下 JavaScript 原型,原型链,它们有何特点?

首先明确一点,JavaScript是基于原型的

每个构造函数(constructor)都有一个原型对象(prototype),原型对象都包含一个指向构造函数的指针,而实例(instance)都包含一个指向原型对象的内部指针.

原型链.png

图解:

  • 每一个构造函数都拥有一个prototype属性,这个属性指向一个对象,也就是原型对象
  • 原型对象默认拥有一个constructor属性,指向指向它的那个构造函数
  • 每个对象都拥有一个隐藏的属性[[prototype]],指向它的原型对象

那么什么是原型链:

JavaScript中所有的对象都是由它的原型对象继承而来。而原型对象自身也是一个对象,它也有自己的原型对象,这样层层上溯,就形成了一个类似链表的结构,这就是原型链

所有原型链的终点都是Object函数的prototype属性。Objec.prototype指向的原型对象同样拥有原型,不过它的原型是null,而null则没有原型

image.png

详见 JavaScript中的原型与原型链

10. JavaScript 如何实现继承?

  • 原型链继承
function Animal() {}
Animal.prototype.name = 'cat'
Animal.prototype.age = 1
Animal.prototype.say = function() {console.log('hello')}

var cat = new Animal()

cat.name  // cat
cat.age  // 1
cat.say() // hello

最简单的继承实现方式,但是也有其缺点

  1. 来自原型对象的所有属性被所有实例共享
  2. 创建子类实例时,无法向父类构造函数传参
  3. 要想为子类新增属性和方法,必须要在new语句之后执行,不能放到构造器中
  • 构造继承
function Animal() {
    this.species = "动物"
}
function Cat(name, age) {
    Animal.call(this)
    this.name = name 
    this.age = age
}

var cat = new Cat('豆豆', 2)

cat.name  // 豆豆
cat.age // 2
cat.species // 动物

使用call或apply方法,将父对象的构造函数绑定在子对象上.

  • 组合继承
function Animal() {
    this.species = "动物"
}

function Cat(name){
  Animal.call(this)
  this.name = name
}

Cat.prototype = new Animal() // 重写原型
Cat.prototype.constructor = Cat

如果没有Cat.prototype = new Animal()这一行,Cat.prototype.constructor是指向Cat的;加了这一行以后,Cat.prototype.constructor指向Animal.这显然会导致继承链的紊乱(cat1明明是用构造函数Cat生成的),因此我们必须手动纠正,将Cat.prototype对象的constructor值改为Cat

  • extends 继承
ES6新增继承方式,Class 可以通过extends关键字实现继承
class Animal {

}

class Cat extends Animal {
    constructor() {
        super();
  }
}

使用 extends 实现继承,必须添加 super 关键字定义子类的 constructor,这里的super() 就相当于 Animal.prototype.constructor.call(this)

当然,还有很多种实现继承的方式,这里就不多说了。然后,再推荐一波 红宝书

详见 JavaScript中的继承

11.new 操作符具体干了什么?

  • 创建一个空对象,并且 this 变量引用该对象,同时还继承了该函数的原型
  • 属性和方法被加入到 this 引用的对象中
  • 新创建的对象由 this 所引用,并且最后隐式的返回 this

12.同步和异步的区别,怎么异步加载 JavaScript?

同步模式

同步模式,又称阻塞模式。javascript 在默认情况下是会阻塞加载的。当前面的 javascript 请求没有处理和执行完时,会阻止浏览器的后续处理

异步模式

异步加载又叫非阻塞,浏览器在下载执行 js 同时,还会继续进行后续页面的处理

异步加载 JavaScript

  • 动态添加 script 标签
  • defer
  • async

defer属性和async都是属于 script 标签上面的属性,两者都能实现 JavaScript 的异步加载。不同之处在于:async 在异步加载完成的时候就马上开始执行了,defer 会等到 html 加载完毕之后再执行

13.跨域问题的产生,怎么解决它?

由于浏览器的 同源策略,在出现 域名、端口、协议有一种不一致时,就会出现跨域,属于浏览器的一种安全限制。

解决跨域问题有很多种方式,常用的就是以下几种:

  • jsonp**** 跨域:动态创建script,再请求一个带参网址实现跨域通信.缺点就是只能实现 get 一种请求
  • document.domain + iframe跨域:两个页面都通过js强制设置document.domain为基础主域,就实现了同域.但是仅限主域相同,子域不同的跨域应用场景
  • 跨域资源共享(CORS):只服务端设置Access-Control-Allow-Origin即可,前端无须设置,若要带cookie请求:前后端都需要设置
  • nginx****反向代理接口跨域:同源策略是浏览器的安全策略,不是HTTP协议的一部分。服务器端调用HTTP接口只是使用HTTP协议,不会执行JS脚本,不需要同源策略,也就不存在跨越问题
  • WebSocket****协议跨域

14.对 this 的理解?

在 JavaScript 中,研究 this 一般都是 this 的指向问题,核心就是 this**** 永远指向最终调用它的那个对象,除非改变 this 指向或者箭头函数那种特殊情况

1. obj.fun() -> this->obj

2. fun() 或(function(){ ... })() this->window

3. new fun() -> this->新对象

4. Student.prototype.intr=function(){ ... this.sname ...}

this-> 将来调用intr()的.前的子对象

function test() {
    console.log(this);
}

test() // window

var obj = {
  foo: function () { console.log(this.bar) },
  bar: 1
};

var foo = obj.foo;
var bar = 2;

obj.foo() // 1
foo() // 2
// 函数调用的环境不同,所得到的结果也是不一样的

15.apply()、call()和 bind() 是做什么的,它们有什么区别?

相同点:三者都可以改变 this 的指向

不同点:

  • apply 方法传入两个参数:一个是作为函数上下文的对象,另外一个是作为函数参数所组成的数组
var obj = {
    name : 'sss'
}
function func(firstName, lastName){
    console.log(firstName + ' ' + this.name + ' ' + lastName);
}
func.apply(obj, ['A', 'B']);    // A sss B
  • call 方法第一个参数也是作为函数上下文的对象,但是后面传入的是一个参数列表,而不是单个数组
var obj = {
    name: 'sss'
}
function func(firstName, lastName) {
    console.log(firstName + ' ' + this.name + ' ' + lastName);
}
func.call(obj, 'C', 'D');       // C sss D
  • bind 接受的参数有两部分,第一个参数是是作为函数上下文的对象,第二部分参数是个列表,可以接受多个参数
var obj = {
    name: 'sss'
}
function func() {
    console.log(this.name);
}
var func1 = func.bind(null, 'xixi');
func1();

apply、call 方法都会使函数立即执行,因此它们也可以用来调用函数

bind 方法不会立即执行,而是返回一个改变了上下文 this 后的函数。而原函数 func 中的 this 并没有被改变,依旧指向全局对象 window

bind 在传递参数的时候会将自己带过去的参数排在原函数参数之前

function func(a, b, c) {
    console.log(a, b, c);
}
var func1 = func.bind(this, 'xixi');
func1(1,2) // xixi 1 2

16.什么是内存泄漏,哪些操作会造成内存泄漏?

内存泄漏:是指一块被分配的内存既不能使用,又不能回收,直到浏览器进程结束

可能造成内存泄漏的操作:

  • 意外的全局变量
  • 闭包
  • 循环引用
  • 被遗忘的定时器或者回调函数

你可能还需要知道 垃圾回收机制

17.什么是事件代理,它的原理是什么?

事件代理:通俗来说就是将元素的事件委托给它的父级或者更外级元素处理

原理:利用事件冒泡机制实现的

优点:只需要将同类元素的事件委托给父级或者更外级的元素,不需要给所有元素都绑定事件,减少内存空间占用,提升性能; 动态新增的元素无需重新绑定事件

18.对ES6的了解

ECMAScript 6.0 是 JavaScript 语言的下一代标准

新增的特性:

  • 声明变量的方式 let const
  • 变量解构赋值
  • 字符串新增方法 includes() startsWith() endsWith() 等
  • 数组新增方法 Array.from() Array.of() entries() keys() values() 等
  • 对象简洁写法以及新增方法 Object.is() Object.assign() entries() keys() values()等
  • 箭头函数、rest 参数、函数参数默认值等
  • 新的数据结构: Set 和 Map
  • Proxy
  • Promise对象
  • async函数 await命令
  • Class类
  • Module 体系 模块的加载和输出方式

了解更多,参考 ES6入门-阮一峰

19.箭头函数有什么特点

ES6 允许使用“箭头”(=>)定义函数
var f = v => v;
// 等同于
var f = function (v) {
  return v;
}

注意点:

  • 函数体内的 this 对象,就是定义时所在的对象,而不是使用时所在的对象
  • 不可以当作构造函数,也就是说,不可以使用 new 命令,否则会抛出一个错误
  • 不可以使用 arguments 对象,该对象在函数体内不存在。如果要用,可以用 rest 参数代替

20.async 函数以及 awit 命令

async 函数是什么?一句话,它就是 Generator 函数的语法糖

了解Generator函数的小伙伴,这里 传送门

async 特点:

async 函数返回一个 Promise 对象,可以使用 then 方法添加回调函数。当函数执行的时候,一旦遇到 await 就会先返回,等到异步操作完成,再接着执行函数体内后面的语句

async 函数内部 return 语句返回的值,会成为 then 方法回调函数的参数

async 函数返回的 Promise 对象,必须等到内部所有 await 命令后面的 Promise 对象执行完,才会发生状态改变,除非遇到 return 语句或者抛出错误

async 函数内部抛出错误,会导致返回的 Promise 对象变为 reject 状态。抛出的错误对象会被 catch 方法回调函数接收到

function timeout(ms) {
  return new Promise((resolve) => {
    setTimeout(resolve, ms);
  });
}

async function asyncPrint(value, ms) {
  await timeout(ms);
  console.log(value);
}

asyncPrint('hello world', 50);

await 命令: await 命令后面是一个 Promise 对象,返回该对象的结果。如果不是 Promise 对象,就直接返回对应的值

async function f() {
  // 等同于
  // return 123;
  return await 123;
}

f().then(v => console.log(v))
// 123

await 命令后面是一个thenable对象(即定义then方法的对象),那么await会将其等同于 Promise 对象.也就是说就算一个对象不是Promise对象,但是只要它有then这个方法, await 也会将它等同于Promise对象

使用注意点:

  • await 命令后面的 Promise 对象,运行结果可能是 rejected,所以最好把 await 命令放在 try...catch 代码块中
  • 多个 await 命令后面的异步操作,如果不存在继发关系,最好让它们同时触发
  • await 命令只能用在 async 函数之中,如果用在普通函数,就会报错

了解更多,参考:ES6 --async函数

21.export 与 export default有什么区别

export 与 export default 均可用于导出常量、函数、文件、模块等

在一个文件或模块中,export、import 可以有多个,export default 仅有一个

通过 export 方式导出,在导入时要加 { },export default 则不需要

使用 export default命令,为模块指定默认输出,这样就不需要知道所要加载模块的变量名; export 加载的时候需要知道加载模块的变量名

export default 命令的本质是将后面的值,赋给 default 变量,所以可以直接将一个值写在 export default 之后

22.前端性能优化

参见 雅虎14条前端性能优化

23.对JS引擎执行机制的理解

首选明确两点:

JavaScript 是单线程语言

JavaScript 的 Event Loop 是 JS 的执行机制, 也就是事件循环

console.log(1)
setTimeout(function(){
    console.log(2)
},0)
console.log(3)
// 1 3 2

JavaScript 将任务分为同步任务和异步任务,执行机制就是先执行同步任务,将同步任务加入到主线程,遇到异步任务就先加入到 event table ,当所有的同步任务执行完毕,如果有可执行的异步任务,再将其加入到主线程中执行

setTimeout(function(){console.log(1);},0);
new Promise(function(resolve){
     console.log(2);
     for(var i = 0; i < 10000; i++){
         i == 99 && resolve();
     }
 }).then(function(){
     console.log(3)
 });
 console.log(4);
 // 2 4 3 1

在异步任务中,定时器也属于特殊的存在。有人将其称之为 宏任务、微任务,定时器就属于宏任务的范畴。

参考 JS引擎的执行机制

24.DOM事件模型

事件的三个阶段

  • 捕获、目标、冒泡

介绍事件“捕获”和“冒泡”执行顺序和事件的执行次数?

  • 按照W3C标准的事件:首是进入捕获阶段,直到达到目标元素,再进入冒泡阶段

  • 事件执行次数(DOM2-addEventListener):元素上绑定事件的个数

  • 注意1:前提是事件被确实触发

  • 注意2:事件绑定几次就算几个事件,即使类型和功能完全一样也不会“覆盖”

  • 事件执行顺序:判断的关键是否目标元素

  • 非目标元素:根据W3C的标准执行:捕获->目标元素->冒泡(不依据事件绑定顺序)

  • 目标元素:依据事件绑定顺序:先绑定的事件先执行(不依据捕获冒泡标准)

  • 最终顺序:父元素捕获->目标元素事件1->目标元素事件2->子元素捕获->子元素冒泡->父元素冒泡

  • 注意:子元素事件执行前提 事件确实“落”到子元素布局区域上,而不是简单的具有嵌套关系

在一个DOM上同时绑定两个点击事件:一个用捕获,一个用冒泡。事件会执行几次,先执行冒泡还是捕获?

  • 该DOM上的事件如果被触发,会执行两次(执行次数等于绑定次数)
  • 如果该DOM是目标元素,则按事件绑定顺序执行,不区分冒泡/捕获
  • 如果该DOM是处于事件流中的非目标元素,则先执行捕获,后执行冒泡

事件的代理/委托

  • 事件委托是指将事件绑定目标元素的到父元素上,利用冒泡机制触发该事件

  • 优点:

  • 可以减少事件注册,节省大量内存占用

  • 可以将事件应用于动态添加的子元素上

  • 缺点: 使用不当会造成事件在不应该触发时触发

vue笔试题

1. Vue 生命周期的理解

Vue 实例有一个完整的生命周期,生命周期也就是指一个实例从开始创建到销毁的这个过程。

  • beforeCreated():在实例创建之间执行,数据未加载状态。
  • created():在实例创建、数据加载后,能初始化数据,DOM 渲染之前执行。
  • beforeMount():虚拟 DOM 已创建完成,在数据渲染前最后一次更改数据。
  • mounted():页面、数据渲染完成,真实 DOM 挂载完成。
  • beforeUpadate():重新渲染之前触发。
  • updated():数据已经更改完成,DOM 也重新 render 完成,更改数据会陷入死循环。
  • beforeDestory() 和 destoryed():前者是销毁前执行(实例仍然完全可用),后者则是销毁后执行。

期望答案(参考):

beforeCreate、created(此时需说明可以在created中首次拿到data中定义的数据)、beforeMount、mounted(此时需说明dom树渲染结束,可访问dom结构)、beforeUpdate、updated、beforeDestroy、destroyed

2. 简述Vue的响应式原理

当一个Vue实例创建时,vue会遍历data选项的属性,用 Object.defineProperty 将它们转为 getter/setter并且在内部追踪相关依赖,在属性被访问和修改时通知变化。

每个组件实例都有相应的 watcher 程序实例,它会在组件渲染的过程中把属性记录为依赖,之后当依赖项的 setter 被调用时,会通知 watcher 重新计算,从而致使它关联的组件得以更新。

[图片上传失败...(image-161c57-1660467001116)]

3.说一下 Vue 的双向绑定数据的原理

vue 实现数据双向绑定主要是:采用数据劫持结合“发布者 - 订阅者”模式的方式,通过 Object.defineProperty() 来劫持各个属性的 setter、 getter,在数据变动时发布消息给订阅者,触发相应监听回调。

4. 解释单向数据流和双向数据绑定

单向数据流:顾名思义,数据流是单向的。数据流动方向可以跟踪,流动单一,追查问题的时候可以更快捷。缺点就是写起来不太方便。要使 UI 发生变更就必须创建各种 action 来维护对应的 state。

双向数据绑定:数据之间是相通的,将数据变更的操作隐藏在框架内部。优点是在表单交互较多的场景下,会简化大量与业务无关的代码。缺点就是无法追踪局部状态的变化,增加了出错时 debug 的难度。

5. 对 MVC、MVVM 的理解?

MVC:

[图片上传失败...(image-f5a6c1-1660467001116)]

特点:

1.View 传送指令到 Controller;

2.Controller 完成业务逻辑后,要求 Model 改变状态;

3.Model 将新的数据发送到 View,用户得到反馈。

所有通信都是单向的。

MVVM:

[图片上传失败...(image-17ed6b-1660467001116)]

特点:

  1. 各部分之间的通信,都是双向的;
  2. 采用双向绑定: View 的变动,自动反映在 ViewModel,反之亦然。

6. 谈谈你对MVVM开发模式的理解

MVVM分为Model、View、ViewModel三者。

Model 代表数据模型,数据和业务逻辑都在Model层中定义;

View 代表UI视图,负责数据的展示;

ViewModel 负责监听 Model 中数据的改变并且控制视图的更新,处理用户交互操作;

ModelView 并无直接关联,而是通过 ViewModel 来进行联系的,ModelViewModel 之间有着双向数据绑定的联系。因此当 Model 中的数据改变时会触发 View 层的刷新,View 中由于用户交互操作而改变的数据也会在 Model 中同步。

  1. 这种模式实现了 ModelView 的数据自动同步,因此开发者只需要专注对数据的维护操作即可,而不需要自己操作 dom

  1. 组件通信

父****组件向子组件通信

子组件通过 props 属性,绑定父组件数据,实现双方通信。

子组件****向****父组件通信

将父组件的事件在子组件中通过 $emit 触发。

非父子组件、兄弟组件之间的数据传递

父传子:props;子传父:$emit;兄弟:eventbus;vuex;

/*新建一个Vue实例作为中央事件总嫌*/
let event =new Vue();
/*监听事件*/
event.$on(
'eventName', (val) => {
//......do something
});
/*触发事件*/
event.$emit(
'eventName'
, 
'this is a message.'
)

8.v-if 和 v-show 有什么区别?

v-show 仅仅控制元素的显示方式,将 display 属性在 block 和 none 来回切换;而v-if会控制这个 DOM 节点的存在与否。当我们需要经常切换某个元素的显示/隐藏时,使用v-show会更加节省性能上的开销;当只需要一次显示或隐藏时,使用v-if更加合理。

9. vue-router 路由实现和传参的几种方式?

路由就是用来跟后端服务器进行交互的一种方式,通过不同的路径,来请求不同的资源,请求不同的页面是路由的其中一种功能。

vue-router传递参数分为两大类

  • 编程式的导航 router.push
  • 声明式的导航

想要传递参数主要就是以对象的方式来写,分为两种方式:命名路由、查询参数。

命名路由

命名路由的前提就是在注册路由的地方需要给路由命名如:

path: '/a',

name: 'a',

component: () => import('../cs/a')

命名路由传递参数需要使用params来传递,这里一定要注意使用params不是query。目标页面接收传递参数时使用params

特别注意:命名路由这种方式传递的参数,如果在目标页面刷新是会出错的

//使用方法如下
this.$router.push({ name: 'a', params: { userId: 123 }})

//实列:



//接受传递的参数:

查询参数其实就是在路由地址后面带上参数和传统的url参数一致的,传递参数使用query而且必须配合path来传递参数而不能用name,目标页面接收传递的参数使用query。

注意:和name配对的是params,和path配对的是query

使用方法如下:
this.$router.push({ path: '/a', query: { userId: 123 }})

命名路由:

click to news page

路由传递参数和传统传递参数是一样的,命名路由类似表单提交而查询就是url传递,在vue项目中基本上掌握了这两种传递参数就能应付大部分应用了,最后总结为以下两点:
1.命名路由搭配params,刷新页面参数会丢失
2.查询参数搭配query,刷新页面数据不会丢失
3.接受参数使用this.$router后面就是搭配路由的名称就能获取到参数的值

原文连接:Vue router传参的几种方式

10. router 的区别

router.push 方法。

$router是路由对象,专门执行跳转动作

$route 为当前 router 跳转对象里面可以获取 name 、 path 、 query 、 params 等。

$route 是封装地址栏信息的对象,是保存数据的,不执行操作。

11.计算属性 computed 和事件 methods 有什么区别

我们可以将同一函数定义为一个 method 或者一个计算属性。对于最终的结果,两种方式是相同的。

不同点:

  • computed:计算属性是基于它们的依赖进行缓存的,只有在它的相关依赖发生改变时才会重新求值。
  • method:只要发生重新渲染, method 调用总会执行该函数。(没有缓存)

关于:computed中的getter和setter。

问题描述:

很多情况,我问到这个问题的时候对方的回答都是vue的getter和setter、订阅者模式之类的回答,我就会直接说问的并不是这个,而是computed,直接让对方说computed平时怎么使用,很多时候得到的回答是computed的默认方式,只使用了其中的getter,就会继续追问如果想要再把这个值设置回去要怎么做,当然一般会让问到这个程度的这个问题他都答不上来了。

期待答案(参考):


computed: {
fullName: {
// getter
get: function () {
return this.firstName + ' ' + this.lastName
},
// setter
set: function (newValue) {
var names = newValue.split(' ')
this.firstName = names[0]
this.lastName = names[names.length - 1]
}
}
}

12.Vue 中 key 的作用

key 的特殊属性主要用在 Vue 的虚拟 DOM 算法,在新旧 nodes 对比时辨识 VNodes。如果不使用 key,Vue 会使用一种最大限度减少动态元素并且尽可能的尝试修复/再利用相同类型元素的算法。使用 key,它会基于 key 的变化重新排列元素顺序,并且会移除 key 不存在的元素。

有相同父元素的子元素必须有独特的 key。重复的 key 会造成渲染错误。

期望答案(参考):

vue的dom渲染是虚拟dom,数据发生变化时,diff算法会只比较更改的部分,如果数据项的顺序被改变,Vue将不是移动DOM元素来匹配数据项的改变,而是简单复用此处每个元素,并且确保它在特定索引下显示已被渲染过的每个元素。举例说明:有一个列表我们现在在中间插入了一个元素,diff算法会默认复用之前的列表并在最后追加一个,如果列表存在选中一类的状态则会随着复用出现绑定错误的情况而不是跟着原元素,key的作用就可以给他一个标识,让状态跟着数据渲染。(具体的可以去查一下文档)

13. Vue 的核心是什么

数据驱动、组件系统。

14. Vue 等单页面应用的优缺点

优点

  • 良好的交互体验
  • 良好的前后端工作分离模式
  • 减轻服务器压力

缺点

  • SEO 难度较高
  • 前进、后退管理
  • 初次加载耗时多

15. NextTick 是做什么的

nextTick,则可以在回调中获取更新后的 DOM。

具体可参考官方文档:深入响应式原理(https://cn.vuejs.org/v2/guide/reactivity.html)。

期望答案(参考):

在下次 DOM 更新循环结束之后执行延迟回调。在修改数据之后立即使用这个方法,获取更新后的 DOM。(官网解释)

解决的问题:有些时候在改变数据后立即要对dom进行操作,此时获取到的dom仍是获取到的是数据刷新前的dom,无法满足需要,这个时候就用到了$nextTick。

代码实例:
// 修改数据
vm.msg = 'Hello'
// DOM 还没有更新
Vue.nextTick(function () {
  // DOM 更新了
})
// 作为一个 Promise 使用 (2.1.0 起新增,详见接下来的提示)
Vue.nextTick()
  .then(function () {
    // DOM 更新了
  })

16.如何watch监听一个对象内部的变化。

watch 是一个对象,对象就有键,有值。

值可以是函数:就是当你监控的家伙变化时,需要执行的函数,这个函数有两个形参,第一个是变化后的值,第二个是变化前的值。

值也可以是函数名:不过这个函数名要用单引号来包裹。

值是包括选项的对象:选项包括有三个。

第一个handler:其值是一个回调函数。即监听到变化时应该执行的函数。

第二个是deep:其值是true或false;确认是否深入监听。deep的意思就是深入观察,监听器会一层层的往下遍历,给对象的所有属性都加上这个监听器(受现代 JavaScript 的限制 (以及废弃 Object.observe),Vue 不能检测到对象属性的添加或删除)

第三个是immediate:其值是true或false;immediate:true代表如果在 wacth 里声明了之后,就会立即先去执行里面的handler方法,如果为 false就跟我们以前的效果一样,不会在绑定的时候就执行

如果只是监听obj内的某一个属性变化,可以直接obj.key进行监听。

watch: {
    'obj.question': function (newQuestion, oldQuestion) {
      this.answer = 'Waiting for you to stop typing...'
      this.debouncedGetAnswer()
    }
  }

如果对整个obj深层监听

watch: {
    obj: {
        handler: function (newQuestion, oldQuestion) {
          this.answer = 'Waiting for you to stop typing...'
          this.debouncedGetAnswer()
        },
        deep: true,
        immediate: true
    }
  }

你可能感兴趣的:(前端笔试题涉及html、css、js、Vue 等)