12~18k的前端面试会问个啥?(答案版上)

基本功考察

一、关于html

  1. html语义化标签的理解seo优化

    语义化简单的说就是用正确的含义的标签做正确的事eg:头部:header 导航:nav等,语义化的优点是易于修改和维护,支持无障碍阅读,搜索引擎友好,方便seo,面向未来的 HTML,浏览器在未来可能提供更丰富的支持

  2. seo优化

    三剑客: <title> 标签、<meta name="description"> 标签和 <meta name="keywords"> 标签。顾名思义,它们分别代表当前页面的标题、内容摘要和关键词

    robots文件告知搜索引擎可以抓取的内容和相关页面

    sitemap文件辅助搜索引擎访问网站的工具(协议)

    百度自动推送代码

  let bp = document.createElement('script');
  const curProtocol = window.location.protocol.split(':')[0];
  if (curProtocol === 'https') {
    bp.src = `https://zz.bdstatic.com/linksubmit/push.js`;
  }else {
    bp.src = `http://push.zhanzhang.baidu.com/push.js`;
  }
  let s = document.getElementsByTagName('script')[0];
  s.parentNode.insertBefore(bp, s);
})();


复制代码
  1. h5新增属性和标签

    表单属性:autofocus--自动地获得焦点,multiple--可选择多个值,required--规定不能为空

    连接属性:size target 超链接

    defer:加载完脚本后并不执行,而是等整个页面加载完之后再执行

    扫描二维码关注公众号,回复: 13469741 查看本文章

    async:加载完脚本后立刻执行,不用等整个页面都加载完,属于异步执行。 多媒体标签 video audio source等多媒体标签,还有时间time等新标签

  2. h5新增的api

    localStorage:永久储存,多窗口共享,最大20mb

    sessionStorage: 生命周期为关闭浏览器窗口,关闭当前窗口数据存储失效;可以在同一窗口下访问,不可以多窗口共享,数据大小为5mb

    新增dom操作document.querySelector("选择器"); document.querySelectorAll('选择器');

    新增class操作可以删除替换class等操作

