前端常见面试题整合

浏览器、HTML、CSS

什么是BFC

https://blog.csdn.net/sinat_36422236/article/details/88763187

BFC(Block formatting context)直译为"块级格式化上下文"。它是一个独立的渲染区域,只有Block-level box参与, 它规定了内部的Block-level Box如何布局,并且与这个区域外部毫不相干。

BFC的布局规则

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

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

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

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

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

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

如何创建BFC

  1. float的值不是none。
  2. position的值不是static或者relative。
  3. display的值是inline-block、table-cell、flex、table-caption或者inline-flex
  4. overflow的值不是visible

BFC的作用

  1. 利用BFC避免margin重叠
  2. 自适应两栏布局
  3. 清除浮动(高度塌陷)

CSRF 和 XSS 攻击,预防

https://blog.csdn.net/m0_37631322/article/details/81346335

XSS

XSS,即 Cross Site Script,中译是跨站脚本攻击;其原本缩写是 CSS,但为了和层叠样式表(Cascading Style Sheet)有所区分,因而在安全领域叫做 XSS。

XSS 攻击是指攻击者在网站上注入恶意的客户端代码,通过恶意脚本对客户端网页进行篡改,从而在用户浏览网页时,对用户浏览器进行控制或者获取用户隐私数据的一种攻击方式。

攻击者对客户端网页注入的恶意脚本一般包括 JavaScript,有时也会包含 HTML 和 Flash。有很多种方式进行 XSS 攻击,但它们的共同点为:将一些隐私数据像 cookie、session 发送给攻击者,将受害者重定向到一个由攻击者控制的网站,在受害者的机器上进行一些恶意操作。

防范
  1. HttpOnly 防止劫取 Cookie
  2. 输入检查
  3. 输出检查

CSRF

CSRF,即 Cross Site Request Forgery,中译是跨站请求伪造,是一种劫持受信任用户向服务器发送非预期请求的攻击方式。

通常情况下,CSRF 攻击是攻击者借助受害者的 Cookie 骗取服务器的信任,可以在受害者毫不知情的情况下以受害者名义伪造请求发送给受攻击服务器,从而在并未授权的情况下执行在权限保护之下的操作。

防范
  1. 验证码
  2. Referer Check
  3. 添加 token 验证(token==令牌)

Flex 三个属性

flex: flex-grow flex-shrink flex-basis;

flex-grow 属性用于设置或检索弹性盒子的***放大比率***。属性值number 一个数字,规定项目将相对于其他灵活的项目进行扩展的量。默认值是 0。

flex-shrink 属性指定了 flex 元素的***缩小比例***。flex 元素仅在默认宽度之和大于容器的时候才会发生收缩,其收缩的大小是依据 flex-shrink 的值。默认为1

flex-basis 属性给上面两个属性分配多余空间之前, 计算项目是否有多余空间, 默认值为 auto, 即项目本身的大小。属性值number 一个长度单位或者一个百分比,规定灵活项目的初始长度。

清除浮动的方式有哪些?请说出各自的优点

高度塌陷:当所有的子元素浮动的时候,且父元素没有设置高度,这时候父元素就会产生高度塌陷。

清除浮动方式

  1. 给父元素单独定义高度

    优点:快速简单,代码少

    缺点:无法进行响应式布局

  2. 父级定义 overflow:hidden;zoom:1(针对 ie6 的 兼容)
    优点:简单快速、代码少,兼容性较高

    缺点:超出部分被隐藏,布局时要注意清除浮动方式

  3. 在浮动元素后面加一个空标签,clear:both;height: 0;overflow:hidden

    优点:简单快速、代码少,兼容性较高。

    缺点:增加空标签,不利于页面优化

  4. 父级定义 overflow:auto

    优点:简单,代码少,兼容性好

    缺点:内部宽高超过父级 div 时,会出现滚动条

  5. 万能清除法: 给塌陷的元素添加伪对象

    .father:after{ 
    		Content:“随便写”;
    		Clear:both;
    		display:block;
    		Height:0;
    		Overflow:hidden;
    		Visibility:hidden
    	}
    

    优点:写法固定,兼容性高
    缺点:代码多

