前端面试锦集之基础题总结

一、面试基础题
  1. 作用域和值类型引用类型的传递,代码如下所示:
<!DOCTYPE html>
<html>

	<head>
		<meta charset="UTF-8">
		<title></title>
	</head>

	<body>
		<script type="text/javascript">
			//第1题 作用域
			var num1 = 55;
			var num2 = 66;//100

			function f1(num, num1) {
				// var num =55;
				// var num1 = 66;
				num = 100;//100
				num1 = 100;//100
				num2 = 100;//100
				console.log(num);//100
				console.log(num1);//100
				console.log(num2);//100
			}
			//  55    66
			f1(num1, num2);
			console.log(num1);//55
			console.log(num2);//100
			console.log(num);// 报错

			//第2题  值类型和引用类型的传递
			function Person(name, age, salary) {
				this.name = name;
				this.age = age;
				this.salary = salary;
			}

			function f1(person) {
				//var person = p;
				person.name = "ls";
				person = new Person("aa", 18, 10);
			}

			var p = new Person("zs", 18, 1000);
			console.log(p.name);//zs
			f1(p);
			console.log(p.name);//ls
		</script>
	</body>

</html>
  1. 封装函数进行字符串驼峰命名的转换,代码如下所示:
<!DOCTYPE html>
<html>

	<head>
		<meta charset="UTF-8">
		<title></title>
	</head>

	<body>
		<script type="text/javascript">
			//已知有字符串foo='get-element-by-id',写一个function将其转化成驼峰表示法”getElementById”

			//自定义函数
			function toString(foo) {
//				var foo = 'get-element-by-id';
				//根据某个字符进行切割
				var arr = foo.split('-');
				//获取每个元素中的第一个字符并转换成大写
				console.log(arr[1].charAt(0).toUpperCase() + arr[1].substr(1, arr[1].length - 1));
				for(var i = 1; i < arr.length; i++) {

					arr[i] = arr[i].charAt(0).toUpperCase() + arr[i].substr(1, arr[i].length - 1)
				}
				//根据某个字符将数组转成字符串
				return arr.join('');
			}
			
		 	console.log(toString('get-element-by-id'));
		</script>
	</body>

</html>
  1. 冒泡排序的实现,代码如下所示:
<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8">
		<title></title>
	</head>

	<body>
		<script type="text/javascript">
			var arr = [32,4,67,82,21,11];
			
			///轮数
			for(var i = 0; i<arr.length-1;i++){
				//次数
				for(var j = 0;j<arr.length-1-i;j++){
					
					//判断前一个大于后一个数时进行交换
					if(arr[j]>arr[j+1]){
						//借助第三方变量交换两个变量的值
						var temp = arr[j];
						arr[j] = arr[j+1];
						arr[j+1] = temp;
					}
				}
			}
			console.log(arr);
		</script>
	</body>
</html>
  1. 反转数组,代码如下所示:
<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8">
		<title></title>
	</head>
	<body>
		<script type="text/javascript">
			var arr = [1,2,3,4,5,6,7,8];
			for(var i = 0;i<arr.length/2;i++){
				//arr[0]    arr[arr.length-1-0];
				//arr[1]    arr[arr.length-1-1];
				//arr[2]    arr[arr.length-1-2];
				//arr[3]    arr[arr.length-1-3];
				
				//借助第三方变量交换两个变量的值
				var temp = arr[i];
				arr[i] = arr[arr.length-1-i];
				arr[arr.length-1-i] = temp;
			}
			console.log(arr);
		</script>
	</body>
</html>

  1. 去掉数组中重复性的数据,代码如下所示:
<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8">
		<title></title>
	</head>
	<body>
		<script type="text/javascript">
			/*
			 * 1.创建一个新数组,把原数组中的第一个元素插入到新数组中
			 * 2.遍历原数组中的每一个元素分别和新数组中的每一个元素进行比较
			 */
			//原数组
			var arr = [8,11,20,5,20,8,0,2,4,0,8];
			// 新数组
			var  t = [];//var  t = [8,11];
			t[0] = arr[0];
			//arr中的每个元素
			for(var i=0;i<arr.length;i++){
				//t中的每个元素
				for(var k = 0;k<t.length;k++){
					
					//当原数组中的值和新数组中的值相同的时候,就没有必要再继续比较了,跳出内循环
					if(t[k] == arr[i]){
						break;
					}
					//拿原数组中的某个元素比较到新数组中的最后一个元素还没有重复
					if(k == t.length-1){
						//将数据插入新数组
						t.push(arr[i]);
					}
				}
			}
			console.log(t);
		</script>
	</body>