二、关于css

  1. css选择器

    • 标签选择器、伪元素选择器:1

    • 类选择器、伪类选择器、属性选择器:10

    • id 选择器:100

    • 内联样式:1000

    • !important声明的样式的优先级最高;

    • 如果优先级相同,则最后出现的样式生效;

    • 继承得到的样式的优先级最低;
    • 通用选择器(*)、子选择器(>)和相邻同胞选择器(+)并不在这四个等级中,所以它们的权值都为 0 ;
    • 样式表的来源不同时,优先级顺序为:内联样式 > 内部样式 > 外部样式 > 浏览器用户自定义样式 > 浏览器默认样式。

  2. BFC机制

    块格式上下文(BFC)是web页面的可视化css渲染的一部分,是布局过程中生成块级盒子的区域,也是浮动元素与其他元素的交互限定区域

    通俗来讲BFC是一个独立布局环境,可以理解为一个容器,在这个容器中按照一定规则进行物品摆放不会影响到其他环境中的物品。元素符合触发bfc的条件,则bfc中元素的布局不受外部影响

    创建BFC的条件
     -   根元素:body
     -   元素设置浮动:float除none以外的值
     -   元素设置绝对定位:position为 absolute,fixed
     -   displa值为:inline-block table-cell  table-caption flex
     -   overflow值为:hidden.auto scroll
     
    复制代码
    BFC的特点
         垂直方向上,自上而下排列,和文档流的排列方式一样
         在BFC中上下相邻的两个容器的margin会重叠
         计算BFC的高度时,需要计算浮动元素的高度
         BFC区域不会与浮动的容器发生重叠
         BFC是独立的容器,容器内部元素不受外部元素影响
         每个元素的左右margin值和容器的作border相接触
    复制代码
    BFC的作用
    解决margin的重叠问题:
        由于BFC是一个独立区域,内部的元素和外部元素互不影响,将两个元素变为BFC,就解决了margin塌陷问题
    解决高度塌陷问题:
        对子元素设置浮动以后,父元素会发生高度塌陷问题,也就是父元素高度会变成0,只需要在父元素设置overflow:hidden
    创建自适应两栏布局: 左侧设置为浮动,右侧设置为overflow:hidden,这样右侧就会触发BFC,实现自适应两栏布局
        left:{
            width:100px;
            hight:200px;
            float:left;
        }
        .right {
            hight:200px;
            overflow:hidden;
         }
       
       
    复制代码
  3. 盒模型

    css3有两种盒模型:标准盒子模型、IE盒子模型,通过box-sizeing属性来修改元素的盒模型,标准盒模型和IE盒模型的区别在于width和height时的范围不同,

    标准盒模型的width和height属性的范围只包含了content,通过设置box-sizeing: content-box

    IE盒模型的width和height属性的范围包含了border,padding和content,可以通过设置box-sizeing: border-box来实现

  4. css模块化开发

    css模块化是指的是吧页面分割成不同的组成部分,这些组成部分没有依赖关系,我们要达到的目的是,当我们去修改其中一部分css时,不会对其他部分产生意料之外的影响。

    所有的预处理器(比如Sass或者LESS)都提供了把分散的CSS文件合并成一个文件的功能。预处理器会从base.scss中引入基础样式,并从每个模块文件引入相应的模块样式,然后输出一个包含所有样式的样式表文件。这样每个模块都单独拥有一个便于维护的文件。 css预处理起,一般来说他们是基于css扩展了一套属于自己的dsl,来解决我们书写css时难以解决的问题:

    • 语法不够强大,无法嵌套书写导致模块化开发中需要书写很多重复的选择器
    • 没有变量和合理样式复用机制,是得逻辑上相关的属性值必须以字面量的形式重复输出,导致难以维护。

    所以预处理器的目标就是:提供css缺失的样式层复用机制,减少冗余代码,提高样式代码的可维护性。

  5. 屏幕适配 以及 页面自适应

    链接

  6. css3中新增的选择器

    伪类选择器 伪元素选择器 属性选择器

  7. css3中新增加的属性

    transform属性应用于元素的2d到3d的转换,这个属性允许你将元素,旋转,缩放,倾斜等

    transition属性可以设置元素的过渡效果,四个属性transition-property:指定CSS属性的name,transition效果, transition-duration: 指定效果需要多少秒或者毫秒才能完成,transition-timing-function:指定transition效果的转速曲线 transition-delay:指定transition效果开始的时候

    animation动画属性 通过@keyframes xxx来定义一个动画 然后在需要添加动画的盒子里面使用animation:xxx 2s; 2s是指的动画执行的时间长度