水平居中方法

  1. 子父元素宽度固定,子元素设置 margin:auto,并且子元素不能设置 浮动,否则居中失效
  2. 子父元素宽度固定,子元素设置 margin:auto,并且子元素不能设置 浮动,否则居中失效
  3. 子元素相对于父元素绝对定位,子元素 top,left 设置 50%,子元素 margin-top 和 margin-left 减去各自宽高的一半
  4. 子元素相对于父元素绝对定位,子元素上下左右全为 0,然后设置子元素 margin:auto
  5. 父元素设置 display:table-cell vertical-align:middle,子元素设置 margin:auto
  6. 子元素相对定位,子元素 top,left 值为 50%,transform:translate (-50%,-50%)
  7. 子元素相对父元素绝对定位,子元素 top,left 值为 50%,transform: translate(-50%,-50%)
  8. 父元素设置弹性盒子, display:flex; justify-content:center ;align-item:center; justify-content:center

元素垂直居中

  1. 设置子元素和父元素的行高一样,再水平居中
  2. 子元素设置为行内块,再加 vertical-align:middle
  3. 已知父元素高度,子元素相对定位,通过 transform:translateY(-50%)
  4. 不知道父元素高度,子绝父相,子元素 top:50%,transform: translateY(-50%)
  5. 创建一个隐藏节点,让隐藏节点的 height 为剩余高度的一半
  6. 给父元素 display:table,子元素 display:table-cell,vertical-align: middle
  7. 弹性盒,父元素display: flex, 子元素: align-self: center

三栏布局方式两边固定中间自适应

  1. margin 负值法:左右两栏均左浮动,左右两栏采用负的 margin 值。 中间栏被宽度为 100%的浮动元素包起来
  2. 自身浮动法:左栏左浮动,右栏右浮动,中间栏放最后
  3. 绝对定位法:左右两栏采用绝对定位,分别固定于页面的左右两侧, 中间的主体栏用左右 margin 值撑开距离。
  4. flex 左右固定宽 中间 flex:1
  5. 网格布局
  6. table 布局

浏览器缓存机制

强缓存和协商缓存

https://www.cnblogs.com/chengxs/p/10396066.html

强缓存相关字段有 expires,cache-control。如果 cache-control 与 expires 同时存在的话, cache-control 的优先级高于 expires。 协 商 缓 存 相 关 字 段 有 Last-Modified/If-Modified-Since , Etag/If-None-Match

其中Etag / If-None-Match的优先级比Last-Modified / If-Modified-Since高。

  • Last-Modified

    是服务器响应请求时,返回该资源文件在服务器最后被修改的时间

  • If-Modified-Since

    则是客户端再次发起该请求时,携带上次请求返回的Last-Modified值,通过此字段值告诉服务器该资源上次请求返回的最后被修改时间。服务器收到该请求,发现请求头含有If-Modified-Since字段,则会根据If-Modified-Since的字段值与该资源在服务器的最后被修改时间做对比,若服务器的资源最后被修改时间大于If-Modified-Since的字段值,则重新返回资源,状态码为200;否则则返回304,代表资源无更新,可继续使用缓存文件

  • Etag

    是服务器响应请求时,返回当前资源文件的一个唯一标识(由服务器生成)

  • If-None-Match

    是客户端再次发起该请求时,携带上次请求返回的唯一标识Etag值,通过此字段值告诉服务器该资源上次请求返回的唯一标识值。服务器收到该请求后,发现该请求头中含有If-None-Match,则会根据If-None-Match的字段值与该资源在服务器的Etag值做对比,一致则返回304,代表资源无更新,继续使用缓存文件;不一致则重新返回资源文件,状态码为200