</html>

  1. 1 物理像素,有两种方式,如下所示:
  • 第一种方式,代码如下所示:

    <!DOCTYPE html>
    <html>
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width,initial-scale=1,user-scalable=no" />
        <title></title>
        <style type="text/css">
            *{
                margin: 0;
                padding: 0;
            }
            #box{
                width: 8rem;
                height: 8rem;
                border: 1px solid #000000;
            }
        </style>
    </head>
    <body>
    <div id="box"></div>
    </body>
    <script type="text/javascript">
        var box = document.getElementById('box');
    
        //获取设备像素比
        var dpr = window.devicePixelRatio;
        //比例
        var scale = 1/dpr;
    
        //获取屏幕宽度 375
        var width = document.documentElement.clientWidth;
    
        //获取meta标签
        var metaNode = document.querySelector('meta[name="viewport"]')
        metaNode.setAttribute('content','width=device-width,initial-scale='+ scale +',user-scalable=no')
    
        //元素比例乘回来
        var htmlNode = document.querySelector('html');
        htmlNode.style.fontSize = width/16*dpr + 'px';
    
    </script>
    </html>
    
    
  • 第二种方式,代码如下所示:

 <!DOCTYPE html>
   <html>
   <head>
       <meta charset="UTF-8">
       <meta name="viewport" content="width=device-width,initial-scale=1,user-scalable=no" />
       <title></title>
       <style type="text/css">
           *{
               margin: 0;
               padding: 0;
           }
           #box{
               width: 200px;
               height: 200px;
               position: relative;
           }
           #box:after{
               content: '';
               position: absolute;
               left: 0;
               bottom: 0;
               width: 100%;
               height: 1px;
               background: #000000;
           }
           @media screen and ( -webkit-min-device-pixel-ratio:2 ) {
               #box:after{
                   transform: scaleY(0.5);
               }
           }
           @media screen and ( -webkit-min-device-pixel-ratio:3 ) {
               #box:after{
                   transform: scaleY(0.333333333333);
               }
           }
       </style>
   </head>
   <body>
   <div id="box"></div>
   </body>

</html>
  1. flex 元素水平垂直居中,如下所示:
  • 新版本的垂直居中,代码如下:
 <!DOCTYPE html>
   <html lang="en">
   <head>
       <meta charset="UTF-8">
       <title>Title</title>
   
       <style type="text/css">
           * {
               margin: 0;
               padding: 0;
           }
   
           #wrap {
               width: 500px;
               height: 500px;
               background: grey;
   
               display: flex;
               justify-content: center;
               align-items: center;
           }
           #box{
               width: 200px;
               height: 200px;
               background: deeppink;
           }
       </style>
   </head>
   <body>
   <div id="wrap">
       <div id="box"></div>
   </div>
   </body>
   <script type="text/javascript">
       window.onload = function () {
           var box = document.getElementById('box');
   
   
       }
   </script>
</html>
  • 老版本的垂直居中,代码如下:

     <!DOCTYPE html>
      <html lang="en">
      <head>
          <meta charset="UTF-8">
          <title>Title</title>
      
          <style type="text/css">
              * {
                  margin: 0;
                  padding: 0;
              }
      
              #wrap {
                  width: 500px;
                  height: 500px;
                  background: grey;
      
                  display: -webkit-box;
                  -webkit-box-pack: center;
                  -webkit-box-align: center;
              }
              #box{
                  width: 200px;
                  height: 200px;
                  background: deeppink;
              }
          </style>
      </head>
      <body>
      <div id="wrap">
          <div id="box"></div>
      </div>
      </body>
      <script type="text/javascript">
          window.onload = function () {
              var box = document.getElementById('box');
      
      
          }
      </script>
      </html>
    
  1. css 实现三角形,代码如下所示:
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>

    <style type="text/css">
        * {
            margin: 0;
            padding: 0;
        }

        #box {
            width: 0px;
            height: 0px;

            border: 100px solid transparent;

            border-top-color: deeppink;
            border-left-color: deeppink;
            /*border-right-color: deeppink;*/
            /*border-bottom-color: deeppink;*/
        }
    </style>