关于布局

  1. 标准文档流(padding+margin+负margin)+浮动float+定位

    定义:标准文档流就是元素排版过程中,元素会默认的自动从左往右,从上往下的 流式排列方式。前面内容发生了变化,后面的内容位置也会随着发生变化。

  2. 百分比布局(流式布局): px单位 用 %代替, 占父级元素的百分比

    定义:流式布局,就是百分比布局,也称非固定像素布局,通过盒子的宽度设置成百分比来根据屏幕的宽度来进行伸缩,不受固定像素的限制,内容向两侧填充。不过需要注意的是需要定义页面的最大和最小支持宽度。

  3. flex弹性布局: 主轴 辅助轴的几个属性

    定义:Flex是Flexible Box的缩写,意为”弹性布局”,用来为盒状模型提供最大的灵活性。任何一个容器都可以使用flex布局

    采用flex布局的元素,称为flex容器(flex container),简称”容器”。它的所有子元素自动成为容器成员,称为flex项目,简称项目

    采用Flex布局的元素,称为Flex容器(flex container),简称”容器”。它的所有子元素自动成为容器成员,称为Flex项目(flex item),简称”项目“。

    容器默认存在两根轴:水平主轴和垂直交叉轴,主轴的开始位置(与边框的交叉点)叫做main start,结束位置叫main end 交叉轴的开始位置叫做cross start 结束叫做cross end。

    它有六种属性可以设置在容器上,他们分别是:

    -   flex-direction: 绝对主轴的方向 默认水平方向,从左侧开始
    -   flex-wrap:决定容器内是否换行,默认不换行
    -   flex-flow:是flex-direction和flex-wrap的缩写
    -   justify-content:定义了主轴的对齐方式
    -   align-items:定义了在交叉轴上的方式
    -   align-content:定义了多跟轴线的对齐方式
    复制代码

    他们的参数都有下面这些

    flex-direction: row | row-reverse | column | column-reverse;
    flex-wrap: nowrap | wrap | wrap-reverse;
    flex-flow: <flex-direction> <flex-wrap>;
    justify-content: flex-start | flex-end | center | space-between | space-around;
    align-items: flex-start | flex-end | center | baseline | stretch;
    align-content: flex-start | flex-end | center | space-between | space-around | stretch;
    复制代码
  4. grid栅格布局: 使用框架中的类名来替代: 本质上还是百分比布局

    定义:gird布局即网格布局,一种新的css布局模型,擅长讲一个页面划分为几个主要的区域,以及定义这些区域的大小位置,层次等关系,是css唯一的二维布局。

    使用: 我们通过在元素上声明display:grid或者display:inline-grid来创建一个网格容器,这个元素所有的直系子元素将会成为网格项目。网格轨道:grid-template-columns 和 grid-template-rows 属性来定义网格中的行和列。grid-row-gap 属性、grid-column-gap 属性分别设置行间距和列间距。grid-gap 属性是两者的简写形式。grid-auto-flow 属性控制着自动布局算法怎么样运行,精确指定在网格中被自动布局的元素怎么样排列,默认的防止顺序是先行后列。justify-items属性设置单元格的内容的水平位置,align-items设置单元格的垂直位置。

    应用:可以使用gird布局实现响应式布局。

关于js基础

  1. 变量数据类型及检测:基本+引用 JavaScript共有八种数据类型,分别是Undefine,null,boolean,number,string,object,bigint,symbol。

    其中bigint和symbol是es6新增的数据类型:

    • Symbol代表创建后独一无二且不可变的数据类型,他主要是为了解决可能出现的全局变量冲突的问题。
    • Bigint是一个数字类型的数据,他可以表示任意精度格式的整数,使用Bigint可以安全的存储和使用大整数。

这些数据可以分为原始数据类型和引用数据类型:可以根据存储的位置不同分为:

  • 栈:原始数据类型(undefined、 null、 Boolean、 number、 string)
  • 堆: 引用数据类型(对象 数组和函数)

这两种数据的区别主要在于存储的位置不同:

  • 原始数据类型直接存储在栈中简单的数据段,占据空间小,大小固定,属于被频繁使用的数据
  • 引用数据存在在堆(heap)中的对象,占据空间大,大小不固定。如果存在栈中,将会影响程序的运行性能;引用数据在栈中存储了指针,该指针会指向堆中改实体的起始地址。当解释器寻找引用值时,会首先检索其中在栈的地址,然后从地址中获取堆中的实体。
  • 检测方式:

1)typeof

console.log(typeof true); // boolean 
console.log(typeof 'str'); // string 
console.log(typeof []); // object 
console.log(typeof function(){}); // function 
console.log(typeof {}); // object 
console.log(typeof undefined); // undefined 
console.log(typeof null); // object
复制代码