浏览器输入网址到页面渲染全过程

浏览器从输入URL到渲染完页面的整个过程_猫老板的豆-CSDN博客

输入网址到浏览器渲染页面的过程_哎呦喂1111的博客-CSDN博客

关于 JS 动画和 css3 动画的差异性

渲染线程分为 main threadcompositor thread,如果 css 动画 只 改 变 transform 和 opacity , 这 时 整 个 CSS 动 画 得 以 在 compositor trhead 完成(而 JS 动画则会在 main thread 执行, 然后出发 compositor thread 进行下一步操作),特别注意的是如果 改变 transform 和 opacity 是不会 layout 或者 paint 的。

区别:
功能涵盖面,JS 比 CSS 大
实现/重构难度不一,CSS3 比 JS 更加简单,性能跳优方向固定对帧速表现不好的低版本浏览器,css3 可以做到自然降级
css 动画有天然事件支持 css3 有兼容性问题

双边距重叠问题(外边距折叠)

多个相邻(兄弟或者父子关系)普通流的块元素垂直方向 marigin 会重叠

折叠的结果为:

  • 两个相邻的外边距都是正数时,折叠结果是它们两者之间较大的值。
  • 两个相邻的外边距都是负数时,折叠结果是两者绝对值的较大值。
  • 两个外边距一正一负时,折叠结果是两者的相加的和。

JavaScript

Js 基本数据类型有哪些

字符串 String数值 Number布尔 boolean
nullundefined对象、数组

ajax和axios、fetch的区别

https://www.jianshu.com/p/8bc48f8fde75

https://www.cnblogs.com/bala/p/11650296.html

传统 Ajax 指的是 XMLHttpRequest(XHR), 最早出现的发送后端请求技术,隶属于原始 js 中,核心使用 XMLHttpRequest 对象,多个请求之间如果有先后关系的话,就会出现回调地狱。

JQuery ajax 是对原生 XHR 的封装

axios 是一个基于 Promise ,本质上也是对原生 XHR 的封装,只不过 它是 Promise 的实现版本,符合最新的 ES 规范

fetch 不是 ajax 的进一步封装,而是原生 js,没有使用 XMLHttpRequest 对象

如何判断一个数据是 NaN

NaN 非数字 但是用 typeof 检测是 number 类型

  1. isNaN(n)
let a  = NaN 
console.log(isNaN(a))  // true
  1. Object.is(n)
let a  = NaN
console.log(Object.is(a,NaN)) // true
  1. 封装成方法:NaN连自己本身都不相等,所以可以利用这个特性来判断这个值是不是NaN
let isNaNMethod = v=>v!==v && true 
    console.log(isNaNMethod(NaN)); // true
    console.log(isNaNMethod('sdsd')); // false
    console.log(isNaNMethod(3)); // false
    console.log(isNaNMethod('3.233')); // false
    let bq = {name:'zs'}
    console.log(isNaNMethod(bq)); // false
  1. 判断数组中是否含有NaN
let arr = [1,2,3,NaN]
console.log(arr.includes(NaN))  // true

注意:不能用indexOf判断数组中是否含有NaN

Js 中 null 与 undefined 区别

相同点不同点
用 if 判断时,两者都会被转换成 falsenumber 转换的值不同 number(null)为 0 number(undefined) 为 NaN

Null 表示一个值被定义了,但是这个值是空值 Undefined 变量声明但未赋

闭包

闭包可以简单理解成:定义在一个函数内部的函数。其中一个内部函数 在包含它们的外部函数之外被调用时,就会形成闭包。

能够读取其他函数内部变量的函数,或者 子函数在外调用, 子函数所在的父函数的作用域不会被释放。

特点:

  1. 函数嵌套函数。

  2. 函数内部可以引用外部的参数和变量。

  3. 参数和变量不会被垃圾回收机制回收。

