前端中高级基础知识面试汇总

Posted Vicky沛沛

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了前端中高级基础知识面试汇总相关的知识,希望对你有一定的参考价值。

持续更新ing~

⭐️就是最好的鼓励哦wink~💗

文章目录

4.27

html5

  • 标签语义化

    • 合适的标签做合适的事情
    • 标签分类:
      • 块状标签
        • 独占一行
        • example:div,h1-h6,hr,table,form,p,li,dl,dt
      • 行内标签
        • example:span、a、img
      • 行内块状标签
        • example:input
  • 音视频

    • 改变了传统的flash播放,采用video和audio等
  • webGL/canvas等动画渲染

  • websocket:

    • 改变了传统的长轮询方式

css3

  • 盒子模型

    • 标准盒模型
      • width和height只是指内容content部分,不包括padding、border、margin部分
    • IE盒模型(怪异盒模型)
      • width和height包括margin、border、padding的盒子
    • 通常我们使用的都是标准盒模型,但是我们有些情况下需要使用IE盒模型的话可以设置box-sizing:border-box
  • 水平居中的实现方式

    • 使用定位
    .container
      position:relative;
    
    .box
    	width:200px;
    	height:200px;
      position:absolute;
      left:50%;
      top:50%;
      margin-left:-100px;
      margin-right:-100px;
    
    //或者
    .box
      position:absolute;
      left:50%;
      top:50%;
      transformX:-50%;
      transformY:-50%;
    
    
    • 使用flex
    .container
      display:flex;
      justify-content:center;
      align-item:center;
    
    
    • 使用table
    .container
      display:table-ceil;
      text-align:center;
      vertical-align:middle;
      width:500px;
      height:500px;
    
    .box
      display:inline-block;
    
    
    • 使用JS控制
  • 响应式布局

    • 圣杯布局
      • 利用position定位以及浮动还有负margin进行实现
    • 双飞翼布局
    • flex实现圣杯布局
.container
  display:flex;
  flex-direction:row;
  justify-content:space-between;

.left
	height:200px;
  flex:0 0 200px;	//缩放比0 0,宽度200px

.center
  flex:1;		//或者使用flex-grow

.right
	height:200px;
  flex:0 0 200px;

布局方案

  • media媒体查询
    • 适用于一套代码多端适配
  • rem适用于移动端
  • vm/vh百分比布局
  • flex

z-index原理

  • 使元素脱离文档流
  • 使元素脱离文档流的其他的方式:
    • 浮动
    • 定位
    • transform
    • Css3动画

不考虑其他因素下面哪种渲染性能比较高

//方式一
.box a
  

//方式二
a
  

方式二:因为浏览器的渲染机制使从右到左进行查找的

js的数据类型

  • 基本类型:
    • number
    • string
    • boolean
    • null
    • undefined
  • 引用类型
    • object
    • function
  • 特殊类型
    • Symbol

判断数据类型的几种方式

  • typeof
  • instanceof
  • constructor
  • Object.prototype.toString.call

4.28

堆栈内存、闭包作用域

let a = ,b = '0',c = 0;
a[b] = '张三'
a[c] = '李四'

console.log(a[b])		//李四

对象中,数字属性名和字符串属性名都是一样的,数组是特殊的字符串

拓展:对象和数组的区别

let a=, b=Symbol('1'), c=Symbol('1');  
a[b]='张三';	
a[c]='李四';  
console.log(a[b]);	//张三

Symbol创建的是唯一的值,不相等。对象的属性名不一定是字符串,如果是数字和字符串则是同一个值,因为索引是字符串。对象的属性名可以是不二null,Symbol、undefined等等。引用类型值都是变成字符串逆行存储。

拓展:自己实现一个Symbol

let a=, b=n:'1', c=m:'2';  
a[b]='张三';
a[c]='李四';  
console.log(a[b]);	//李四

b、c作为引用的时候会被转化成为字符串,对象转化toString那么即[Object Object],两个都是[Object Object],所以结果是李四

拓展:Object.prototype.toString项目中应用,跟valueOf跟toString区别(编译顺序)

基本类型直接存储,引用类型要放进堆里面,最终是把地址复制给这个值。

浏览一加载页面,就形成一个栈内存。每个函数执行,叫做把一个执行上下文压缩到栈中执行。

null和undefined

//立即执行函数,执行完被销毁,回收机制。但是由于i被占用因此不销毁。test表示的不是一个函数,而是一个函数返回的执行结果
var test = (function(i)
    return function()
        alert(i*=2);	//没有i,那么在它上级作用域中找。在哪创建的上级作用域就是谁
    
)(2);
test(5);		//字符串4。test中没有形参。

alert输出的结果都是会转化成字符串的。

var a=0,
    b=0;
function A(a)
    A=function(b)
        alert(a+b++);
    ;
    alert(a++);

A(1);		//"1"
A(2);		//"4"

注意: a++先跟别人运算,再自身累加1;++a先自身累加1,再跟别人运算。

