前端基础面试题


这里面的是我遇到的面试题

JavaScript面试题

js中==和===区别

简单来说: == 代表相同, ===代表严格相同, 为啥这么说呢,

这么理解: 当进行双等号比较时候: 先检查两个操作数数据类型,如果相同, 则进行===比较, 如果不同, 则愿意为你进行一次类型转换, 转换成相同类型后再进行比较, 而===比较时, 如果类型不同,直接就是false.

操作数1 == 操作数2, 操作数1 === 操作数2

比较过程:

  双等号==:

  (1)如果两个值类型相同,再进行三个等号(===)的比较

  (2)如果两个值类型不同,也有可能相等,需根据以下规则进行类型转换在比较:

    1)如果一个是null,一个是undefined,那么相等

    2)如果一个是字符串,一个是数值,把字符串转换成数值之后再进行比较

  

  三等号===:

  (1)如果类型不同,就一定不相等

  (2)如果两个都是数值,并且是同一个值,那么相等;如果其中至少一个是NaN,那么不相等。(判断一个值是否是NaN,只能使用isNaN( ) 来判断)

  (3)如果两个都是字符串,每个位置的字符都一样,那么相等,否则不相等。

  (4)如果两个值都是true,或是false,那么相等

  (5)如果两个值都引用同一个对象或是函数,那么相等,否则不相等

  (6)如果两个值都是null,或是undefined,那么相等

JS如何避免全局变量污染

  1. 加上个人标识符

  2. 匿名函数

    如果是A写的变量跟B写的变量名字一样,那么就会造成变量冲突,此时每个人之间都可以使用匿名函数来开发

    <!doctype html>
    <html>
        <head>
            <meta charset="UTF-8">
            <title>使用匿名函数解决变量作用域问题</title>
            <script>
                (function() {
                    //程序员a写的代码
                    var a = 123;
                    alert(a);
                })();
            </script>
        </head>
    
        <body>
    
            <script>
                (function() {
                    //程序员b写的代码
                    var a = 89;
                    alert(a);
                })();
            </script>
    
    
       <script>
           (function() {
               //程序员c写的代码
               alert(a);
           })();
       </script>

       这里每个程序员定义了自己的匿名函数,在不同的函数中定义变量,这个变量就是一个局部变量。 <br />
       用匿名函数将脚本包起来,可以有效控制全局变量,避免冲突。

   </body>