使用:

  1. 读取函数内部的变量;
  2. 这些变量的值始终保持在内存中,不会在外层函数调用后被自动清除。

优点:

  1. 变量长期驻扎在内存中;
  2. 避免全局变量的污染;
  3. 私有成员的存在 ;

缺点:会造成内存泄露

箭头函数

箭头函数是匿名函数,不能作为构造函数,不能使用 new

箭头函数不能绑定 arguments,要用 rest 参数解决

箭头函数没有原型属性

箭头函数的 this 永远指向其上下文的 this

箭头函数不会创建自己的this,所以它没有自己的this,它只会从自己的作用域链的上一层继承this

箭头函数中的this是在定义函数的时候绑定

var x = 11
var obj = {
    x: 22,
    say: () => {
       console.log(this.x) // 11
    }
}
obj.say()

箭头函数没有自己的arguments

	// 例子1
    let fun = (val) => {
        console.log(val) // 111
        console.log(arguments) // 报错
    }
    fun(111)
    // 例子2
    function outer(val1, val2) {
        let argOut = arguments
        console.log(arguments) // argument
        let fun = () => {
            let argIn = arguments
            console.log(argIn) // argument
            console.log(argOut === argIn)  // true
        }
        fun()
    }
    outer(111, 222)

箭头函数没有原型prototype

JS中常见的内存泄露

不再用到的内存,没有及时释放,就叫做内存泄漏(memory leak)。

  1. 意外的全局变量

    function foo(){ 
        bar=2 
        console.log('bar没有被声明!')
    }
    

    b 没被声明,会变成一个全局变量,在页面关闭之前不会被释放.使用严格模式可以避免.

  2. 被遗忘的计时器或回调函数

    如果没有清除定时器,那么 someResource 就不会被释放,如果刚好它又占用了较大内存,就会引发性能问题. 但是 setTimeout ,它计时结束后它的回调里面引用的对象占用的内存是可以被回收的. 当然有些场景 setTimeout 的计时可能很长, 这样的情况下也是需要纳入考虑的.

  3. 脱离 DOM 的引用
    很多时候,为了方便存取,经常会将 DOM 结点暂时存储到数据结构中.但是在不需要该DOM节点时,忘记解除对它的引用,则会造成内存泄露.

  4. 闭包

    相互循环引用.这是经常容易犯的错误,并且有时也不容易发现.

function foo() { 
    var a = {}; 
    function bar() { 
        console.log(a); 
    }; 
    a.fn = bar; 
    return bar; 
};

避免

避免策略:

  1. 减少不必要的全局变量,或者生命周期较长的对象,及时对无用的数据进行垃圾回收(即赋值为null);
  2. 注意程序逻辑,避免“死循环”之类的 ;
  3. 避免创建过多的对象 原则:不用了的东西要记得及时归还。
  4. 减少层级过多的引用

事件委托 事件冒泡

事件冒泡:JS中当出发某些具有冒泡性质的事件是,首先在触发元素寻找是否有相应的注册事件,如果没有再继续向上级父元素寻找是否有相应的注册事件作出相应,这就是事件冒泡。

事件委托:利用事件冒泡的特性,将本应该注册在子元素上的处理事件注册在父元素上,这样点击子元素时发现其本身没有相应事件就到父元素上寻找作出相应。这样做的优势有:1.减少DOM操作,提高性能。2.随时可以添加子元素,添加的子元素会自动有相应的处理事件。

Let 与 var 与 const 的区别

  • var 声明的变量会挂载在 window 上,而 let 和 const 声明的变量不会
var b = 123;
let c = 246;
const d = 512;
console.log(b, 'b'); // 123
console.log(window.b, 'window.b'); // 123
console.log(c, 'c'); //246
console.log(window.c, 'window.c'); // undefined
console.log(d, 'd'); // 512
console.log(window.d, 'window.d'); // undefined
  • Var 声明的变量存在变量提升,let 和 const 不存在变量提升
  console.log(foo1); // [Function: foo1]
  foo1(); // foo1
  console.log(foo2); // undefined
  foo2(); // TypeError: foo2 is not a function
  function foo1 () {
  	console.log("foo1");
  };
  var foo2 = function () {
      console.log("foo2");
  };
  • 同一作用域下 var 可以声明同名变量,let 和 const、不可以