过程解释:

1、GO全局:初始化 a = 0,b = 0, A一个方法,引用地址,此处暂时记为AAAFFF000

2、A(1)执行,传入形参,此时在执行中a= 1,往下中性,A = function…,此处相当于重新定义了全局的方法A,改变了原来的方法A的指向,此处引用地址从AAAFFF000改变到另外一个记为BBBFFF000,继续执行alert(a++),由于a=1,并且由于下面demo可以看出,a是在执行之后再自身加1的,那么此时alert的是没有叠加之前的1

3、继续执行A(2),那么此时A指向的function是改变之后的BBBFFF000,此时传入的形参b=2,而a在其上一级作用域中,由步骤2可知,叠加之后为2,那么此时alert出来的应该是2+2,为字符串4(alert出来的会自动同toString转化)

let a = 1;
console.log(5+a++);	//6
console.log(a)	//2

let b = 1;
console.log(5+(++b));	//7
console.log(b)		//2

闭包的作用:保存、保护

对象和数组的深浅拷贝

let obj = 
    a: 100,
    b: [10, 20, 30],
    c: 
        x: 10
    ,
    d: /^\\d+$/
;

let arr = [10, [100, 200], 
    x: 10,
    y: 20
];

//=>深克隆
function deepClone(obj) 
    if (typeof obj !== "object") return obj;
    if (obj instanceof RegExp) return new RegExp(obj);
    if (obj instanceof Date) return new Date(obj);
    let cloneObj = new obj.constructor;
    for (let key in obj) 
        if (obj.hasOwnProperty(key)) 
            cloneObj[key] = deepClone(obj[key]);
        
    
    return cloneObj;

  • 浅拷贝:只拷贝第一层,操作第二级仍然可以改第一级。只是浅拷贝,只拷贝引用
let obj = 
    a: 100,
    b: [10, 20, 30],
    c: 
        x: 10
    ,
    d: /^\\d+$/
;

let obj2 = 
for(let key in obj)
//obj.hasOwnProperty(key),true是私有的,false不是私有的。不是私有的不遍历,只遍历私有的
  if(!obj.hasOwnProperty(key))break;	
  obj2[key] = obj[key]



//ES6实现浅克隆
let obj3 = ...obj
  • 深拷贝:(递归/字符串转化)
// JSON.stringify&JSON.parse 
let obj = 
    a: 100,
    b: [10, 20, 30],
    c: 
        x: 10
    ,
    d: /^\\d+$/
;
let obj2 = JSON.stringify(obj);		//""a":100,"b":[10,20,30],"c":"x":10,"d":"
obj2 = JSON.parse(obj2)			

JSON.parse这种方式弊端:正则、函数、日期、symbol等,会有问题

//递归实现深克隆
function deepClone(obj)
//或者let newobj = new obj.constructor;或者;一般obj.constructor为Object,防止传入的是实例
//不直接创建控对象的目的,克隆的结果和之前保持相同的所属类
//过滤特殊情况,object才递归
	if(typeof obj === null)return null;
	if(typeof obj !== "object")return obj;
	if(obj instanceOf RegExp)
  	return new RegExp(obj)
	
	if(obj instanceOf Date)
  	return new Date(obj)
	
  let newobj = new Object();		
  for(let key in obj)
    if(obj.hasOwnProperty(key))		//判断是私有属性
      newobj[key] = deepclone(obj[key ])
    
  
  return newobj;

排除:null,Date,正则RegExp,以及不是object

面向对象

function Foo() 
    getName = function () 
        console.log(1);
    ;
    return this;

Foo.getName = function () 
    console.log(2);
;
Foo.prototype.getName = function () 
    console.log(3);
;
var getName = function () 
    console.log(4);
;
function  getName() 
    console.log(5);


Foo.getName();		//2
getName();		//4
Foo().getName();		//Foo()普通函数执行;Foo执行过程中,内部函数有个getName赋值,但是getName并不是私有的,于是此时重新定义全局的getName = -> 1,并且返回this,这里的this的指向就是window,那么应该是window.getName  1
getName();		//1
new Foo.getName();	//无参数new,点的方式叫做成员访问。优先级问题,先执行成员访问,new一个输出2的函数,那么输出也是2
new Foo().getName();	//有参数new,执行方式先new Foo,再getName。创建实例,实例的getName,那么应该找prototype上的,因此结果是3
new new Foo().getName();	//优先级new (new Foo()).getName().getName,先new Foo()创建一个实例foo,变成 new foo.getName(),此时变成了先成员访问,原型上的方法,输出3的方法,变成了new 3,即3

注意:由参数的new先执行new,无参数的new和成员访问两个同级别,谁先救先执行谁

答案为:2 4 1 1 2 3 3


//function声明加赋值,var先声明先不赋值
Foo AAAFFF0000
getName = func -> 5

//代码执行

Foo是一个堆,里面存了方法代码字符串,Foo仍然是一个对象,有prototype(也是一个引用类型即也是一个堆)、length、然后我们给他加了一个getName属性;