```

但是如果是不同人之间要共享一个变量的话,如上代码就用不了了

解决方案: 将多个全局变量包装在一起,使用一个hash全局变量,类似于一个集合一样的用。

  1. 使用命名空间解决问题

为解决如上问题,可以使用 命名空间的方法

<!doctype html>
<html>
    <head>
        <meta charset="UTF-8">
        <title>使用hash变量作为全局变量</title>

        <script>
            //hash全局变量
            var GLOBAL = {};
        </script>

        <script>
            (function() {
                //程序员a写的代码
                var a = 123;
                alert(a);
            })();
        </script>
    </head>

    <body>

        <script>
            (function() {
                //程序员b写的代码:操作全局GLOBAL变量
                GLOBAL.a = 89;
                alert("程序员b:" + GLOBAL.a);
            })();
        </script>


        <script>
            (function() {
                //程序员c写的代码访问的就是全局变量
                alert("程序员c:" + GLOBAL.a);
            })();
        </script>

        在这里使用了GLOBAL作为全局变量名, 在匿名函数间要传递值的话,将这些变量作为全局变量的属性即可。 <br />
        但GLOBAL是全局变量,它在各个函数间都可以访问到,这很容易让GLOBAL的属性不小心被覆盖掉。 <br />
        解决方案:<br />
        命名空间


    </body>
</html>

但是这样的话,如果B不小心把GLOBAL重新赋值了,那么其他人用的变量就会出错

<!doctype html>
<html>
    <head>
        <meta charset="UTF-8">
        <title>全局变量GLOBAL中添加定义命名空间的函数</title>

        <script>
            //hash全局变量
            var GLOBAL = {};
            //   str :表示要生成的命名空间,例如:    GLOBAL.A.name  或是     A.name
            GLOBAL.namespace = function(str) {
                var arr = str.split(".");
                var o = GLOBAL;
                var i = (arr[0] == "GLOBAL" ? 1 : 0); //如果str中的第一部分为GLOBAL的话,命名空间从第二个开始计算
                for (; i < arr.length; i++) {
                    o[arr[i]] = o[arr[i]] || {};
                    o = o[arr[i]];
                }
            }
        </script>

        <script>
            /*
            * @method 功能A:
            * @author 程序员a
            * @connect 1234567
            * @time 2015-01-01
            */
            (function() {
                //程序员a写的代码
                GLOBAL.namespace("A.person"); //程序员a定义了自己的命名空间A,并在A下面定义了子命名空间person
                GLOBAL.A.person.name = "zy";
                GLOBAL.A.person.age = 22;
                alert(GLOBAL.A.person.name + "\t" + GLOBAL.A.person.age);
            })();
        </script>
    </head>

    <body>

        <script>
            /*
            * @method 功能B:
            * @author 程序员b
            * @connect 1234567
            * @time 2015-01-01
            */
            (function() {
                //程序员b写的代码:定义自己的命名空间
                GLOBAL.namespace("B.student"); //程序员a定义了自己的命名空间B,并在B下面定义了子命名空间student
                GLOBAL.B.student.name = "lisi";
                GLOBAL.B.student.age = 33;
                alert(GLOBAL.B.student.name + "\t" + GLOBAL.B.student.age);
            })();
        </script>


        <script>
            (function() {
            /*
            * @method 功能C:
            * @author 程序员c
            * @connect 1234567
            * @time 2015-01-01
            */
                alert("程序员c操作A命名空间下的变量:" + GLOBAL.A.person.name + "\t" + GLOBAL.A.person.age);
                alert("程序员c操作B命名空间下的变量:" + GLOBAL.B.student.name + "\t" + GLOBAL.B.student.age);
            })();
        </script>


        以上体现的就是合理使用命名空间解决变量冲突的问题。

    </body>
</html>

NaN是什么数据类型

NaN是数字类型的,但是它又可以用isNaN()检测,isNaN() 函数用于检查其参数是否是非数字值

isNaN() 函数通常用于检测 parseFloat() 和 parseInt() 的结果,以判断它们表示的是否是合法的数字

isNaN()为false的两种情况

isNaN(123)    //false
isNaN('123')    //false

通俗的讲isNaN()是用来检测非合法数字的,只要不是数字,或者可以转换为数字的都是true
注意isNaN(true) //false isNaN(false) //false isNaN(undefined) //true
这是因为:

Number(true)    //1
Number(false)  //0
Number(undefined)  //NaN

在ES6的Number.isNaN()扩展方法没有出现之前,全局的isNaN()方法是比较可靠的方式判断是否为NaN,但是在ES6出来之后,我们可以使用Number.isNaN()方法进行可靠的判断NaN值
Number.isNaN()方法的判断过程:首先判断传入的参数是否为数值类型,如果判断为true再使用isNaN()方法进行判断。为false就直接返回flase
所以:

Number.isNaN(undefined)   //false

由此得出NaN是一个非法数字,更是一个没有固定值的数字
所以:

NaN != NaN  // true
NaN !== NaN  // true

||和&&的问题

console.log('0 || 1=' + (0 || 1))        //1
console.log('1 || 0=' + (1 || 0))        //1
console.log('2 || 0=' + (2 || 0))        //2
console.log('0 || 2=' + (0 || 2))        //2
console.log('2 || 1=' + (2 || 1))        //1
console.log('1 || 2=' + (1 || 2))        //1
console.log('  ')
console.log('0 && 1=' + (0 && 1))        //0
console.log('1 && 0=' + (1 && 0))        //0
console.log('2 && 0=' + (2 && 0))        //0
console.log('0 && 2=' + (0 && 2))        //0
console.log('2 && 1=' + (2 && 1))        //1
console.log('1 && 2=' + (1 && 2))        //2

&& 是与运算表达式,可以理解为当 && 前面的值为真时,执行 && 后面的表达式, && 前面的表达式为假时,返回false。
|| 或运算表达式,可以理解为当 || 前面的值为假时,执行|| 后面的表达式。当 || 前面的表达式为真时,直接返回前面的表达式。

变量声明的问题

function h5course() {
//     var a;
//     b = 2;
var a = b = 2        //var a=b=2; 等价于 var a=(b=2);
}                        //其中只有a被声明了,b是自动解析为全局变量了
h5course();

console.log(typeof a !== 'undefined') //a is not defined         false
console.log(typeof b !== 'undefined') //true                         true

变量拼接问题

var a = 11
var b = 22
var c = Number(a) + Number(b)

console.log('A||B=' + Number(a) + Number(b))    //1122
console.log(c)                                    //33

Vue面试题总结

1.什么是虚拟 DOM?

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

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

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

计算机原理题

讲讲输入完网址按下回车,到看到网页这个过程中发生了什么

  • a. 域名解析
  • b. 发起TCP的3次握手
  • c. 建立TCP连接后发起http请求
  • d. 服务器端响应http请求,浏览器得到html代码
  • e. 浏览器解析html代码,并请求html代码中的资源
  • f. 浏览器对页面进行渲染呈现给用户

谈谈你对前端性能优化的理解

  • a. 请求数量:合并脚本和样式表,CSS Sprites,拆分初始化负载,划分主域
  • b. 请求带宽:开启GZip,精简JavaScript,移除重复脚本,图像优化,将icon做成字体
  • c. 缓存利用:使用CDN,使用外部JavaScript和CSS,添加Expires头,减少DNS查找,配置ETag,使AjaX可缓存
  • d. 页面结构:将样式表放在顶部,将脚本放在底部,尽早刷新文档的输出
  • e. 代码校验:避免CSS表达式,避免重定向

前端 MV*框架的意义

早期前端都是比较简单,基本以页面为工作单元,内容以浏览型为主,也偶尔有简单的表单操作,基本不太需要框架.

随着 AJAX 的出现,Web2.0的兴起,人们可以在页面上可以做比较复杂的事情了,然后前端框架才真正出现了。

如果是页面型产品,多数确实不太需要它,因为页面中的 JavaScript代码,处理交互的绝对远远超过处理模型的,但是如果是应用软件类产品,这就太需要了。

长期做某个行业软件的公司,一般都会沉淀下来一些业务组件,主要体现在数据模型、业务规则和业务流程,这些组件基本都存在于后端,在前端很少有相应的组织。

从协作关系上讲,很多前端开发团队每个成员的职责不是很清晰,有了前端的 MV框架,这个状况会大有改观。

之所以感受不到 MV*框架的重要性,是因为Model部分代码较少,View的相对多一些。如果主要在操作View和Controller,那当然 jQuery 这类库比较好用了。

请简述盒模型

IE6盒子模型与W3C盒子模型。

文档中的每个元素被描绘为矩形盒子。盒子有四个边界:外边距边界margin, 边框边界border, 内边距边界padding与内容边界content。

CSS3中有个box-sizing属性可以控制盒子的计算方式,

content-box:padding和border不被包含在定义的width和height之内。对象的实际宽度等于设置的width值和border、padding之和。(W3C盒子模型)

border-box:padding和border被包含在定义的width和height之内。对象的实际宽度就等于设置的width值。(IE6盒子模型)

请你谈谈Cookie的弊端

  • a. 每个特定的域名下最多生成的cookie个数有限制
  • b. IE和Opera 会清理近期最少使用的cookie,Firefox会随机清理cookie
  • c. cookie的最大大约为4096字节,为了兼容性,一般不能超过4095字节
  • d. 安全性问题。如果cookie被人拦截了,那人就可以取得所有的session信息。

浏览器本地存储

在HTML5中提供了sessionStorage和localStorage.

sessionStorage用于本地存储一个会话(session)中的数据,这些数据只有在同一个会话中的页面才能访问并且当会话结束后数据也随之销毁,是会话级别的存储。

localStorage用于持久化的本地存储,除非主动删除数据,否则数据是永远不会过期的。

web storage和cookie的区别

  • a. Cookie的大小是受限的
  • b. 每次你请求一个新的页面的时候Cookie都会被发送过去,这样无形中浪费了带宽
  • c. cookie还需要指定作用域,不可以跨域调用
  • d. Web Storage拥有setItem,getItem等方法,cookie需要前端开发者自己封装setCookie,getCookie
  • e. Cookie的作用是与服务器进行交互,作为HTTP规范的一部分而存在 ,而Web Storage仅仅是为了在本地“存储”数据而生
  • f. IE7、IE6中的UserData通过简单的代码封装可以统一到所有的浏览器都支持web storage

线程与进程的区别

  • a. 一个程序至少有一个进程,一个进程至少有一个线程
  • b. 线程的划分尺度小于进程,使得多线程程序的并发性高
  • c. 进程在执行过程中拥有独立的内存单元,而多个线程共享内存,从而极大地提高了程序的运行效率
  • d. 每个独立的线程有一个程序运行的入口、顺序执行序列和程序的出口。但是线程不能够独立执行,必须依存在应用程序中,由应用程序提供多个线程执行控制
  • e. 多线程的意义在于一个应用程序中,有多个执行部分可以同时执行。但操作系统并没有将多个线程看做多个独立的应用,来实现进程的调度和管理以及资源分配

请说出三种减少页面加载时间的方法

  • a. 尽量减少页面中重复的HTTP请求数量
  • b. 服务器开启gzip压缩
  • c. css样式的定义放置在文件头部
  • d. Javascript脚本放在文件末尾
  • e. 压缩合并Javascript、CSS代码
  • f. 使用多域名负载网页内的多个文件、图片

你都使用哪些工具来测试代码的性能?

JSPerf, Dromaeo

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

渐进增强 progressive enhancement:

针对低版本浏览器进行构建页面,保证最基本的功能,然后再针对高级浏览器进行效果、交互等改进和追加功能达到更好的用户体验。

优雅降级 graceful degradation:

一开始就构建完整的功能,然后再针对低版本浏览器进行兼容。

区别:

  • a. 优雅降级是从复杂的现状开始,并试图减少用户体验的供给
  • b. 渐进增强则是从一个非常基础的,能够起作用的版本开始,并不断扩充,以适应未来环境的需要
  • c. 降级(功能衰减)意味着往回看;而渐进增强则意味着朝前看,同时保证其根基处于安全地带

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

  • a. html5 websoket
  • b. WebSocket 通过 Flash
  • c. XHR长时间连接
  • d. XHR Multipart Streaming
  • e. 不可见的Iframe
  • f. <script>标签的长时间连接(可跨域)

对前端界面工程师这个职位是怎么样理解的?

  • a. 前端是最贴近用户的程序员,前端的能力就是能让产品从 90分进化到 100 分,甚至更好
  • b. 参与项目,快速高质量完成实现效果图,精确到1px;
  • c. 与团队成员,UI设计,产品经理的沟通;
  • d. 做好的页面结构,页面重构和用户体验;
  • e. 处理hack,兼容、写出优美的代码格式;
  • f. 针对服务器的优化、拥抱最新前端技术。

平时如何管理你的项目?

  • a. 先期团队必须确定好全局样式(globe.css),编码模式(utf-8) 等;
  • b. 编写习惯必须一致(例如都是采用继承式的写法,单样式都写成一行);
  • c. 标注样式编写人,各模块都及时标注(标注关键样式调用的地方);
  • d. 页面进行标注(例如 页面 模块 开始和结束);
  • e. CSS跟HTML 分文件夹并行存放,命名都得统一(例如style.css);
  • f. JS 分文件夹存放 命名以该JS功能为准的英文翻译。
  • g. 图片采用整合的 images.png png8 格式文件使用 尽量整合在一起使用方便将来的管理

Flash、Ajax各自的优缺点,在使用中如何取舍?

Flash:

  • a. Flash适合处理多媒体、矢量图形、访问机器
  • b. 对CSS、处理文本上不足,不容易被搜索

Ajax:

  • a. Ajax对CSS、文本支持很好,支持搜索
  • b. 多媒体、矢量图形、机器访问不足

共同点:

  • a. 与服务器的无刷新传递消息
  • b. 可以检测用户离线和在线状态
  • c. 操作DOM

请解释一下 JavaScript 的同源策略

同源策略指的是:协议,域名,端口相同,同源策略是一种安全协议。

指一段脚本只能读取来自同一来源的窗口和文档的属性。

AMD和CMD 规范的区别?

AMD 提前执行依赖 - 尽早执行,requireJS 是它的实现

CMD 按需执行依赖 - 懒执行,seaJS 是它的实现

网站重构的理解

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

  • a. 使网站前端兼容于现代浏览器(针对于不合规范的CSS、如对IE6有效的)
  • b. 对于移动平台的优化,针对于SEO进行优化
  • c. 减少代码间的耦合,让代码保持弹性
  • d. 压缩或合并JS、CSS、image等前端资源

浏览器的内核分别是什么?

IE浏览器的内核Trident、Mozilla的Gecko、Chrome的Blink(WebKit的分支)、Opera内核原为Presto,现为Blink

请介绍下cache-control

每个资源都可以通过 Cache-Control HTTP 头来定义自己的缓存策略

Cache-Control 指令控制谁在什么条件下可以缓存响应以及可以缓存多久

Cache-Control 头在 HTTP/1.1 规范中定义,取代了之前用来定义响应缓存策略的头(例如 Expires)。

前端页面有哪三层构成,分别是什么?作用是什么?

  • a. 结构层:由 HTML 或 XHTML 之类的标记语言负责创建,仅负责语义的表达。解决了页面“内容是什么”的问题。
  • b. 表示层:由CSS负责创建,解决了页面“如何显示内容”的问题。
  • c. 行为层:由脚本负责。解决了页面上“内容应该如何对事件作出反应”的问题。

知道的网页制作会用到的图片格式有哪些?

png-8,png-24,jpeg,gif,svg

Webp:谷歌(google)开发的一种旨在加快图片加载速度的图片格式。图片压缩体积大约只有JPEG的2/3,并能节省大量的服务器带宽资源和数据空间。Facebook Ebay等知名网站已经开始测试并使用WebP格式。

Apng:全称是“Animated Portable Network Graphics”, 是PNG的位图动画扩展,可以实现png格式的动态图片效果。04年诞生,但一直得不到各大浏览器厂商的支持,直到日前得到 iOS safari 8的支持,有望代替GIF成为下一代动态图标准。

一次js请求一般情况下有哪些地方会有缓存处理?

  • a. 浏览器端存储
  • b. 浏览器端文件缓存
  • c. HTTP缓存304
  • d. 服务器端文件类型缓存
  • e. 表现层&DOM缓存

一个页面上有大量的图片(大型电商网站),加载很慢,你有哪些方法优化这些图片的加载,给用户更好的体验。

  • a. 图片懒加载,滚动到相应位置才加载图片。
  • b. 图片预加载,如果为幻灯片、相册等,将当前展示图片的前一张和后一张优先下载。
  • c. 使用CSSsprite,SVGsprite,Iconfont、Base64等技术,如果图片为css图片的话。
  • d. 如果图片过大,可以使用特殊编码的图片,加载时会先加载一张压缩的特别厉害的缩略图,以提高用户体验。

谈谈以前端角度出发做好SEO需要考虑什么?

  • a. 了解搜索引擎如何抓取网页和如何索引网页
  • b. meta标签优化
  • c. 关键词分析
  • d. 付费给搜索引擎
  • e. 链接交换和链接广泛度(Link Popularity)
  • f. 合理的标签使用

HTML

文章内有引用于:
版权声明:本文为CSDN博主「Eric_qf」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/qfxietian/article/details/90608484

1.<img>标签上title属性与alt属性的区别是什么?

alt属性是为了给那些不能看到你文档中图像的浏览者提供文字说明的。且长度必须少于100个英文字符或者用户必须保证替换文字尽可能的短。

这包括那些使用本来就不支持图像显示或者图像显示被关闭的浏览器的用户,视觉障碍的用户和使用屏幕阅读器的用户等。

title属性为设置该属性的元素提供建议性的信息。使用title属性提供非本质的额外信息。

2.请写出至少5个html5新增的标签,并说明其语义和应用场景

section:定义文档中的一个章节

nav:定义只包含导航链接的章节

header:定义页面或章节的头部。它经常包含 logo、页面标题和导航性的目录。

footer:定义页面或章节的尾部。它经常包含版权信息、法律信息链接和反馈建议用的地址。

aside:定义和页面内容关联度较低的内容——如果被删除,剩下的内容仍然很合理。

3.请说说你对标签语义化的理解?

  • a. 去掉或者丢失样式的时候能够让页面呈现出清晰的结构
  • b. 有利于SEO:和搜索引擎建立良好沟通,有助于爬虫抓取更多的有效信息:爬虫依赖于标签来确定上下文和各个关键字的权重;
  • c. 方便其他设备解析(如屏幕阅读器、盲人阅读器、移动设备)以意义的方式来渲染网页;
  • d. 便于团队开发和维护,语义化更具可读性,遵循W3C标准的团队都遵循这个标准,可以减少差异化。

4.Doctype作用? 严格模式与混杂模式如何区分?它们有何意义?

声明位于文档中的最前面,处于 标签之前。告知浏览器以何种模式来渲染文档。

严格模式的排版和 JS 运作模式是,以该浏览器支持的最高标准运行。

在混杂模式中,页面以宽松的向后兼容的方式显示。模拟老式浏览器的行为以防止站点无法工作。

DOCTYPE不存在或格式不正确会导致文档以混杂模式呈现。

5.你知道多少种Doctype文档类型?

标签可声明三种 DTD 类型,分别表示严格版本、过渡版本以及基于框架的 HTML 文档。

HTML 4.01 规定了三种文档类型:Strict、Transitional 以及 Frameset。

XHTML 1.0 规定了三种 XML 文档类型:Strict、Transitional 以及 Frameset。

Standards (标准)模式(也就是严格呈现模式)用于呈现遵循最新标准的网页,

Quirks(包容)模式(也就是松散呈现模式或者兼容模式)用于呈现为传统浏览器而设计的网页。

6.HTML与XHTML——二者有什么区别

  • a. XHTML 元素必须被正确地嵌套。
  • b. XHTML 元素必须被关闭。
  • c. 标签名必须用小写字母。
  • d. XHTML 文档必须拥有根元素。

7.html5有哪些新特性、移除了那些元素?

  • a. HTML5 现在已经不是 SGML 的子集,主要是关于图像,位置,存储,多任务等功能的增加。
  • b. 拖拽释放(Drag and drop) API
  • c. 语义化更好的内容标签(header,nav,footer,aside,article,section)
  • d. 音频、视频API(audio,video)
  • e. 画布(Canvas) API
  • f. 地理(Geolocation) API
  • g. 本地离线存储 localStorage 长期存储数据,浏览器关闭后数据不丢失
  • h. sessionStorage 的数据在页面会话结束时会被清除
  • i. 表单控件,calendar、date、time、email、url、search
  • j. 新的技术webworker, websocket等

移除的元素:

  • a. 纯表现的元素:basefont,big,center, s,strike,tt,u;
  • b. 对可用性产生负面影响的元素:frame,frameset,noframes;

8.iframe的优缺点?

优点:

  • a. 解决加载缓慢的第三方内容如图标和广告等的加载问题
  • b. iframe无刷新文件上传
  • c. iframe跨域通信

缺点:

  • a. iframe会阻塞主页面的Onload事件
  • b. 无法被一些搜索引擎索引到
  • c. 页面会增加服务器的http请求
  • d. 会产生很多页面,不容易管理。

9.Quirks模式是什么?它和Standards模式有什么区别?

在写程序时我们也会经常遇到这样的问题,如何保证原来的接口不变,又提供更强大的功能,尤其是新功能不兼容旧功能时。IE6以前的页面大家都不会去写DTD,所以IE6就假定 如果写了DTD,就意味着这个页面将采用对CSS支持更好的布局,而如果没有,则采用兼容之前的布局方式。这就是Quirks模式(怪癖模式,诡异模式,怪异模式)。

区别:总体会有布局、样式解析和脚本执行三个方面的区别。

  • a. 盒模型:在W3C标准中,如果设置一个元素的宽度和高度,指的是元素内容的宽度和高度,而在Quirks 模式下,IE的宽度和高度还包含了padding和border。
  • b. 设置行内元素的高宽:在Standards模式下,给等行内元素设置wdith和height都不会生效,而在quirks模式下,则会生效。
  • c. 设置百分比的高度:在standards模式下,一个元素的高度是由其包含的内容来决定的,如果父元素没有设置百分比的高度,子元素设置一个百分比的高度是无效的用
  • d. 设置水平居中:使用margin:0 auto在standards模式下可以使元素水平居中,但在quirks模式下却会失效。

10.请阐述table的缺点

  • a. 太深的嵌套,比如table>tr>td>h3,会导致搜索引擎读取困难,而且,最直接的损失就是大大增加了冗余代码量。
  • b. 灵活性差,比如要将tr设置border等属性,是不行的,得通过td
  • c. 代码臃肿,当在table中套用table的时候,阅读代码会显得异常混乱
  • d. 混乱的colspan与rowspan,用来布局时,频繁使用他们会造成整个文档顺序混乱。
  • e. table需要多次计算才能确定好其在渲染树中节点的属性,通常要花3倍于同等元素的时间。
  • f. 不够语义

11.简述一下src与href的区别

src用于替换当前元素;href用于在当前文档和引用资源之间确立联系。

src是source的缩写,指向外部资源的位置,指向的内容将会嵌入到文档中当前标签所在位置

href是Hypertext Reference的缩写,指向网络资源所在位置,建立和当前元素(锚点)或当前文档(链接)之间的链接

12.HTML与XHTML——二者有什么区别?

  1. HTML 元素必须被正确地嵌套。
  2. XHTML 元素必须被关闭。
  3. 标签名必须用小写字母。
  4. XHTML 文档必须拥有根元素。

13.iframe的优缺点?

​ 答案:优点:

  • a. 解决加载缓慢的第三方内容如图标和广告等的加载问题

  • b. iframe无刷新文件上传 c. iframe跨域通信

缺点:

  • a. iframe会阻塞主页面的Onload事件 b. 无法被一些搜索引擎索引到

  • c. 页面会增加服务器的http请求 d. 会产生很多页面,不容易管理。

14.全屏滚动的原理是什么?用到了CSS的哪些属性?

  答案:原理:有点类似于轮播,整体的元素一直排列下去,假设有5个需要展示的全屏页面,那么高度是500%,只是展示100%,剩下的可以通过transform进行y轴定位,也可以通过margin-top实现

  overflow:hidden;transition:all 1000ms ease;

15.页面导入样式时,使用link和@import有什么区别?

  • 差别1:本质的差别:link属于XHTML标签,而@import完全是CSS提供的一种方式。

  • 差别2:加载顺序的差别:当一个页面被加载的时候(就是被浏览者浏览的时候),link引用的CSS会同时被加载,而@import引用的CSS会等到页面全部被下载完再被加载。所以有时候浏览@import加载CSS的页面时开始会没有样式(就是闪烁),网速慢的时候还挺明显。

  • 差别3:兼容性的差别:@import是CSS2.1提出的,所以老的浏览器不支持,@import只有在IE5以上的才能识别,而link标签无此问题。

  • 差别4:使用dom(document o bject model文档对象模型 )控制样式时的差别:当使用javascript控制dom去改变样式的时候,只能使用link标签,因为@import不是dom可以控制的.

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

答案:单冒号(:)用于CSS3伪类,双冒号(::)用于CSS3伪元素。

  • ::before就是以一个子元素的存在,定义在元素主体内容之前的一个伪元素。并不存在于dom之中,只存在在页面之中。

  • :before 和 :after 这两个伪元素,是在CSS2.1里新出现的。起初,伪元素的前缀使用的是单冒号语法,但随着Web的进化,在CSS3的规范里,伪元素的语法被修改成使用双冒号,成为::before ::after

17.怎么让Chrome支持小于12px 的文字?

 答案:p{font-size:10px;-webkit-transform:scale(0.8);}//0.8是缩放比例

18.简述一下你对HTML语义化的理解?

答案:

  1. 用正确的标签做正确的事情。

  2. html语义化让页面的内容结构化,结构更清晰,便于对浏览器,搜索引擎解析;

  3. 即使在没有样式CSS情况下也以一种文档格式显示,并且是容易阅读的;

  4. 搜索引擎的爬虫也依赖于HTML标记确定上下文和各个关键字的权重,利用SEO;

  5. 使阅读源代码的人对网站更容易将网站分块,便于阅读维护理解。

9道价值20k薪资的“VUE必备面试题”,快来围观!

本文引用于:https://zhuanlan.zhihu.com/p/142412438

(1)v-if和v-for谁的优先级最高?

当面试官提出这个问题时,显然想要考察应聘者对v-if和v-for的“基本功”,同时还想要考察应聘者如何将理论应用到操作里

基于以上两点,我们可以拓展问题:

当v-if和v-for同时出现时,我们应该怎样优化从而获得更好的性能?

得知了面试官的隐含问题,接下来我们对症下药就可以了。

首先,在源码中找答案:

compiler/codegen/index.js(☜文件中的位置)

做个测试如下:

img

两者同级时,渲染函数如下:

img

_l包含了isFolder的条件判断☝☝

两者不同级时,渲染函数如下:

img

先判断条件再决定是否执行☝☝

正确解答:

1、显然v-for优先于v-if被解析(把你是怎么知道的告诉面试官

2、如果同时出现,每次渲染都会先执行循环再判断条件,无论如何循环都不可避免,浪费了性能

3、要避免出现这种情况,则在外层嵌套template,在这一层进行v-if判断,然后在内部进行v-for循环

4、如果条件出现在循环内部,可通过计算属性提前过滤掉那些不需要显示的项

(2)VUE组件data为什么必须是函数

我们都知道,VUE的data实例必须是函数,那么有没有与之相反的情况呢?答案是肯定的,因为VUE的根实例就没有“必须是函数”这个限制的。

所以,我们在对这道题进行解答之前,我们还要考虑与“VUE组件data对象实例”所对应的“VUE的根实例”。

通过两者的对比论证,会让我们的答案更加清晰缜密、更有说服力。

源码中找答案:

src\core\instance\state.js - initData()

文件中的位置☝

通过源码得知:

函数每次执行都会返回全新data对象实例

测试代码如下:

img

然而程序甚至无法通过vue检测☟☟

img

正确解答:

Vue组件可能存在多个实例,如果使用对象形式定义data,则会导致它们共用一个data对象,那么状态变更将会影响所有组件实例,这是不合理的;

采用函数形式定义,在initData时会将其作为工厂函数返回全新data对象,有效规避多实例之间状态污染问题。

而在Vue根实例创建过程中则不存在该限制,也是因为根实例只能有一个,不需要担心这种情况。

(3)vue中key的作用和工作原理

为了表达的更加透彻,我们可以通过对比测试来寻找key的工作原理:

首先是在源码中找答案,它在文件中的位置是☟

src\core\vdom\patch.js - updateChildren()

测试代码如下:

img

本次案例代码重现的是以下过程☟☟:

img

在不使用Key的情况下是这样的☟☟:

img

如果使用Key☟☟:

// 首次循环patch A

A B C D E

A B F C D E

// 第2次循环patch B

B C D E

B F C D E

// 第3次循环patch E

C D E

F C D E

// 第4次循环patch D

C D

F C D

// 第5次循环patch C

C

F C

// oldCh全部处理结束,newCh中剩下的F,创建F并插入到C前面

正确解答:

1、key的作用主要是为了高效的更新虚拟DOM,其原理是vue在patch过程中通过key可以精准判断两个节点是否是同一个,从而避免频繁更新不同元素,使得整个patch过程更加高效,减少DOM操作量,提高性能。

2、另外,若不设置key还可能在列表更新时引发一些隐蔽的bug

3、vue中在使用相同标签名元素的过渡切换时,也会使用到key属性,其目的也是为了让vue可以区分它们,否则vue只会替换其内部属性而不会触发过渡效果。

(4)你怎么理解vue中的diff算法?

在分析diff算法之前,我们可以看一下VUE的diff算法模型图:

img

接下来还是先从源码入手解决问题:

源码分析1:必要性

lifecycle.js - mountComponent()

组件中可能存在很多个data中的key使用

源码分析2:执行方式

patch.js - patchVnode()

patchVnode是diff发生的地方

整体策略:深度优先,同层比较

源码分析3:高效性

patch.js - updateChildren()

测试代码如下:

img

正确解答:

1、diff算法是虚拟DOM技术的必然产物:通过新旧虚拟DOM作对比(即diff),将变化的地方更新在真实DOM上;

另外,也需要diff高效的执行对比过程,从而降低时间复杂度为O(n)。

2、vue 2.x中为了降低Watcher粒度,每个组件只有一个Watcher与之对应,只有引入diff才能精确找到发生变化的地方。

3、vue中diff执行的时刻是组件实例执行其更新函数时,它会比对上一次渲染结果oldVnode和新的渲染结果newVnode,此过程称为patch

4、diff过程整体遵循深度优先、同层比较的策略;两个节点之间比较会根据它们是否拥有子节点或者文本节点做不同操作;

比较两组子节点是算法的重点,首先假设头尾节点可能相同做4次比对尝试;

如果没有找到相同节点才按照通用方式遍历查找,查找结束再按情况处理剩下的节点;

借助key通常可以非常精确找到相同节点,因此整个patch过程非常高效。

(5)谈一谈对vue组件化的理解?

听到“理解”两个字我们就要注意了,看似一道开放性的问题,实际是要考察我们对VUE组件化的认知基础。

我们可以从定义、优点、使用场景和注意事项等方面展开陈述,同时要强调vue中组件化的一些特点。

始终不变的是“从源码深入解决问题,最终达到深入浅出的效果。”

源码分析1:组件定义

src\core\global-api\assets.js
(☝文件中的位置)
// 组件定义
Vue.component('comp', {
template: '
this is a component
' })

vue-loader会编译template为render函数,最终导出的依然是组件配置对象。☟

源码分析2:组件化优点

lifecycle.js - mountComponent()

☝组件、Watcher、渲染函数和更新函数之间的关系

源码分析3:组件化实现

构造函数,

src\core\global-api\extend.js

实例化及挂载,

src\core\vdom\patch.js - createElm()

正确解答:

1、组件是独立和可复用的代码组织单元。组件系统是 Vue 核心特性之一,它使开发者使用小型、独立和通常可复用的组件构建大型应用;

2、组件化开发能大幅提高应用开发效率、测试性、复用性等;

3、组件使用按分类有:页面组件、业务组件、通用组件;

4、vue的组件是基于配置的,我们通常编写的组件是组件配置而非组件,框架后续会生成其构造函数,它们基于VueComponent,扩展于Vue;

5、vue中常见组件化技术有:属性prop,自定义事件,插槽等,它们主要用于组件通信、扩展等;

6、合理的划分组件,有助于提升应用性能;

7、组件应该是高内聚、低耦合的;

8、遵循单向数据流的原则。

(6)谈一谈对vue设计原则的理解?

和上一题的思路一样,我们首先要明确:关于VUE设计原则,我们要从哪几个方面入手进行详细解答?

而在vue的官网上,就写着大大的定义和特点:

渐进式JavaScript框架

易用、灵活和高效

所以阐述此题的整体思路按照这个展开即可。

正确解答:

首先就是渐进式JavaScript框架:

与其它大型框架不同的是,Vue 被设计为可以自底向上逐层应用。

Vue 的核心库只关注视图层,不仅易于上手,还便于与第三方库或既有项目整合。

另一方面,当与现代化的工具链以及各种支持类库结合使用时,Vue 也完全能够为复杂的单页应用提供驱动。

img

易用性

vue提供数据响应式、声明式模板语法和基于配置的组件系统等核心特性。

这些使我们只需要关注应用的核心业务即可,只要会写js、html和css就能轻松编写vue应用。

灵活性

渐进式框架的最大优点就是灵活性,如果应用足够小,我们可能仅需要vue核心特性即可完成功能;

随着应用规模不断扩大,我们才可能逐渐引入路由、状态管理、vue-cli等库和工具;

不管是应用体积还是学习难度都是一个逐渐增加的平和曲线。

高效性

超快的虚拟 DOM 和 diff 算法使我们的应用拥有最佳的性能表现。

追求高效的过程还在继续,vue3中引入Proxy对数据响应式改进以及编译器中对于静态内容编译的改进都会让vue更加高效。

(7)对MVC、MVP和MVVM的理解

当我们面对这道考题时,往往有些摸不着头脑,因为MVC、MVP和MVVM的知识点非常广泛,很难做到说清、说透。

那要怎么才能回答的简洁有条理?让面试官眼前一亮呢?

来听我给你清晰解读一下这道题的正确思路吧!

其实在日常工作中,类似MVP、MVC这类前端程序,我们程序员甚至自己都没用过,这恰恰就反映了:

前端这些年从无到有,从有到优的变迁过程。

想到这里,我们的解题思路便慢慢浮出水面了,那就是:

按时间顺序,浅谈MVC、MVP、MVVM等系列产品的更新迭代。

Web1.0时代

在web1.0时代,并没有前端的概念。

开发一个web应用多数采用:

http://ASP.NET/Java/PHP编写,

项目通常由多个aspx/jsp/php文件构成。

每个文件中同时包含了HTML、CSS、JavaScript、C#/Java/PHP代码。

系统整体架构可能是这样子的☟:

img

这种架构的好处是简单快捷,但是,缺点也非常明显:JSP代码难以维护

为了让开发更加便捷,代码更易维护,前后端职责更清晰。便衍生出MVC开发模式和框架,前端展示以模板的形式出现。

典型的框架就是:

Spring、Structs、Hibernate。

整体框架如图所示☟:

img

使用这种分层架构,职责清晰,代码易维护。

但这里的MVC仅限于后端,前后端形成了一定的分离,前端只完成了后端开发中的view层。

但是,同样的这种模式存在着一些问题:

1、前端页面开发效率不高

2、前后端职责不清

web 2.0时代

自从Gmail的出现,ajax技术开始风靡全球。有了ajax之后,前后端的职责就更加清晰了。

因为前端可以通过Ajax与后端进行数据交互,因此,整体的架构图也变化成了下面这幅图☟:

img

通过ajax与后台服务器进行数据交换,前端开发人员,只需要开发页面这部分内容,数据可由后台进行提供。

而且ajax可以使得页面实现部分刷新,减少了服务端负载和流量消耗,用户体验也更佳。

这时,才开始有专职的前端工程师。同时前端的类库也慢慢的开始发展,最著名的就是jQuery了。

当然,此架构也存在问题:缺乏可行的开发模式承载更复杂的业务需求,页面内容都杂糅在一起,一旦应用规模增大,就会导致难以维护了。

因此,前端的MVC也随之而来。

前后端分离后的架构演变——MVC、MVP和MVVM

MVC

前端的MVC与后端类似,具备着View、Controller和Model。

Model:负责保存应用数据,与后端数据进行同步

Controller:负责业务逻辑,根据用户行为对Model数据进行修改

View:负责视图展示,将model中的数据可视化出来。

三者形成了一个如图所示的模型:

img

这样的模型,在理论上是可行的。但往往在实际开发中,并不会这样操作。因为开发过程并不灵活。

例如,一个小小的事件操作,都必须经过这样的一个流程,那么开发就不再便捷了。

在实际场景中,我们往往会看到另一种模式,

如图所示☟:

img

这种模式在开发中更加的灵活,backbone.js框架就是这种的模式。

但是,这种灵活可能导致严重的问题:

1、数据流混乱:如下图☟

img

2、View比较庞大,而Controller比较单薄:

由于很多的开发者都会在view中写一些逻辑代码,逐渐的就导致view中的内容越来越庞大,而controller变得越来越单薄。

既然有缺陷,就会有变革。

前端的变化中,似乎少了MVP的这种模式,是因为AngularJS早早地将MVVM框架模式带入了前端。

MVP模式虽然前端开发并不常见,但是在安卓等原生开发中,开发者还是会考虑到它。

MVP

MVP与MVC很接近,P指的是Presenter,presenter可以理解为一个中间人。

它负责着View和Model之间的数据流动,防止View和Model之间直接交流。

我们可以看一下图示☟

img

我们可以通过看到,presenter负责和Model进行双向交互,还和View进行双向交互。

这种交互方式,相对于MVC来说少了一些灵活,VIew变成了被动视图,并且本身变得很小。虽然它分离了View和Model。

但是应用逐渐变大之后,导致presenter的体积增大,难以维护。

要解决这个问题,或许可以从MVVM的思想中找到答案。

MVVM

首先,何为MVVM呢?MVVM可以分解成(Model-View-VIewModel)。

ViewModel可以理解为在presenter基础上的进阶版。如图所示☟☟:

img

ViewModel通过实现一套数据响应式机制自动响应Model中数据变化;

同时Viewmodel会实现一套更新策略自动将数据变化转换为视图更新;

通过事件监听响应View中用户交互修改Model中数据。

这样在ViewModel中就减少了大量DOM操作代码。

MVVM在保持View和Model松耦合的同时,还减少了维护它们关系的代码,使用户专注于业务逻辑,兼顾开发效率和可维护性。

总结:

这三者都是框架模式,它们设计的目标都是为了解决Model和View的耦合问题。

MVC模式出现较早主要应用在后端,如Spring MVC、http://ASP.NET MVC等,在前端领域的早期也有应用,如Backbone.js。

它的优点是分层清晰,缺点是数据流混乱,灵活性带来的维护性问题。

MVP模式在是MVC的进化形式,Presenter作为中间层负责MV通信,解决了两者耦合问题,但P层过于臃肿会导致维护问题。

MVVM模式在前端领域有广泛应用,它不仅解决MV耦合问题,还同时解决了维护两者映射关系的大量繁杂代码和DOM操作代码,在提高开发效率、可读性同时还保持了优越的性能表现。

(8)你了解哪些Vue性能优化方法?

相对其他的“陷阱面试题”,这个问题就显得友善了很多,只要我们基础功底扎实,回答得井井有条并不是难事。

首先,我们要找到VUE性能的现存问题,大部分都是代码层面的,然后具体的提出代码层优化意见就可以了。

目前我们所知的VUE代码层优化大致为一下11点,村长已经都帮大家整理好了,请大家随意消化一下:

●路由懒加载

●keep-alive缓存页面
●使用v-show复用DOM
●v-for 遍历避免同时使用 v-if
●长列表性能优化
●事件的销毁
●图片懒加载
●第三方插件按需引入
●无状态的组件标记为函数式组件
●子组件分割
●变量本地化

●SSR

下面是针对这11个优化点给出的具体优化方案:

●路由懒加载☟

const router = new VueRouter({
  routes: [
    { path: '/foo', component: () => import('./Foo.vue') }
  ]
})

●keep-alive缓存页面☟

●使用v-show复用DOM☟

img

●v-for 遍历避免同时使用 v-if☟

img

●长列表性能优化:

如果列表是纯粹的数据展示,不会有任何改变,就不需要做响应化☟

img

如果是大数据长列表,可采用虚拟滚动,只渲染少部分区域的内容☟

img

参考:

vue-virtual-scroller☟

https://github.com/Akryum/vue-virtual-scroller
vue-virtual-scroll-list☟

https://github.com/tangbc/vue-virtual-scroll-list

●事件的销毁:

Vue 组件销毁时,会自动解绑它的全部指令及事件监听器,但是仅限于组件本身的事件。

created() {
  this.timer = setInterval(this.refresh, 2000)
},
beforeDestroy() {
  clearInterval(this.timer)
}

●图片懒加载:

对于图片过多的页面,为了加速页面加载速度。

所以很多时候我们需要将页面内未出现在可视区域内的图片先不做加载, 等到滚动到可视区域后再去加载。

参考项目:

vue-lazyload☟

https://github.com/hilongjw/vue-lazyload

●第三方插件按需引入:

像element-ui这样的第三方组件库可以按需引入,避免体积太大。

import Vue from 'vue';
import { Button, Select } from 'element-ui';

 Vue.use(Button)
 Vue.use(Select)

●无状态的组件标记为函数式组件☟

img

●子组件分割

img

●变量本地化

img

●服务端渲染 - SSR

(9)你对Vue3.0的新特性有没有了解?

young村长帮大家总结了Vue3.0改进方向,主要在以下几点:

●更快

○虚拟DOM重写

○优化slots的生成

○静态树提升

○静态属性提升

○基于Proxy的响应式系统

●更小:

○通过摇树优化核心库体积

●更容易维护:

○TypeScript + 模块化

●更加友好

○跨平台:编译器核心和运行时核心与平台无关,使得Vue更容易与任何平台(Web、Android、iOS)一起使用

●更容易使用

○改进的TypeScript支持,编辑器能提供强有力的类型检查和错误及警告

●更好的调试支持

●独立的响应化模块

●Composition API

虚拟 DOM 重写

期待更多的编译时提示来减少运行时开销,使用更有效的代码来创建虚拟节点。

组件快速路径+单个调用+子节点类型检测

▷跳过不必要的条件分支

▷JS引擎更容易优化

详情见下图☟

img

优化slots生成

vue3中可以单独重新渲染父级和子级:

▷确保实例正确的跟踪依赖关系

▷避免不必要的父子组件重新渲染

详情见下图☟

img

静态树提升(Static Tree Hoisting)

使用静态树提升,这意味着 Vue 3 的编译器将能够检测到什么是静态的,然后将其提升,从而降低了渲染成本。

▷跳过修补整棵树,从而降低渲染成本

▷即使多次出现也能正常工作

详情见下图☟

img

静态属性提升

使用静态属性提升,Vue 3打补丁时将跳过这些属性不会改变的节点。☟

img

基于 Proxy 的数据响应式

Vue 2的响应式系统使用:

Object.defineProperty 的getter 和 setter。

Vue 3 将使用 ES2015 Proxy 作为其观察机制,这将会带来如下变化:

●组件实例初始化的速度提高100%

●使用Proxy节省以前一半的内存开销,加快速度,但是存在低浏览器版本的不兼容

●为了继续支持 IE11,Vue 3 将发布一个支持旧观察者机制和新 Proxy 版本的构建

img

高可维护性

Vue 3 将带来更可维护的源代码。它不仅会使用 TypeScript,而且许多包被解耦,更加模块化。

created() {
  this.timer = setInterval(this.refresh, 2000)
},
beforeDestroy() {
  clearInterval(this.timer)
}

img


评论
  目录