初级 Vue.js 面试题


1. 为什么Vue被称为“渐进框架”?

使用渐进式框架的代价很小,从而使现有项目(使用其他技术构建的项目)更容易采用并迁移到新框架。Vue.js 是一个渐进式框架,因为你可以逐步将其引入现有应用,而不必从头开始重写整个程序。

Vue 的最基本和核心的部分涉及“视图”层,因此可以通过逐步将 Vue 引入程序并替换“视图”实现来开始你的旅程。

由于其不断发展的性质,Vue 与其他库配合使用非常好,并且非常容易上手。这与 Angular.js 之类的框架相反,后者要求将现有程序完全重构并在该框架中实现。

2. Vue.js 中的声明式渲染是什么?

Vue.js 使渲染数据变得容易,并隐藏了内部实现。例如下面的代码:

HTML

JavaScript

const greeting = “Hello there!”; const appDiv = document.getElementById(“app”); appDiv.innerText = greeting;

上面的代码段将在 ID 为 “app” 的 div 中显示短语 “Hello there!”。代码包含实现结果所需的所有步骤。首先选择 ID 为 “app” 的 DOM 元素,然后用 innerText 属性手动设置 div 的内容。

现在,让我们看看在 Vue 中是怎么做的。

Template

{{ greeting }}

App