其中对数组对象还有null都会判断为object 2)instanceof

  • instanceof额可以正确判断对象的类型,起内部运行机制是判断在其原型链中是否能找到该类型的原型。instanceof只能正确判断引用数据类型,而不能判断基本数据类型。instanceof运算符可以用来测试一个对象在其原型链上是否存在一个构造函数的prototype属性。instanceof的基本逻辑如下
        let proto = Object.getPrototypeOf(left)
        let prototype = right.prototype;
        while(true) {
            if(!proto) return false
            if(proto === prototype) return true
            proto = Object.getPrototypeOf(proto)
        }
}
复制代码
  1. constructor

    constructor有两个作用,一个是判断数据的类型,二是对象实例通过constructor对象访问他们的构造函数。但是创建一个对象然后去改变他的原型,constructor就不能用来判断数据类型了

4) Object.prototype.toString.call()

  • Object.prototype.toString.call()使用Object对象的原型方法toString来判断数据类型,但是同样是检测对象obj调用toString方法,obj.toString的结果和Object.prototype.toString.call的结果是不一样的。这是因为toString是Object的原型方法,Array,function等类型作为Object的实例,都重写了toString方法,不同对象类型的toString方法,根据原型链的知识,调用的是重写之后的方法,而不是调用object上的toString,所以obj.toString是不能的带其对象类型的。
  1. 运算符: 算术 + 条件 + 逻辑 + 位 + 短路, 隐式转换等

    这个具体的可以参考菜鸟教程啥的,写几个比较常考的例子。

    1. 0.1 + 0.2 !== 0.3: 计算机是通过二进制的方式存储数据的,所以计算机计算0.1+0.2的时候是计算的这两个数的二进制的和。0.1的二进制: 0.00011001100…… (1100)循环,0.2的是0.0011001100……(1100)的循环,这两个的二进制是都是无限循环的数,JavaScript中Number准守IEEE754标准, 使用64位规定长度来表示,也就double双精度浮点数,双精度浮点数的小数部分保留52位,剩余的要舍去,遵从:“0舍1入”的原则,根据这个原则,0.1+0.2的二进制和转化为十进制是0.3000000000004

    2)+操作符什么时候用于拼接字符串

       如果+的其中一个操作数是字符串,则执行字符串拼接,否则执行数字加法
    复制代码

    3) || 和 && 操作符返回值

       对于|| 来说如果条件判断为true返回第一个操作数的值,否则返回第二个值
       对于&& 来说 如果条件判断为true返回第二个操作数的值,否则返回第一值
    复制代码
  2. 函数定义, 调用方式(apply, call, 直接调用)

    1)函数的定义

        声明式函数定义`function fn(a, b) {}`
        赋值式函数定义`var fn=function(a, b){}`
        箭头函数 `var func = (params) => params + 2`
    复制代码

    2)调用方式:

        直接调用(直接调用函数名)和依靠行为调用(绑定到事件)
        call和apply在特定作用域内调用函数,来改变this的指向,他们两个的作用差不多,但是在调用中存在差异
    复制代码
    • apply接受两个参数,第一个参数指定了this对象的指向,第二个参数为带下标的集合,这个集合可以是数组或者是类数组,apply会把这个集合的元素作为参数传递给被调用的函数

    • call的参数不固定,第一个参数跟apply一样,代表函数体内的this对象的指向,第二个以后的参数会依次传递给函数

  3. 作用域, 作用域链

    作用域分为全局作用域,块级作用域和函数作用域

    全局作用域:

     最外层函数和最外层函数外面定义的变量拥有全局作用域
     所有未定义直接复制的变量自动声明为全局作用域
     所有window对象的属性都有全局作用域
     全局作用域有很大的弊端,过多的全局作用域会污染全局命名空间
     
    复制代码

    函数作用域:

     函数作用域声明在函数内部的变量,一般只有固定代码片段可以访问
     作用域是分层的,内层组用于可访问外层,反之不行
    复制代码

    块级作用域

     let和const可以声明会计作用域,由{}包裹或者在函数中创建
     let和const声明的变量不存在变量提升,不可以重复声明
     常用语循环中
    复制代码

    作用域链:

      定义:
          在自己的作用域内没有找到该变量,就去父级作用域查找,依次向上查找直到window对象被终止
      作用域链的作用:
          是保证执行环境有权访问所有变量和函数的有序访问,通过作用域链,可以访问到外层函数和变量、
      实质:
          是一个指向变量对象的指针列表,变量对象是一个包含了执行环境中所以变量和函数的对象。作用域链的前端是当前执行的上下文的变量对象。
    复制代码
  4. 闭包

    定义: 指的是有权访问另一个函数作用域中变量的函数,常见的创建闭包的方式是,在函数内创建一个新函数,新函数可以访问到函数的局部变量

    闭包有两个常用的用途:

    一个是让我们在函数外包能够访问到函数内部的变量。通过闭包,可以通过在外边调用闭包函数,从而在外部访问到函数内部的变量,通过这个方法来创建私有变量
    另外一个是在已经运行结束的函数上下文中的变量对象继续留在内存中,因为闭包函数保留了这个变量对象的引用,所以这个变量对象不会被回收
    复制代码