var name1 = "hello";
console.log(name1,'name1');
var name1 = "hello2";
console.log(name1,'name1');
  • Let 和 const 声明会形成块级作用域 Let 暂存死区 Const 一旦声明必须赋值,不能用 null 占位,声明后不能再修改,如果 声明的是复合类型数据,可以修改属性

    暂时性死区:let 和 const 声明的变量不存在变量提升,其作用域都是块级作用域,凡是在声明变量之前使用变量就会报错,所以,在代码块内,使用let命令声明变量之前,该变量都是不可用的。这在语法上,称为“暂时性死区”(temporal dead zone,简称 TDZ)。

if (true) {
   // 死区开始
   name = 'lut'; //  ReferenceError
   console.log(name); //  ReferenceError
   // 开始声明变量,死区结束
   let name; 
   console.log(name); // undefined 
   name = 520;
   console.log(name); // 520
}

原型

最详尽的 JS 原型与原型链终极详解,没有「可能是」。(一)

每个对象都有 __proto__ 属性,但只有函数对象才有 prototype 属性

在默认情况下,所有的原型对象都会自动获得一个 constructor(构造函数)属性,这个属性(是一个指针)指向 prototype 属性所在的函数(Person)

person1.constructor == PersonPerson.prototype.constructor == Person

instanceof 原理其实就是在原型链上去找是否有匹配的原型

call()、apply()、bind()区别

通过 apply 和 call 改变函数的 this 指向,他们两个函数的第一个 参数都是一样的表示要改变指向的那个对象,第二个参数,apply 是 数组,而 call 则是 arg1,arg2…这种形式。通过 bind 改变 this 作 用域会返回一个新的函数,这个函数不会马上执行

手写bind函数

function test(a, b, c) {
	console.log()
	console.log('this', this)
    return '返回值'
}

// 普通执行
const result = test(1, 10, 100)

// 通过bind 函数改变this 指向
const boundTest = test.bind({name: 'kcyu'}, 7, 77, 777)
// 改变后执行
const boundResult = boundTest() // {name: 'kcyu'}

console.log('result', result)
console.log('boundResult', boundResult)

开始手写

前端面试之手写一个bind方法_明月如霜丶-CSDN博客_手写bind

Function.prototype.myBind = function () {
        const self = this
        const args = Array.prototype.slice.call(arguments)
        const thisValue = args.shift()
        
        return function() {
            return self.apply(thisValue,args)
        }
    }

浅拷贝和深拷贝

实现浅拷贝

  1. for···in只循环第一层
// 只复制第一层的浅拷贝
function simpleCopy(obj1) {
   var obj2 = Array.isArray(obj1) ? [] : {};
   for (let i in obj1) {
   obj2[i] = obj1[i];
  }
   return obj2;
}
var obj1 = {
   a: 1,
   b: 2,
   c: {
         d: 3
      }
}
var obj2 = simpleCopy(obj1);
obj2.a = 3;
obj2.c.d = 4;
alert(obj1.a); // 1
alert(obj2.a); // 3
alert(obj1.c.d); // 4
alert(obj2.c.d); // 4
  1. Object.assign方法
var obj = {
    a: 1,
    b: 2
}
var obj1 = Object.assign(obj);
obj1.a = 3;
console.log(obj.a) // 3
  1. 直接用=赋值

实现深拷贝

(5条消息) js对象深复制的方法总结(包装对象,Date对象,正则对象)_liwusen的博客-CSDN博客

  1. 采用递归去拷贝所有层级属性