</head>
<body>
<div id="box"></div>
</body>
<script type="text/javascript">
    window.onload = function () {
        var box = document.getElementById('box');


    }
</script>
</html>
  1. rem 适配,代码如下所示:
<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width,initial-scale=1,user-scalable=no" />
    <title></title>
    <style type="text/css">
        *{
            margin: 0;
            padding: 0;
        }
        #box{
            width: 8rem;
            height: 8rem;
            background: deeppink;
        }

    </style>
</head>
<body>
<div id="box"></div>
</body>
<script type="text/javascript">
    //获取屏幕宽度
    var width = document.documentElement.clientWidth;

    //获取html
    var htmlNode = document.querySelector('html');

    //设置html字体大小
    htmlNode.style.fontSize = width/16 + 'px';

</script>
</html>

  1. 背景图片的距离,代码如下所示:
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>

    <style type="text/css">
        * {
            margin: 0;
            padding: 0;
        }

        #box{
            width: 100px;
            height: 200px;
            background: pink;
            padding: 100px;
            border: 80px solid blue;
            background-image: url("img/1.png");
            background-repeat: no-repeat;
            background-origin: content-box;
            background-position: -50px 0;
        }

        /*答案:130px*/
    </style>
</head>
<body>
<div id="box"></div>
</body>
</html>
  1. 对于函数节流与函数防抖的理解,如下所示:
  • 函数节流,一个函数执行一次后,只有大于设定的执行周期后才会执行第二次。有个需要频繁触发函数,出于优化性能的角度,在规定时间内,只让函数触发的第一次生效,后面不生效。具体来说,记录上一次函数触发的时间,记录当前函数触发的时间,同步时间。
  • 防抖函数,一个需要频繁触发的函数,在规定时间内,只让最后一次生效,前面的不生效。具体来说,记录上一次的延时器,清除上一次的延时器,重新设置新的延时器。
  1. 对于跨域的理解,解决跨域的方法有哪些,如下所示:
  • 同源策略,是浏览器安全策略,协议名、域名和端口号必须完全一致。
  • 跨域,违背同源策略就会产生跨域
  • 解决跨域, jsonpcors 服务器代理
  • 对于跨域的具体实现,创建 script 标签,设置回调函数,数据请求回来会被触发的函数,设置 scriptsrc 属性,设置请求地址,让 script 生效
  1. 对于 node.js 的事件轮询机制的理解,可以借助 libuv 库实现的,概括事件轮询机制,分为六个阶段,如下所示:
  • timers 定时器阶段,计时和执行到点的定时器回调函数
  • pending callbacks,某些操作系统的回调函数,比如 TCP 错误类型
  • idle,prepare,准备工作
  • poll 轮询阶段,轮询队列,如果轮询队列不为空,依次同步取出轮询队列中第一个回调函数执行,直到轮询队列为空或者达到系统最大的限制。如果轮询队列为空,如果之前设置过 setImmediate 函数,直接进入下一个 check 阶段。如果之前没有设置过 setImmediate 函数,在当前 poll 阶段等待,直到轮询队列添加回调函数,就去第一个情况执行。如果定时器到点了,也会去下一个阶段。
  • check 查阶段,执行 setImmediate 设置的回调函数
  • close callbacks 关闭阶段,执行 close 事件回调函数
  • process.nextTick 能在任意阶段优先执行,process.nextTick() > setTimeout() > setImmediate()
  1. 对于从一个 url 地址到最终页面渲染完成,发生了什么,如下所示:
  • DNS 解析,将域名地址解析为 IP 地址,如下所示:
    • 浏览器 DNS 缓存
    • 系统 DNS 缓存
    • 路由器 DNS 缓存
    • 网络运营商 DNS 缓存
    • 递归搜索,如 blog.baidu.com.com 域名下查找 DNS 解析,.baidu 域名下查找 DNS 解析,blog 域名下查找 DNS 解析,出错了
  • TCP连接,TCP 三次握手,如下所示:
    • 第一次握手,由浏览器发起,告诉服务器我要发送请求了
    • 第二次握手,由服务器发起,告诉浏览器我准备接受了,你赶紧发送吧
    • 第三次握手,由浏览器发送,告诉服务器,我马上就发了,准备接受吧
  • 发送请求,请求报文,HTTP 协议的通信内容
  • 接受响应,响应报文
  • 渲染页面,如下所示:
    • 遇见 HTML 标记,浏览器调用 HTML 解析器解析完成 Token 并构建 DOM
    • 遇见 style/link 标记,浏览器调用 css 解析器,处理 css 标记并构建 CSSOM
    • 遇见 script 标记,调用 javascript 解析器,处理 script 代码,绑定事件,修改 DOM 树/CSSOm
    • DOM 树和 CSSOM 树合并成一个渲染树
    • 根据渲染树来计算布局,计算每个节点的几个信息,布局
    • 将各个节点颜色绘制到屏幕上,渲染
    • 值得注意的是,这几个步骤不一定按照顺序执行,如果 DOM 树或 CSSOM 树被修改了,可能会执行多次布局和渲染,往往实际页面中,这些步骤都会执行多次的
  • 断开连接,TCP 四次挥手,如下所示:
    • 第一次挥手,由浏览器发起的,发送给服务器,我东西发送完了,请求报文,你准备关闭吧
    • 第二次挥手,由服务器发起的,告诉浏览器,我东西接收完了,请求报文,我准备关闭了,你也准备吧
    • 第三次挥手,有服务器发起,告诉浏览器,我东西发送完了,响应报文,你准备关闭吧
    • 第四次挥手,由浏览器发起,告诉服务器,我东西接收完了,我准备关闭了,响应报文,你也准备吧
  1. 对于闭包的理解,如下所示:
  • 闭包,密闭的容器,类似于setmap容器,存储数据的。闭包是一个对象,存放数据的格式: key: value
  • 闭包的形成的条件,函数嵌套,内部函数引用外部函数的局部变量
  • 闭包的优点,延长外部函数局部变量的生命周期
  • 闭包的缺点,容易造成内存泄漏
  • 注意的是,合理的使用闭包,用完闭包要及时清除(销毁)
  • 闭包的实例代码,如下所示:
    
    // 闭包的应用场景
    // function fun() {
    //   var count = 1;
    //   return function () {
    //     count++;
    //     console.log(count);
    //   }
    // }
    //
    // var fun2 = fun();
    // fun2(); // 2
    // fun2(); // 3
    //
    
    
    /*
       说说它们的输出情况
       */
    
    function fun(n, o) {
      // var n = 1, o;
      console.log(o)
      return {
        fun: function (m) {
          // var m = 1;
          return fun(m, n)
        }
      }
    }
    var a = fun(0)
    a.fun(1)
    a.fun(2)
    a.fun(3) //undefined,0,0,0
    
    var b = fun(0).fun(1).fun(2).fun(3).fun(50).fun(22) //undefined,0,1,2,3,50
    
    var c = fun(0).fun(1)
    c.fun(2)
    c.fun(3) //undefined,0,1,1
    
    
    
  1. 对于变量提升与执行上下文的理解,如下所示:
  • 变量提升,JS 引擎在代码正式执行之前会做一个预处理的工作,收集变量和收集函数。依据是 varvar 后边的变量定义但是不赋值 var username = undefined; function() {} 提前定义该函数
  • 执行上下文,execute context EC,代码执行的环境,代码正式执行之前会进入到执行环境,对于它的工作,如下所示:
    • 创建变量对象,变量,函数及函数的对象,全局是 window,局部是抽象的但是确实存在
    • 确认 this 的指向,全局 this 指向 window,局部 this 指向调用其的对象
    • 创建作用域链,父级作用域链 + 当前的变量对象
    • 扩展,ECObj = { 变量对象:{变量,函数,函数的形参}, scopeChain:父级作用域链 + 当前的变量对象,this:{ window || 调用其的对象}}
  1. 对于宏任务和微任务的理解,如下所示:
  • 宏任务,分类: setTimeout setInterval requrestAnimationFrame,如下所示:
    • 宏任务所处的队列就是宏任务队列
    • 第一个宏任务队列中只有一个任务: 执行主线程的 js 代码
    • 宏任务队列可以有多个
    • 当宏任务队列的中的任务全部执行完以后会查看是否有微任务队列如果有先执行微任务队列中的所有任务,如果没有就查看是否有宏任务队列
  • 微任务,分类: new Promise().then(回调) process.nextTick,如下所示:
    • 微任务所处的队列就是微任务队列
    • 只有一个微任务队列
    • 在上一个宏任务队列执行完毕后如果有微任务队列就会执行微任务队列中的所有任务
  • 宏任务和微任务的代码,如下所示:
    
    setTimeout(() => {
      console.log('setTimeout');
    }, 0)
    
    new Promise((resolve, reject) =>{
      for (var i = 0; i < 5; i++) {
        console.log(i);
      }
      resolve();  // 修改promise实例对象的状态为成功的状态
    }).then(() => {
      console.log('promise实例成功回调执行');
    })
    
    
    
  1. 比较一下 ReactVue 之间的相同点与不同点,如下所示:
  • 相同点,如下所示:
    • 都有组件化开发和 Virtual DOM
    • 都支持 props 进行父子组件间数据通信
    • 都支持数据驱动视图, 不直接操作真实 DOM, 更新状态数据界面就自动更新
    • 都支持服务器端渲染
    • 都有支持 native 的方案, ReactReact Native,VueWeex
  • 不同点,如下所示:
    • 数据绑定: vue实现了数据的双向绑定,react数据流动是单向的
    • 组件写法不一样, React推荐的做法是 JSX , 也就是把HTMLCSS全都写进JavaScript了,即'all in js'; Vue推荐的做法是webpack+vue-loader的单文件组件格式,即html,css,js写在同一个文件
    • state对象在react应用中不可变的,需要使用setState方法更新状态;在vue中,state对象不是必须的,数据由data属性在vue对象中管理
    • virtual DOM不一样,vue会跟踪每一个组件的依赖关系,不需要重新渲染整个组件树.而对于React而言,每当应用的状态被改变时,全部组件都会重新渲染,所以react中会需要shouldComponentUpdate这个生命周期函数方法来进行控制
    • React严格上只针对MVCview层,Vue则是MVVM模式
  1. 对于Redux管理状态的机制的理解,如下所示:
  • Redux 基本理解,如下所示:
    • redux是一个独立专门用于做状态管理的JS库, 不是react插件库
    • 它可以用在react, angular, vue项目中, 但基本与 react 配合使用
    • 作用是集中式管理 react 应用中多个组件共享的状态和从后台获取的数据
  • Redux使用扩展,如下所示:
    • 使用react-redux简化redux的编码
    • 使用redux-thunk实现redux的异步编程
    • 使用Redux DevTools实现chromeredux的调试
  1. 对于 Vue 组件间通信方式的理解,如下所示:
  • 通信种类,如下所示:
    • 父组件向子组件通信
    • 子组件向父组件通信
    • 隔代组件间通信
    • 兄弟组件间通信
  • 实现通信方式,如下所示:
    • props
    • vue自定义事件
    • 消息订阅与发布
    • vuex
    • slot
  • 方式1: props,如下所示:
    • 通过一般属性实现父向子通信
    • 通过函数属性实现子向父通信
    • 缺点是隔代组件和兄弟组件间通信比较麻烦
  • 方式2: vue 自定义事件,如下所示:
    • vue 内置实现, 可以代替函数类型的props,绑定监听: <MyComp @eventName="callback",触发(分发)事件: this.$emit("eventName", data)
    • 缺点是只适合于子向父通信
  • 方式3: 消息订阅与发布,如下所示:
    • 需要引入消息订阅与发布的实现库, 如: pubsub-js,订阅消息: PubSub.subscribe('msg', (msg, data)=>{}),发布消息: PubSub.publish(‘msg’, data)
    • 优点是此方式可用于任意关系组件间通信
  • 方式4: vuex,如下所示:
    • vuexvue官方提供的集中式管理vue多组件共享状态数据的vue插件
    • 优点是对组件间关系没有限制, 且相比于pubsub库管理更集中, 更方便
  • 方式5: slot,如下所示:
    • 专门用来实现父向子传递带数据的标签,子组件和父组件
    • 注意的是,通信的标签模板是在父组件中解析好后再传递给子组件的
  1. 对于 Vuex管理状态的机制的理解,如下所示:
  • Vuex 是一个专为 Vue.js 应用程序开发的状态管理的vue插件
  • 作用是集中式管理vue多个组件共享的状态和从后台获取的数据
  1. 对于VueMVVM实现原理的理解,如下所示:
  • Vue作为MVVM模式的实现库的2种技术,模板解析和数据绑定
  • 模板解析,实现初始化显示,解析大括号表达式和解析指令
  • 数据绑定,实现更新显示,通过数据劫持实现
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值