getName = func -> 4	//之前赋值输出5,之后重新赋值输出4的

变量提升:在var function,所有代码执行之前,带var和function提前定义和赋值

同步异步EventLoop

async function async1() 
    console.log('async1 start');
    await async2();
    console.log('async1 end');

async function async2() 
    console.log('async2');

console.log('script start');
setTimeout(function() 
    console.log('setTimeout');
, 0)
async1();
new Promise(function(resolve) 
    console.log('promise1');
    resolve();
).then(function() 
    console.log('promise2');
);
console.log('script end');


script start
async1 start
async2
promise1
script end
async1 end
promise2
setTimeout

浏览器多线程,js单线程。时间队列EventQueue。微任务队列,宏任务队列。主线程代码先执行。

定时器、事件绑定、ajax都是宏任务,async、await、promise等是微任务

4.29

  • 题一:
function A()
    alert(1);

function Func() 
    A=function()
       alert(2);
    ;
    return this;

Func.A=A;
Func.prototype=
    A:()=>
       alert(3);
    
;
A();
Fn.A();
Fn().A();
new Fn.A();
new Fn().A();
new new Fn().A();

//注意最后一个,箭头函数是不可以被new的,因为箭头函数没有原型链,也就没有constructor构造器
  • 题三:
var a = ?;
if (a == 1 && a == 2 && a == 3) 
    console.log(1);
 

两个等于号转化数据类型值相等,三个等于好要绝对相等

双等

  • 对象==字符串 对象toString变成字符串,再变成数字,对比;[10] == 10
  • null == undefined但是和其他比较不想等
  • NaN和任何东西都不想等
  • 剩下的都转化成数字。eg. '1'==true

1、利用toString

由于两个等号对比,一方为数字,我们假设a为object(例如:[1],[2],[3]这样的,数组是特殊的object),那么他们执行的对比方式一定是要先toString再转化成数字进行对比的。因此我们可以在toString上做文章,去修改它的toString

var a = 
  i:0,
  toString()
    return ++this.i;
  

//因此三次对比,执行三次toString,依次返回1,2,3。valueOf也可以代替toString



var a= [1,2,3]
a.toString = a.shift;	//shift方法删除数组第一个值,并且返回第一个数值。因此每次对比要调用a的toString的时候,依次获得的数值就是i,2,3

2、利用数据劫持get:

由于a是全局的,那么再全局上去劫持获取a的set方法去修改

var i = 0;
Object.definedProperty(window,'a',
  set()
    return ++i;
  
)

3、或者用true也行

Vue&React

  • react和vue区别

    • vue代表MVVM(双向数据绑定)。
    • 数据更改视图变化,视图更改数据变化
    • React代表MVC。
    • vue吧给我们把表单绑定事件写好了,React需要自己去绑定
      • React中需要自己去实现onchange事件
      • vue中直接v-mode直接帮我们绑定了数据,不用自己写onChange事件
    • MVC和MVVM区别
      • MVC默认值实现数据的更改(单向数据改变)
      • MVVM实现数据更改视图更改,视图更改数据更改(双向数据改变)
      • MVC这种只是缺少一个onChange事件绑定
  • vue中数据的双向绑定2.0和3.0的实现

    • vue2.0中,通过Object.definedProperty进行set和get修改;
    • vue3.0中通过Proxy进行拦截set和get方法进行相关操作,实现数据的双向绑定。

跨域问题的解决方案和实现原理

1、JSONP

利用script标签

  • 只有get请求
    • 不安全
    • 有缓存
    • 传递的数据大小有限制
    • 需要服务器单独的支持
  • 客户端
<script src="https://cdn.bootcss.com/jquery/3.4.1/jquery.min.js"></script>
<script>
    $.ajax(
        url: 'http://127.0.0.1:8001/list',
        method: 'get',
        dataType: 'jsonp',
        success: res => 
            console.log(res);
        
    );
</script>
  • 后台
let express = require('express'),
    app = express();
app.listen(8001, _ => 
    console.log('OK!');
);
app.get('/list', (req, res) => 
    let 
        callback = Function.prototype
     = req.query;
    let data = 
        code: 0,
        message: '测试数据'
    ;
    res.send(`$callback($JSON.stringify(data))`);
);

2、基于iframe的跨域解决方案

主域相同,子域不一样

  • window.name
  • document.domin
  • location.hash
  • post message

3、CORS跨域资源共享

客户端

import axios from 'axios';
以上是关于前端中高级基础知识面试汇总的主要内容,如果未能解决你的问题,请参考以下文章

高级前端面试题大汇总(只有试题,没有答案)

2020北京-腾讯视频-高级前端开发面试题目汇总

2020北京-滴滴-高级前端开发面试题目汇总

前端面试题汇总

前端面试题汇总

备战金三银四2022最新Android中高级大厂面试题汇总,高薪必备(文末巨量资料免费分享)