经典面试题:循环中使用闭包解决 var 定义函数的问题,这个运行的结果会输出一堆 6 因为 setTimeout 是个异步函数,所以会先把循环全部执行完毕,这时候 i 就是 6 了

for (var i = 1; i <= 5; i++) {
    setTimeout(function timer() { 
        console.log(i) 
    }, i * 1000) 
}
复制代码

这时候我们一般会使用,来解决这个问题

for (let i = 1; i <= 5; i++) {
    setTimeout(function timer() {
        console.log(i) 
      }, i * 1000) 
 }
复制代码
  1. 原型, 原型链, 继承

    JavaScript中是使用构造函数来创建一个新对象的,每个构造函数都具有prototype这个属性,这个属性值是一个对象,他包含了由该构造函数所有实例共享的属性和方法。使用构造函数创建一个新对象的时候,这个对象里面有一个指针,这个指针将指向构造函数的prototype属性对应的值,构造函数的prototype属性对应的值,会通过__proto_这个属性指向构造函数。

    当访问一个对象的属性时,如果这个对象内部不存在这个属性,呢么它将会去他的原型对象里面去寻找这个属性,这个对象又会有自己的原型,会一直找下去,直到object.prototype,object.prototype将会指向null,一般来说原型链的尽头是null。

    JavaScript对象是通过引用来传递的,创建的每个新对象实体中并没有一份属于自己的副本,所以修改原型师,与之相关的对象也会继承这个一改变。

  2. 函数上下文, this指向

    1)执行上下文类型 分为全局执行上下文 函数执行上下文 eval函数执行上下文

     全局执行上下文是任何不在函数内部的都说全局执行上下文,他首先会创建一个全局的window对象,并且设置this的值等于这个全局对象,一个程序中只有一个全局执行上下文
     
     函数执行上下文 当一个函数被调用时,就会为该函数创建一个新的执行上下文,函数的上下文可以有任意多个
     
     eval函数中的代码有属于他们的执行上下文
    复制代码

    JavaScript引擎用执行上下文栈来管理执行山下文,当JavaScript执行代码是,先遇到全局代码,这时候会先创建一个全局上下文并且压入栈,每当遇到函数调用,就会为函数创建一个新的执行上下文并压入栈顶,引擎会执行位于栈顶的函数,执行完毕在弹出,继续执行其它上下文,直到所有的代码执行完毕,从栈中弹出全局执行上下文

    创建执行山下文有两个阶段,一个是创建阶段一个是执行阶段:

    创建阶段:
        1)this绑定 在全局执行上下文中,this指向window 在函数执行上下文中,this指向取决于函数如何调用。如果被引用对象调用,this将指向呢个对象,否则this的值被设置为全局对象或者undefined
        2)创建词法环境组件 词法环境是一种有标识符--变量映射的数据结构,标识符是指变量/函数名,变量是对实际对象或者原始数据的引用。
        3)创建变量环境组件  环境变量也是一个词法环境,其环境记录器持有变量声明语句在执行上下文中创建的绑定关系
    执行阶段:
        此阶段会完成对变量的分配,然后执行玩代码
        
        
    复制代码

    简单来说执行上下文就是在执行js代码之前,需要先解析代码。解析的时候先创建一个全局的执行上下文环境,先把代码中即将执行的变量函数声明都拿出来,先赋值为undefined 函数先声明好可使用。然后在执行正式程序。在函数执行之前,也会有执行上下文,但是比全局上下文多了this和argument,以及函数参数

    this是执行上下文的一个属性,他指向最后一次调用他的对象。一般有四种调用模式

     1)函数调用模式,一个函数不是对象的属性时,直接作为函数来调用时,this指向全局对象
     2)方法调用 一个函数作为一个方法的属性时,this指向这个对象
     3)构造器调用  一个函数用new方法是,产生的新对象,this指向这个新对象
     4) apply,call, bind 这三个会指定this的指向,不同的是调用方式和接受参数的不同。
     
        
    复制代码

    这四种方式构造器new这种模式优先级最高

  3. js的运行机制, 事件队列和循环

    js是单线程的,基于事件循环,非阻塞IO的,适合处理i/o应用。

    js是单线程,所以代码会自上而下执行,所以代码被放到执行栈中执行,遇到异步函数将回调函数扔到任务队列里面, 当执行栈的代码都执行完毕,去循环任务队列里面的函数,将任务队列的函数扔到执行栈,如此循环往复称之为事件循环。

    其中微任务和宏任务组成了任务队列,其中:

    宏任务的队列是tasks,他的异步任务包括setTimeout setInterval I/O UI rendering 还有serImmediate 和requestAnimationFrame

    微任务是jobs 他包含的异步任务有process.nextTick promise object.observe mutationObserve

    一个完整的事件循环是这样的:

     1)执行全局script同步代码,这些同步代码有些是同步语句,也有些是异步语句
     2)全局script代码执行完毕后,执行栈stack会清空
     3)从微队列中取出位于队首的认为我放入执行栈,,执行完后微队列长度减1
     4)继续循环取出位于微队列队首的热吻放入执行栈,如此循环,直到微队列执行完毕,如果微队列中产生了新的微任务,还是会加入到微队列,也会在这个周期被调用
     5)微队列中所有的任务都完成以后,此时微队列为空,执行栈也空了
     6)开始去取宏队列中的宏任务,放入执行栈,执行完毕后,执行栈也空了
     7)循环的去执行从微队列和宏队列取任务
    复制代码

    这是浏览器中的任务队列和事件循环的情况,在node中的任务队列和事件循环跟浏览器有些许差距

    node中的事件循环分为6个阶段:

     1)timer阶段,这个阶段执行setTimeout和setInterval预定的callback
     2)I/O callback阶段,执行除了close事件的callbacks、被timer设定的callback、setTimeout和setInterval预定的callback之外的callback,
     3)prepare阶段:仅node里面使用
     4)poll阶段:获取新的I/O事件,适当时机node将阻塞在这里
     5)check阶段,执行serImmediate设定的callback
     6)close callback阶段: 执行close.on('close', ..)
    复制代码

node中的宏队列有 Timer queue,IO Callback Queue, Check Queue, Close Callbacks Queue,在浏览器中所有的宏任务都会加载到一个宏队列中,在node下不同的宏任务有不同的队列

node中的微任务有Next Tick Queue,他是放置在process.nextTick(callback)的回调函数,Other Micro Queue:放置其他的微任务,比如promise

node中的事件循环;

1)执行全局同步代码
2)执行微任务,先执行Next Tick Queue,在执行Other Micro Queue
3)开始执行宏任务。
复制代码

猜你喜欢

转载自juejin.im/post/6986645219290644517