function deepClone(obj){
    let objClone = Array.isArray(obj)?[]:{};
    if(obj && typeof obj==="object"){
        for(key in obj){
            if(obj.hasOwnProperty(key)){
                //判断ojb子元素是否为对象,如果是,递归复制
                if(obj[key]&&typeof obj[key] ==="object"){
                    objClone[key] = deepClone(obj[key]);
                }else{
                    //如果不是,简单复制
                    objClone[key] = obj[key];
                }
            }
        }
    }
    return objClone;
}    
let a=[1,2,3,4],
    b=deepClone(a);
a[0]=2;
console.log(a,b);
  1. 通过JSON对象来实现深拷贝(缺点:无法实现对对象中方法的深拷贝,会显示为undefined)
var array = [1,2,3,4];
var newArray = $.extend(true,[],array); // true为深拷贝,false为浅拷贝
  1. 如果对象的value是基本类型的话,也可以用Object.assign来实现深拷贝,但是要把它赋值给一个空对象
var obj = {
    a: 1,
    b: 2
}
var obj1 = Object.assign({}, obj); // obj赋值给一个空{}
obj1.a = 3;
console.log(obj.a)// 1

JS中的变量垃圾回收机制

JS垃圾回收机制 - sunhuahuaa - 博客园 (cnblogs.com)

变量的生命周期

当一个变量的生命周期结束之后它所指向的内存就应该被释放。JS有两种变量,全局变量和在函数中产生的局部变量。局部变量的生命周期在函数执行过后就结束了,此时便可将它引用的内存释放(即垃圾回收),但全局变量生命周期会持续到浏览器关闭页面。

1. 标记清除(mark and sweep)
2. 引用计数(reference counting)

JS 监听对象属性的改变

  1. ES5中可使用Object.defineProperty 来实现已有属性的监听

    缺点:如果 id 不在 user 对象中,则不能监听 id 的变化

    Object.defineProperty(user,'name',{ setfunction(key,value){}})
    
  2. 在 ES6 中可以通过 Proxy

var user = new Proxy({}{
	setfunction(target,key,value,receiver){}
})

函数防抖和节流

https://www.cnblogs.com/cc-freiheit/p/10827372.html

宏任务,微任务

https://www.jianshu.com/p/e9474952ffe4

前端相关

前端工程化的理解

https://www.jianshu.com/p/88ed70476adb

前因:

目前来说,web业务日益复杂化和多元化,前端开发从WebPage模式为主转变为WebApp模式为主了。

前端工程化就是为了让前端开发能够“自成体系”,个人认为主要应该从模块化组件化规范化自动化四个方面思考。

模块化

模块化: 简单来说,模块化就是将一个大文件拆分成相互依赖的小文件,再进行统一的拼装和加载。

JS模块化:

用++Webpack + Babel++将所有模块打包成一个文件同步加载,也可以搭乘多个chunk异步加载;

用++System+Babel++主要是分模块异步加载;

用浏览器的

css的模块化:

从工具层面,社区又创造出Shadow DOM、CSS in JS和CSS Modules三种解决方案。

资源的模块化:

Webpack的强大之处不仅仅在于它统一了JS的各种模块系统,取代了Browserify、RequireJS、SeaJS的工作。更重要的是它的万能模块加载理念,即所有的资源都可以且也应该模块化。

依赖关系单一化。所有CSS和图片等资源的依赖关系统一走JS路线,无需额外处理CSS预处理器的依赖关系,也不需处理代码迁移时的图片合并、字体图片等路径问题;

资源处理集成化。现在可以用loader对各种资源做各种事情,比如复杂的vue-loader等等;

项目结构清晰化。使用Webpack后,你的项目结构总可以表示成这样的函数: dest = webpack(src, config)。

组件化

从UI拆分下来的每个包含模板(HTML)+样式(CSS)+逻辑(JS)功能完备的结构单元,我们称之为组件

规范化

· 目录结构的制定

· 编码规范

· 接口规范

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值