new Vue({ data: { greeting: ‘Hello There!’ }, el: ‘#app’ });

我们在 Vue 程序中创建了一个名为 “greeting” 的数据属性,但是只需要在 div 中用 mustache 语法输入 “greeting” 即可,而不必关心内部实现。我们声明了 “greeting” 变量,其余的由 Vue 完成。这就是声明式渲染的样子。Vue 隐藏并管理内部信息。

3. 你用哪个指令遍历对象的属性?

要遍历对象或数组,可以使用 v-for 指令。下面是一个例子:

Template

  • {{ key }} - {{ value }}

App

new Vue({ el: '#app', data: { card: { name: 'John Doe', age: 25, city: 'New York', country: 'US' } } });

输出

  • name - John Doe
  • age - 25
  • city - New York
  • country - US

4. 给出模板,描述 Vue 程序的输出。

模板:

{{title}}

App:

new Vue({ el: '#app', data: { title: 'Vue.js' } })

上面的代码将在 div 中输出字符串

Vue.js

。之所以将整个标签渲染为字符串,是因为 mustache 模板标签 {{title}}将传入的数据视为字符串,而不将其解析为可执行代码。这也有助于缓解把恶意代码注入到页面的 XSS 相关的问题 。这类似于在 JavaScript 中使用 elementSelector.innerText = text 语句。

5. 如何在输入框和数据属性之间实现双向数据绑定?

要实现双向数据绑定,可以使用 v-model 指令。v-model 指令主要是语法糖:

在上面的语句中,每当观察到 “keyup” 事件时,就会将名为 “nameInput” 的数据属性设置为输入框的值。同时,将输入框的 value 属性绑定到 “nameInput” 数据属性。这样在表单字段和数据属性之间建立了双向数据关系。

v-model 可以做到这一点,并且比手动设置更有效地。要使用 v-model 复制上述效果,请再次在同一输入框中输入以下内容:

需要注意的是,当实现双向数据绑定时,使用的数据属性被认为是事实上的来源。在 data 属性上所做的任何更改都将优先于 form 字段上的用户输入事件。

6. 你如何捕获元素上的点击事件?

可以使用 v-on:click 指令捕获 Click 事件。该指令也可以用缩写符号 @click 表示。这是一个例子:

v-on:click 符号

Launch!

@click 符号

Launch!

7. 什么是动态 prop?

当使用 v-bind 指令为 prop 分配值作为绑定到属性的函数时,被称为动态 prop。例如以下组件的 tweet 属性绑定到名为tweetText的数据属性。这与静态硬编码值相反。这种绑定始终是单向的,这意味着数据可以从父组件流到子组件,而绝不会反过来。

8. Vue.js 中的指令是什么?

指令是一系列特殊属性,你可以通过将其添加到模板 HTML 标记中来赋予它们特殊的响应功能。指令允许模板中的元素使用数据属性、方法、计算或监视的属性和内联表达式根据定义的逻辑对更改做出反应。例如以下代码使用 v-on 指令在组件上实现 click 事件侦听器。

或者

在这个例子中,我们使用 v-if 指令基于名为 showButton 的数据属性显示或删除元素与组件。指令以 v- 开头来指示 Vue 特定的属性。此规则的例外是 v-on 和 v-bind 的简写形式。

Vue 还允许定义自己的自定义指令。

9. v-show 指令的用途是什么?

v-show 指令允许有条件地显示元素。在下面的代码中,仅当 isDisplayed 数据属性为 true 时,才会显示该元素。

使用 v-show 指令时,可使用 CSS 的 display 属性切换元素的可见性。

10. v-show 与 v-if 指令有何不同?

v-show 和 v-if 都用于有条件地显示元素,而后者提供了条件渲染的真正实现。v-show 只需切换 CSS 的 display 属性即可显示或隐藏元素,而 v-if 指令可创建或销毁组件。每次显示状态更改时,代价通常会更大。

另一方面,v-show 成本较低,因为它仅切换元素的CSS显示属性。所以如果必须经常切换元素,则 v-show 会提供比 v-if 更好,更优化的结果。

就加载元素的初始渲染成本而言,v-if 不会渲染最初隐藏的元素的节点,而 v-show 会渲染其 CSS display 属性被设置为 none 的元素。

11. 对于作为元素实现的注释框,我们希望使用户能够按下键盘上的Enter键,来将内容提交给名为 “storeComment” 的方法。在代码中对此进行演示。

可以在任何元素上使用 v-on 指令来实现事件侦听器。此外,v-on 还允许我们将按键修饰符用于 “enter”,“tab”,“esc”,“space” 等常见按键。这是一个例子:

模板

App

new Vue({ el: '#app', methods: { storeComment(event) { // access the value of the textarea box using event.target.value or use v-model to bind to a data property } } });

12. 如何在单页 Vue 应用(SPA)中实现路由?

可以通过官方的 vue-router 库在用 Vue 构建的 SPA 中进行路由。该库提供了全面的功能集,其中包括嵌套路线、路线参数和通配符、过渡、HTML5 历史与哈希模式和自定义滚动行为等功能。Vue 还支持某些第三方路由器包。

13. 使用 Vue 时调用 event.preventDefault() 的最佳方式是什么?

在事件侦听器上调用 event.preventDefault() 的最佳方式是将 .prevent 修饰符与 v-on 指令一起使用。这是一个例子:

Do Something

14. 什么是过滤器?

过滤器是在 Vue 程序中实现自定义文本格式的一种非常简单的方法。它们就像可以在表达式中通过管道传递(使用管道字符)以取得结果的运算符。下面是一个可以反转文本字符串的过滤器示例:

模板

{{ title | reverseText }}

App new Vue({ el: '#app', data: { title: 'This is a title' }, filters: { reverseText(text) { return text.split('').reverse().join(''); } } });

输出

eltit a si sihT

在上面的例子中,我们创建了一个名为 reverseText 的过滤器,该过滤器反转文本字符串并返回。这是一个简单的函数,接受输入并返回处理后的输出。通过在过滤器下声明,它就可以成为可以在模板中使用的过滤器。

在模板中,我们只是将 reverseText 过滤器通过管道传递到了想要在 mustache 标签中显示的数据变量。这样可以将多个过滤器管道连接在一起。因此过滤器提供了一种非常优雅的方式来处理文本。

15. 如何动态地在元素上切换 CSS 类?

Vue 允许我们绑定到 class 属性。在下面的例子中,我们将 class 属性绑定到一个对象,该对象允许使用 data 属性切换类。

模板

App

new Vue({ el: '#app', data: { showDiv: true } });

在上面的代码中,只要数据属性 showDiv 为 true,类名 divStyle 将应用于 div。

16. 绑定 HTML 类时,该如何连接类?假设存在一个元素:Process。我们只希望使用名为 “isActive” 的数据属性动态地切换 btnActive 类。

这可以在绑定类时用 Array 来实现。以下是实现方法:

模板

Process

App

new Vue({ el: '#app', data: { isActive: true } });

在上面的代码段中,将串联各个类的数组,并基于 isActive 数据属性的值对对象中的表达式进行响应式评估。

17. 什么是计算属性?

计算属性是一类特殊函数的结果,当从属属性发生变化时,这些函数会自动进行计算。用它们代替内联表达式可以更好地表达复杂的逻辑,在模板中不能作为内联表达式合并。

每个计算方法都可以在模板部分作为属性使用。当从属属性更改时,计算方法将自动计算并缓存结果,这样比使用普通方法更好。方法在访问时将始终会重新计算,而如果自上一次计算和缓存阶段以来该方法内使用的属性未发生更改,则计算的属性将不会重新计算。

需要注意的是,仅当方法中使用的属性是响应性的(例如数据属性)时,才考虑依赖关系的更改。

这是一个演示计算属性的简单例子:

模板

App

const emailRegEx = /^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/ new Vue({ el: '#app', data: { email: '' }, computed: { isInvalid() { return !emailRegEx.test(this.email); } } });

在上面的代码示例中,如果正则表达式测试针对电子邮件输入框失败,则 isValid 计算属性将返回 true。如果电子邮件验证程序认为输入的值无效,就会看到文本框便为红色(你必须创建一个名为 .invalid 的类,并将背景颜色属性设置为红色)。当用户键入内容时,将重新执行计算的方法,并且在验证格式之后,动态删除无效的类。

18. 如何确保在单文件组件中定义的 CSS 样式仅应用于该组件,而不被用于其他组件?

这可以通过样式标签上的 scoped 属性来实现。在内部 Vue 使用 PostCSS 插件为所有样式元素分配唯一的数据属性,然后使样式针对这些唯一的元素。举个例子:

This is a title

19. 如何将数据从父组件传递到子组件?

可以用作为组件中单向入口的 prop 把数据向下传递到子组件。这是一个例子:

contact-list-item 上绑定的 prop “contact” 是一个入口,用于从用作子项的父组件接收数据。在 contact-list-item 组件中:

{{ contact.name }} {{ contact.email }}

在这里声明了一个名为 “contact” 的 prop 引入数据,然后可以直接在模板部分中显示。

20. 什么是组件?

组件本质上是 Vue 实例,它们封装模板、逻辑和可选的本地响应性数据属性,能够提供可重新使用的自定义构建元素。可重用性是构建组件的核心。

使用单文件组件构建应用程序时,组件在扩展名为 .vue 的文件中定义。单文件组件包含三个部分:模板部分定义了该组件的 HTML 布局;脚本部分定义了数据、属性和逻辑单元(如方法)并将内容导出为 Vue 组件;还有一个样式部分,用于定义组件的样式表。单文件组件使用 Webpack 等模块捆绑器进行编译。

21. 什么是生命周期hook?列出一些生命周期hook。

Vue 实例(组件)从其初始化到销毁和删除都经历生命周期。在整个过程中,Vue 允许开发人员运行自定义函数的几个阶段。这些函数称为生命周期 hook。以下是一些生命周期 hook 的列表:

  • created
  • mounted
  • updated
  • destroyed

22. 什么是插槽(slot)?

插槽允许你定义可以封装和接受子 DOM 元素的元素。组件模板中的 元素作为通过组件标签捕获的所有DOM元素的出口。这是一个例子:

Post.vue |实现插槽的组件

{{title}}

App.vue | 使用Post组件的App组件

Vue 是用于构建用户界面的渐进框架。与其他框架不同,Vue从头开始设计以逐渐采用。核心库仅集中在视图层,并且很容易与其他库或现有项目集成。另一方面,当与现代工具和支持库结合使用时,Vue也完全能够为复杂的单页应用程序提供支持。

在上面的示例中,斜体文本显示在 Post 组件中标有 元素的区域内。

23. 什么是观察者?

观察者允许我们观察更改的特定属性,并执行定义为函数的自定义操作。尽管它们的用例与计算的属性相交叉,但是当某些数据属性发生改变时,有时需要观察者执行自定义操作或运行代价昂贵的操作。

24. 如何从子组件发出自定义事件?

可以用 $emit('event-name', eventPayload)发出自定义事件。然后可以像其他事件一样,用 v-on 指令在父组件上拦截。

25. 开发人员经常使用字母 “vm” 作为变量名来声明根 Vue 实例。例如 const vm = new Vue()。在这种情况下,“vm”指的是什么?

虽然这不是约定,但是开发人员经常使用变量名称 'vm' 来命名根 Vue 实例,该变量名称代表 'ViewModel',因为 Vue 本质上负责视图层,并且部分受到了 MVVM 模式的启发(Model-View-View-Model)。但是,根本没有必要将根实例命名为 “vm”。

前端开发面试题答案(1)


1、页面重构怎么操作?

网站重构:在不改变外部行为的前提下,简化结构、添加可读性,而在网站前端保持一致的行为。

也就是说是在不改变UI的情况下,对网站进行优化,在扩展的同时保持一致的UI。

对于传统的网站来说重构通常是:

表格(table)布局改为DIV+CSS

使网站前端兼容于现代浏览器(针对于不合规范的CSS、如对IE6有效的)

对于移动平台的优化

针对于SEO进行优化

深层次的网站重构应该考虑的方面

减少代码间的耦合

让代码保持弹性

严格按规范编写代码

设计可扩展的API

代替旧有的框架、语言(如VB)

增强用户体验

通常来说对于速度的优化也包含在重构中

压缩JS、CSS、image等前端资源(通常是由服务器来解决)

程序的性能优化(如数据读写)

采用CDN来加速资源加载

对于JS DOM的优化

HTTP服务器的文件缓存

2、列举IE与其他浏览器不一样的特性?

*事件不同之处:

    触发事件的元素被认为是目标(target)。而在 IE 中,目标包含在 event 对象的 srcElement 属性;

    获取字符代码、如果按键代表一个字符(shift、ctrl、alt除外),IE 的 keyCode 会返回字符代码(Unicode),DOM 中按键的代码和字符是分离的,要获取字符代码,需要使用 charCode 属性;

    阻止某个事件的默认行为,IE中阻止某个事件的默认行为,必须将 returnValue 属性设置为 false,Mozilla 中,需要调用 preventDefault() 方法;

停止事件冒泡,IE 中阻止事件进一步冒泡,需要设置 cancelBubble 为 true,Mozzilla 中,需要调用 stopPropagation();

3、99%的网站都需要被重构是那本书上写的?

网站重构:应用web标准进行设计(第2版)

4、什么叫优雅降级和渐进增强?

优雅降级:Web站点在所有新式浏览器中都能正常工作,如果用户使用的是老式浏览器,则代码会针对旧版本的IE进行降级处理了,使之在旧式浏览器上以某种形式降级体验却不至于完全不能用。

如:border-shadow

渐进增强:从被所有浏览器支持的基本功能开始,逐步地添加那些只有新版本浏览器才支持的功能,向页面增加不影响基础浏览器的额外样式和功能的。当浏览器支持时,它们会自动地呈现出来并发挥作用。

如:默认使用flash上传,但如果浏览器支持 HTML5 的文件上传功能,则使用HTML5实现更好的体验;

5、是否了解公钥加密和私钥加密。

一般情况下是指私钥用于对数据进行签名,公钥用于对签名进行验证;

HTTP网站在浏览器端用公钥加密敏感数据,然后在服务器端再用私钥解密。

6、WEB应用从服务器主动推送Data到客户端有那些方式?

html5提供的Websocket

不可见的iframe

WebSocket通过Flash

XHR长时间连接

XHR Multipart Streaming

前端开发面题答案(2)


21、如何判断一个对象是否属于某个类?

  使用instanceof

  if(a instanceof Person){

      alert('yes');

   }

22、new操作符具体干了什么呢?

(1)创建一个空对象,并且 this 变量引用该对象,同时还继承了该函数的原型。

(2)属性和方法被加入到 this 引用的对象中。

(3)新创建的对象由 this 所引用,并且最后隐式的返回 this 。

var obj = {};

obj.__proto__ = Base.prototype;

Base.call(obj);

23、Javascript中,有一个函数,执行时对象查找时,永远不会去查找原型,这个函数是?

hasOwnProperty

javaScript中hasOwnProperty函数方法是返回一个布尔值,指出一个对象是否具有指定名称的属性。此方法无法检查该对象的原型链中是否具有该属性;该属性必须是对象本身的一个成员。

使用方法:

object.hasOwnProperty(proName)

其中参数object是必选项。一个对象的实例。

proName是必选项。一个属性名称的字符串值。

如果 object 具有指定名称的属性,那么JavaScript中hasOwnProperty函数方法返回 true,反之则返回 false。

24、JSON 的了解?

JSON(JavaScript Object Notation) 是一种轻量级的数据交换格式。

它是基于JavaScript的一个子集。数据格式简单, 易于读写, 占用带宽小

如:{"age":"12", "name":"back"}

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);

[].forEach.call($$("*"),function(a){a.style.outline="1pxsolid #"+(~~(Math.random()*(1能解释一下这段代码的意思吗?

25、js延迟加载的方式有哪些?

defer和async、动态创建DOM方式(用得最多)、按需异步载入js

26、Ajax 是什么? 如何创建一个Ajax?

ajax的全称:AsynchronousJavascript And XML。

异步传输+js+xml。

所谓异步,在这里简单地解释就是:向服务器发送请求的时候,我们不必等待结果,而是可以同时做其他的事情,等到有了结果它自己会根据设定进行后续操作,与此同时,页面是不会发生整页刷新的,提高了用户体验。

(1)创建XMLHttpRequest对象,也就是创建一个异步调用对象

(2)创建一个新的HTTP请求,并指定该HTTP请求的方法、URL及验证信息

(3)设置响应HTTP请求状态变化的函数

(4)发送HTTP请求

(5)获取异步调用返回的数据

(6)使用JavaScript和DOM实现局部刷新

27、Ajax 解决浏览器缓存问题?

(1)在ajax发送请求前加上anyAjaxObj.setRequestHeader("If-Modified-Since","0")。

(2)在ajax发送请求前加上anyAjaxObj.setRequestHeader("Cache-Control","no-cache")。

(3)在URL后面加上一个随机数: "fresh=" + Math.random();。

(4)在URL后面加上时间搓:"nowtime=" + new Date().getTime();。

(5)如果是使用jQuery,直接这样就可以了 $.ajaxSetup({cache:false})。这样页面的所有ajax都会执行这条语句就是不需要保存缓存记录。

28、同步和异步的区别?

同步的概念应该是来自于OS中关于同步的概念:不同进程为协同完成某项工作而在先后次序上调整(通过阻塞,唤醒等方式).同步强调的是顺序性.谁先谁后.异步则不存在这种顺序性.

同步:浏览器访问服务器请求,用户看得到页面刷新,重新发请求,等请求完,页面刷新,新内容出现,用户看到新内容,进行下一步操作。

异步:浏览器访问服务器请求,用户正常操作,浏览器后端进行请求。等请求完,页面不刷新,新内容也会出现,用户看到新内容。

29、如何解决跨域问题?

jsonp、 iframe、window.name、window.postMessage、服务器上设置代理页面

30、模块化开发怎么做?

立即执行函数,不暴露私有成员

   var module1 = (function(){

    var_count = 0;

    var m1 =function(){

    //...

    };

    var m2 =function(){

    //...

    };

    return {

    m1 :m1,

    m2 : m2

    };

    })();

31、AMD(Modules/Asynchronous-Definition)、CMD(CommonModule Definition)规范区别?

Asynchronous Module Definition,异步模块定义,所有的模块将被异步加载,模块加载不影响后面语句运行。所有依赖某些模块的语句均放置在回调函数中。

 区别:

    (1)对于依赖的模块,AMD 是提前执行,CMD 是延迟执行。不过RequireJS 从 2.0 开始,也改成可以延迟执行(根据写法不同,处理方式不同)。CMD 推崇 as lazy as possible.

    (2)CMD 推崇依赖就近,AMD 推崇依赖前置。看代码:

// CMD

define(function(require, exports, module) {

   var a = require('./a')

   a.doSomething()

   // 此处略去 100 行

   var b = require('./b') // 依赖可以就近书写

   b.doSomething()

   // ...

})

// AMD 默认推荐

define(['./a', './b'], function(a, b) { // 依赖必须一开始就写好

   a.doSomething()

   // 此处略去 100 行

   b.doSomething()

   // ...

})

32、异步加载JS的方式有哪些?

  (1)defer,只支持IE

  (2)async:

  (3)创建script,插入到DOM中,加载完毕后callBack

33、documen.write和 innerHTML的区别

document.write只能重绘整个页面

innerHTML可以重绘页面的一部分

34、DOM操作——怎样添加、移除、移动、复制、创建和查找节点?

(1)创建新节点

 createDocumentFragment()    //创建一个DOM片段

 createElement()   //创建一个具体的元素

 createTextNode()   //创建一个文本节点

(2)添加、移除、替换、插入

 appendChild()

 removeChild()

 replaceChild()

 insertBefore() //在已有的子节点前插入一个新的子节点

(3)查找

 getElementsByTagName()    //通过标签名称

 getElementsByName()    //通过元素的Name属性的值(IE容错能力较强,会得到一个数组,其中包括id等于name值的)

 getElementById()    //通过元素Id,唯一性

35、.call() 和 .apply() 的区别?

  例子中用 add 来替换 sub,add.call(sub,3,1)== add(3,1) ,所以运行结果为:alert(4);

  注意:js 中的函数其实是对象,函数名是对 Function 对象的引用。

   function add(a,b)

    {

       alert(a+b);

    }

   function sub(a,b)

    {

       alert(a-b);

    }

   add.call(sub,3,1);

36、jquery.extend 与jquery.fn.extend的区别?

* jquery.extend 为jquery类添加类方法,可以理解为添加静态方法

* jquery.fn.extend:

    源码中jquery.fn= jquery.prototype,所以对jquery.fn的扩展,就是为jquery类添加成员函数

使用:

jquery.extend扩展,需要通过jquery类来调用,而jquery.fn.extend扩展,所有jquery实例都可以直接调用。

37、Jquery与jQuery UI 有啥区别?

*jQuery是一个js库,主要提供的功能是选择器,属性修改和事件绑定等等。

*jQuery UI则是在jQuery的基础上,利用jQuery的扩展性,设计的插件。

 提供了一些常用的界面元素,诸如对话框、拖动行为、改变大小行为等等

38、jquery 中如何将数组转化为json字符串,然后再转化回来?

jQuery中没有提供这个功能,所以你需要先编写两个jQuery的扩展:

   $.fn.stringifyArray = function(array) {

       return JSON.stringify(array)

    }

   $.fn.parseArray = function(array) {

       return JSON.parse(array)

    }

    然后调用:

   $("").stringifyArray(array)

39、针对 jQuery 的优化方法?

*基于Class的选择性的性能相对于Id选择器开销很大,因为需遍历所有DOM元素。

*频繁操作的DOM,先缓存起来再操作。用Jquery的链式调用更好。

 比如:varstr=$("a").attr("href");

*for (var i = size; i < arr.length; i++){}

 for 循环每一次循环都查找了数组(arr) 的.length 属性,在开始循环的时候设置一个变量来存储这个数字,可以让循环跑得更快:

 for(var i = size, length = arr.length; i < length; i++) {}

40、如何判断当前脚本运行在浏览器还是node环境中?(阿里)

this === window ? 'browser' : 'node';

通过判断Global对象是否为window,如果不为window,当前脚本没有运行在浏览器中

41、jQuery 的 slideUp动画,如果目标元素是被外部事件驱动, 当鼠标快速地连续触发外部元素事件, 动画会滞后的反复执行,该如何处理呢?

jquery stop(): 如:$("#div").stop().animate({width:"100px"},100);

42、那些操作会造成内存泄漏?

内存泄漏指任何对象在您不再拥有或需要它之后仍然存在。

垃圾回收器定期扫描对象,并计算引用了每个对象的其他对象的数量。如果一个对象的引用数量为 0(没有其他对象引用过该对象),或对该对象的惟一引用是循环的,那么该对象的内存即可回收。

setTimeout 的第一个参数使用字符串而非函数的话,会引发内存泄漏。

闭包、控制台日志、循环(在两个对象彼此引用且彼此保留时,就会产生一个循环)

43、JQuery一个对象可以同时绑定多个事件,这是如何实现的?

* 多个事件同一个函数:

   $("div").on("click mouseover", function(){});

* 多个事件不同函数

   $("div").on({

       click: function(){},

       mouseover: function(){}

});

44、知道什么是webkit么? 知道怎么用浏览器的各种工具来调试和debug代码么?

Chrome,Safari浏览器内核。

45、用js实现千位分隔符?

function commafy(num) {

   return num && num

       .toString()

       .replace(/(\d)(?=(\d{3})+\.)/g, function($0, $1) {

           return $1 + ",";

       });

}

console.log(commafy(1234567.90));//1,234,567.90

46、检测浏览器版本版本有哪些方式?

功能检测、userAgent特征检测

比如:navigator.userAgent

//"Mozilla/5.0 (Macintosh; Intel MacOS X 10_10_2) AppleWebKit/537.36

 (KHTML, like Gecko) Chrome/41.0.2272.101 Safari/537.36"

47、What is a Polyfill?

polyfill 是“在旧版浏览器上复制标准 API 的 JavaScript 补充”,可以动态地加载JavaScript 代码或库,在不支持这些标准 API 的浏览器中模拟它们。

例如,geolocation(地理位置)polyfill 可以在 navigator 对象上添加全局的 geolocation 对象,还能添加 getCurrentPosition 函数以及“坐标”回调对象,

所有这些都是 W3C 地理位置 API 定义的对象和函数。因为 polyfill 模拟标准 API,所以能够以一种面向所有浏览器未来的方式针对这些 API 进行开发,

一旦对这些 API 的支持变成绝对大多数,则可以方便地去掉 polyfill,无需做任何额外工作。

48、做的项目中,有没有用过或自己实现一些polyfill 方案(兼容性处理方案)?

比如: html5shiv、Geolocation、Placeholder

49、使用JS实现获取文件扩展名?

function getFileExtension(filename) {

 return filename.slice((filename.lastIndexOf(".") - 1>>> 0) + 2);

}  

String.lastIndexOf() 方法返回指定值(本例中的'.')在调用该方法的字符串中最后出现的位置,如果没找到则返回 -1。

对于'filename'和'.hiddenfile',lastIndexOf的返回值分别为0和-1无符号右移操作符(»>) 将-1转换为4294967295,将-2转换为4294967294,这个方法可以保证边缘情况时文件名不变。

String.prototype.slice() 从上面计算的索引处提取文件的扩展名。如果索引比文件名的长度大,结果为""。

前端开发面试题答案(3)


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

MVVM分为Model、View、ViewModel三者。

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

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

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

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

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

2. Vue 有哪些指令?

v-html、v-show、v-if、v-for等等

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

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

4. 简述Vue的响应式原理

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

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

5. Vue中如何在组件内部实现一个双向数据绑定?

假设有一个输入框组件,用户输入时,同步父组件页面中的数据

具体思路:父组件通过 props 传值给子组件,子组件通过 $emit 来通知父组件修改相应的props值,具体实现如下:

import Vue from 'vue'

const component = {

props: ['value'],

template: `

`,

data () {

return {

}

},

methods: {

handleInput (e) {

this.$emit('input', e.target.value)

}

}}

new Vue({

components: {

CompOne: component

},

el: '#root',

template: `

`,

data () {

return {

value: '123'

}

}})

可以看到,当输入数据时,父子组件中的数据是同步改变的:

我们在父组件中做了两件事,一是给子组件传入props,二是监听input事件并同步自己的value属性。那么这两步操作能否再精简一下呢?答案是可以的,你只需要修改父组件:

template: `

`

v-model 实际上会帮我们完成上面的两步操作。

6. Vue中如何监控某个属性值的变化?

比如现在需要监控data中,obj.a 的变化。Vue中监控对象属性的变化你可以这样:

watch: {

obj: {

handler (newValue, oldValue) {

console.log('obj changed')

},

deep: true

}

}

deep属性表示深层遍历,但是这么写会监控obj的所有属性变化,并不是我们想要的效果,所以做点修改:

watch: {

'obj.a': {

handler (newName, oldName) {

console.log('obj.a changed')

}

}

}

还有一种方法,可以通过computed 来实现,只需要:

computed: {

a1 () {

return this.obj.a

}}

利用计算属性的特性来实现,当依赖改变时,便会重新计算一个新值。

7. Vue中给data中的对象属性添加一个新的属性时会发生什么,如何解决?

示例:

v-for="value in obj" :key="value">

{{value}}

@click="addObjB">添加obj.b

点击button会发现,obj.b 已经成功添加,但是视图并未刷新:

原因在于在Vue实例创建时,obj.b并未声明,因此就没有被Vue转换为响应式的属性,自然就不会触发视图的更新,这时就需要使用Vue的全局api $set():

addObjB () {

// this.obj.b = 'obj.b' this.$set(this.obj, 'b', 'obj.b')

console.log(this.obj)

}

$set()方法相当于手动的去把obj.b处理成一个响应式的属性,此时视图也会跟着改变了:

8. delete和Vue.delete删除数组的区别

delete只是被删除的元素变成了 empty/undefined 其他的元素的键值还是不变。

Vue.delete直接删除了数组 改变了数组的键值。

var a=[1,2,3,4]

var b=[1,2,3,4]

delete a[1]

console.log(a)

this.$delete(b,1)

console.log(b)

9.如何优化SPA应用的首屏加载速度慢的问题?

· 将公用的JS库通过script标签外部引入,减小app.bundel的大小,让浏览器并行下载资源文件,提高下载速度;

· 在配置 路由时,页面和组件使用懒加载的方式引入,进一步缩小 app.bundel 的体积,在调用某个组件时再加载对应的js文件;

· 加一个首屏 loading 图,提升用户体验;

10. 前端如何优化网站性能?

1. 减少 HTTP 请求数量

在浏览器与服务器进行通信时,主要是通过 HTTP 进行通信。浏览器与服务器需要经过三次握手,每次握手需要花费大量时间。而且不同浏览器对资源文件并发请求数量有限(不同浏览器允许并发数),一旦 HTTP 请求数量达到一定数量,资源请求就存在等待状态,这是很致命的,因此减少 HTTP 的请求数量可以很大程度上对网站性能进行优化。

· CSS Sprites:国内俗称 CSS 精灵,这是将多张图片合并成一张图片达到减少 HTTP 请求的一种解决方案,可以通过 CSS background 属性来访问图片内容。这种方案同时还可以减少图片总字节数。

· 合并 CSS 和 JS 文件:现在前端有很多工程化打包工具,如:grunt、gulp、webpack等。为了减少 HTTP 请求数量,可以通过这些工具再发布前将多个 CSS 或者 多个 JS 合并成一个文件。

· 采用 lazyLoad:俗称懒加载,可以控制网页上的内容在一开始无需加载,不需要发请求,等到用户操作真正需要的时候立即加载出内容。这样就控制了网页资源一次性请求数量。

1. 控制资源文件加载优先级

浏览器在加载 HTML 内容时,是将 HTML 内容从上至下依次解析,解析到 link 或者 script 标签就会加载 href 或者 src 对应链接内容,为了第一时间展示页面给用户,就需要将 CSS 提前加载,不要受 JS 加载影响。

一般情况下都是 CSS 在头部,JS 在底部。

1. 利用浏览器缓存

浏览器缓存是将网络资源存储在本地,等待下次请求该资源时,如果资源已经存在就不需要到服务器重新请求该资源,直接在本地读取该资源。

2. 减少重排(Reflow)

基本原理:重排是 DOM 的变化影响到了元素的几何属性(宽和高),浏览器会重新计算元素的几何属性,会使渲染树中受到影响的部分失效,浏览器会验证 DOM 树上的所有其它结点的 visibility 属性,这也是 Reflow 低效的原因。如果 Reflow 的过于频繁,CPU 使用率就会急剧上升。

减少 Reflow,如果需要在 DOM 操作时添加样式,尽量使用 增加 class 属性,而不是通过 style 操作样式。

1. 减少 DOM 操作

2. 图标使用 IconFont 替换

11. 网页从输入网址到渲染完成经历了哪些过程?

大致可以分为如下7步:

1. 输入网址;

2. 发送到DNS服务器,并获取域名对应的web服务器对应的ip地址;

3. 与web服务器建立TCP连接;

4. 浏览器向web服务器发送http请求;

5. web服务器响应请求,并返回指定url的数据(或错误信息,或重定向的新的url地址);

6. 浏览器下载web服务器返回的数据及解析html源文件;

7. 生成DOM树,解析css和js,渲染页面,直至显示完成;

12. jQuery获取的dom对象和原生的dom对象有何区别?

js原生获取的dom是一个对象,jQuery对象就是一个数组对象,其实就是选择出来的元素的数组集合,所以说他们两者是不同的对象类型不等价。

· 原生DOM对象转jQuery对象:

var box = document.getElementById('box');var $box = $(box);

· jQuery对象转原生DOM对象:

var $box = $('#box');var box = $box[0];

13. jQuery如何扩展自定义方法

(jQuery.fn.myMethod=function () {

alert('myMethod');})// 或者:(function ($) {

$.fn.extend({

myMethod : function () {

alert('myMethod');

}

})})(jQuery)

使用:

$("#div").myMethod();

高级 Vue.js面试题


1. 渲染项目列表时,“key” 属性的作用和重要性是什么?

渲染项目列表时,key 属性允许 Vue 跟踪每个 Vnode。key 值必须是唯一的。

如果没有使用 key 属性,并且列表的内容发生了改变(例如对列表进行排序),则虚拟 DOM 宁愿使用更新的数据来修补节点,来反映更改,而不是上下移动元素。这是默认模式,非常有效。

当提供唯一的键值 IS 时,将根据对键的更改对元素进行重新排序(并且不使用新数据对它们进行修补),如果删除了 key(例如,删除列表中的项目时),则对应的元素节点也被销毁或删除。

这里有一个父组件渲染一个子组件列表。我们看到三个列表项被渲染为三个子组件节点。这些子组件都包含一个 span 标记和一个输入框,可能还包含一个本地状态对象(可选)。现在让我们检查两种情况:

当不使用 key 属性时:例如如果列表已重新排序,则 Vue 会使用重新排序的数据简单地修补已经存在的三个节点,而不用移动这些节点。只要用户没有输入或更改这些子组件中一个或多个子组件的本地状态,此方法就可以正常工作。因此假设用户输入了组件编号为 3的输入框,重新排序列表后,组件编号为 3 的 span 标签内容将呗更改,但是输入框将与用户键入的内容击破状态数据一起保留在这里。这是因为 Vue 无法识别组件编号 3,它只是重新修补它所看到的更新数据,即 span 标签的内容。

当在子组件上使用 key 属性时,Vue 会知道该组件的身份,并且在对列表进行重新排序时,将移动节点而不是对其进行修补。这能够确保手动编辑的输入框以及整个组件移动到新位置。

在有条件地渲染组件或元素时,还可以用 key 属性来向 Vue 发出有关元素唯一性的信号,并确保元素不会被新数据重新修补。

2.你将怎样在模板中渲染原始 HTML?

在模板中输出内容的典型方法是使用 mustache 语法标签从方法、属性或数据变量输出数据。但是 mustache 标记会渲染文本。如果你尝试使用 mustache 标记来渲染 HTML,它将以文本字符串的形式去渲染,并且不会被解析。要将内容渲染和解析为 html,我们可以使用 v-html 指令,如下所示。

模板

App 应用

new Vue({ el: '#app', data: { title: '

Vue.js

' } });

输出

Vue.js

如上面的例子所示,v-html 指令解析所有HTML,结果上面的语句将按需渲染。开发人员必须在了解 v-html 的前提下使用。如果不恰当地使用了 v-html,可能会使网站遭受注入攻击,很有可能会从外部源注入并执行恶意代码。

3. 什么是vue-loader?

Vue-loader 是 Webpack 的加载器模块,它使我们可以用 .vue 文件格式编写单文件组件。单文件组件文件有三个部分,即模板、脚本和样式。vue-loader 模块允许 webpack 使用单独的加载器模块(例如 SASS 或 SCSS 加载器)提取和处理每个部分。该设置使我们可以使用 .vue 文件无缝编写程序。

vue-loader 模块还允许把静态资源视为模块依赖性,并允许使用 webpack 加载器进行处理。而且还允许在开发过程中进行热重装。

4. 什么是 mixin?

Mixins 使我们能够为 Vue 组件编写可插拔和可重用的功能。如果你希望在多个组件之间重用一组组件选项,例如生命周期 hook、方法等,则可以将其编写为 mixin,并在组件中简单地引用它。然后将 mixin 的内容合并到组件中。如果你要在 mixin 中定义生命周期 hook,那么它在执行时将优先于组件自己的 hook 。

5. 在开发过程中,如果你的 Vue 程序和后端 API 服务器未在同一主机上运行,该如何代理 API 请求?

假设我们有一个运行在 localhost:4040 上的 Node.js 后端服务器。为了确保代理并可以从组件中访问它,可以配置 vue.config.js 文件并包含 devServer 部分,如下所示:

在 vue.config.js 文件中:

module.exports: { devServer: { proxy: { '/api': { target: ‘http://localhost:4040/api’, changeOrigin: true } } } }

6. prop 如何指定其类型要求?

通过实现 prop 验证选项,可以为单个 prop 指定类型要求。这对生产没有影响,但是会在开发阶段发出警告,从而帮助开发人员识别传入数据和 prop 的特定类型要求的潜在问题。

配置三个 prop 的例子:

props: { accountNumber: { type: Number, required: true }, name: { type: String, required: true }, favoriteColors: Array }

7. 什么是虚拟 DOM?

文档对象模型或 DOM 定义了一个接口,该接口允许 JavaScript 之类的语言访问和操作 HTML 文档。元素由树中的节点表示,并且接口允许我们操纵它们。但是此接口需要付出代价,大量非常频繁的 DOM 操作会使页面速度变慢。

Vue 通过在内存中实现文档结构的虚拟表示来解决此问题,其中虚拟节点(VNode)表示 DOM 树中的节点。当需要操纵时,可以在虚拟 DOM的 内存中执行计算和操作,而不是在真实 DOM 上进行操纵。这自然会更快,并且允许虚拟 DOM 算法计算出最优化的方式来更新实际 DOM 结构。

一旦计算出,就将其应用于实际的 DOM 树,这就提高了性能,这就是为什么基于虚拟 DOM 的框架(例如 Vue 和 React)如此突出的原因。

8. 什么是 Vue 插件?

Vue 插件允许开发人员构建全局级别的功能并将其添加到 Vue。用于向程序添加可以全局访问的方法和属性、资源,选项,mixin 以及其他自定义 API。VueFire 是 Vue 插件的一个例子,该插件添加了 Firebase 特定的方法并将其绑定到整个程序。之后 firebase 函数可在程序结构中的任何位置的 this 上下文中使用。

9. 什么是渲染函数?举个例子。

Vue 允许我们以多种方式构建模板,其中最常见的方式是只把 HTML 与特殊指令和 mustache 标签一起用于响应功能。但是你也可以通过 JavaScript 使用特殊的函数类(称为渲染函数)来构建模板。这些函数与编译器非常接近,这意味着它们比其他模板类型更高效、快捷。由于你使用 JavaScript 编写渲染函数,因此可以在需要的地方自由使用该语言直接添加自定义函数。

对于标准 HTML 模板的高级方案非常有用。

这里是用 HTML 作为模板的 Vue 程序

new Vue({ el: '#app', data: { fruits: ['Apples', 'Oranges', 'Kiwi'] }, template: `

Fruit Basket

  1. {{ fruit }}

` });

这里是用渲染函数开发的同一个程序:

new Vue({ el: '#app', data: { fruits: ['Apples', 'Oranges', 'Kiwi'] }, render: function(createElement) { return createElement('div', [ createElement('h1', 'Fruit Basket'), createElement('ol', this.fruits.map(function(fruit) { return createElement('li', fruit); })) ]); } });

输出:

Fruit Basket

  1. Apples
  2. Oranges
  3. Kiwi

在上面的例子中,我们用了一个函数,它返回一系列 createElement() 调用,每个调用负责生成一个元素。尽管 v-for 指令在基于 HTML 的模板中起作用,但是当使用渲染函数时,可以简单地用标准 .map() 函数遍历 fruits 数据数组。

10. 哪个生命周期 hook 最适合从 API 调用中获取数据?

尽管这取决于组件的用途及,但是创建的生命周期 hook 内通常非常适合放置 API 调用。这时可以使用组件的数据和响应性功能,但是该组件尚未渲染。

11. 什么时候调用 “updated” 生命周期 hook ?

在更新响应性数据并重新渲染虚拟 DOM 之后,将调用更新的 hook。它可以用于执行与 DOM 相关的操作,但是(默认情况下)不能保证子组件会被渲染,尽管也可以通过在更新函数中使用 this.$nextTick 来确保。

12. 在 Vue 实例中编写生命周期 hook 或其他 option/propertie 时,为什么不使用箭头函数?

箭头函数自己没有定义 this 上下文,而是绑定到其父函数的上下文中。当你在 Vue 程序中使用箭头函数(=>)时,this 关键字病不会绑定到 Vue 实例,因此会引发错误。所以强烈建议改用标准函数声明。

13. 什么时候使用keep-alive元素?

当由于数据属性或其他某种响应状态而动态切换组件时,每次将它们切换到渲染状态时,都会被重新渲染。尽管你可能需要这种行为,但在某些情况下重新渲染可能是不合适的。例如在创建时从 API 调用中引入数据的组件。你可能不希望每次动态切换这个组件进行渲染时都调用此 API。这时你可以将组件包含在 keep-alive 元素中。keep-alive 元素缓存该组件并从那里获取它,而不是每次都重新渲染它。

14. 在大型 Vue 程序中管理状态的推荐方法是什么?为什么?

当程序在功能和代码方面不断增长时,状态管理会变得困难,并且使用无穷无尽的下游网络 prop 和上游事件当然不是明智的决定。在这种情况下,有必要将状态管理转移到中央管理系统。Vue 生态系统中提供了 Vuex,它是官方的状态管理库,也是推荐用于集中存储状态的模式。

Vuex 允许维护中央状态。组件将 Vuex 用作响应性数据存储,并在状态更新时进行更新。多个或者不相关的组件可以依赖于相同的中央存储。

在这种情况下,Vue 充当纯 View 层。要修改状态,视图层(例如按钮或交互式组件)需要发出 Vuex Action,然后执行所需的任务。为了更新或修改状态,Vuex 提供了 Mutations。

这个工作流程的目的是留下可用的操作痕迹。

15. 什么是异步组件?

当大型程序使用大量组件时,从服务器上同时加载所有组件可能是没有意义的。在这种情况下,Vue 允许我们在需要时定义从服务器异步加载的组件。在声明或注册组件时,Vue 接受提供 Promise 的工厂函数。然后可以在调用该组件时对其进行“解析”。

通过仅加载基本组件并把异步组件的加载推迟到未来的调用时间,可以节省带宽和程序加载时间。

这是一个异步组件的简单示例。

new Vue({ components: { ‘tweet-box’: () => import(‘./components/async/TweetBox’) } });

当以这种方式使用时,Webpack 的代码拆分将用于提供此功能。

https://github.com/febobo/web-interview

Logo

前往低代码交流专区

更多推荐