Skip to content

面试题代码题 ​

css(https://juejin.cn/post/6844903491891118087#heading-0) ​

面试题:用CSS画一个三角形 ​

css
用边框画(border),
例如: {
  width: 0;
  height: 0;

  border-left: 100px solid transparent;
  border-right: 100px solid transparent;
  border-top: 100px solid transparent;
  border-bottom: 100px solid #ccc;
}
css
{
    width:0;
    height:0;
    border:100px solid transparent;
    border-top-color:red
  }

面试题:一个盒子不给宽度和高度如何水平垂直居中? ​

方式一: ​
<div class='container'>
	<div class='main'>main</div>
</div>

.container{
		display: flex;
		justify-content: center;
		align-items: center;
		width: 300px;
		height: 300px;
		border:5px solid #ccc;
}
.main{
		background: red;
}
方式二: ​
.container{
	  position: relative;
		width: 300px;
		height: 300px;
		border:5px solid #ccc;
}
.main{
		background: red;
		position:absolute;
        top:50%;
        left:50%;
        transform: translate(-50%,-50%);
}

面试题:写一个左中右布局占满屏幕,其中左、右俩块固定宽200,中间自适应宽,要求先加载中间块,请写出结构及样式(双飞翼) ​

css
html
<div class="container">
  <div class="c">
    <div class="main">中间</div>
  </div>
  <div class="l">左</div>
  <div class="r">右</div>
</div>

js ​

面试题:0到100求和 ​

function sum(a,b){
    let num=a+b;
    if(b>=100){
        return num;
    }
    return sum(num,b+1)
}
let num=sum(0,1);

console.log(num)
function sum(n){
    if(n==1) return 1
     //逻辑  n+n-1 的和
  return n+sum(n-1)
}
let num=sum(100);

console.log(num)
function sum() {
    let num = 0;
    for (let i = 0; i <= 100; i++) {
        num = num + i
    }
    return num
}
let num = sum();

console.log(num)

面试题:JS数据类型考题 ​

考题一: ​
console.log( true + 1 );     			//2
console.log( NAN + 1 );     			//NAN
console.log( 'name'+true );  			//nametrue
console.log( undefined + 1 ); 		//NaN
console.log( typeof undefined ); //undefined
考题二: ​
console.log( typeof(NaN) );       //number
console.log( typeof(null) );      //object

面试题:JS作用域考题 ​

1. 除了函数外,js是没有块级作用域。
2. 作用域链:内部可以访问外部的变量,但是外部不能访问内部的变量。
	 注意:如果内部有,优先查找到内部,如果内部没有就查找外部的。
3. 注意声明变量是用var还是没有写(window.)
4. 注意:js有变量提升的机制【变量悬挂声明】
5. 优先级:声明变量 > 声明普通函数 > 参数 > 变量提升
面试的时候怎么看: ​
1. 本层作用域有没有此变量【注意变量提升】
2. 注意:js除了函数外没有块级作用域
3. 普通声明函数是不看写函数的时候顺序
考题一: ​
function c(){
	var b = 1;
	function a(){
		console.log( b );
		var b = 2;
		console.log( b );
	}
	a();
	console.log( b );
}
c();
考题二: ​
var name = 'a';
(function(){
	if( typeof name == 'undefined' ){
		var name = 'b';
		console.log('111'+name);
	}else{
		console.log('222'+name);
	}
})()
考题三: ​
function fun( a ){
	var a = 10;
	function a(){}
	console.log( a );
}
fun( 100 );

面试题:JS对象考题 ​

JS对象注意点: ​
1. 对象是通过new操作符构建出来的,所以对象之间不想等(除了引用外);
2. 对象注意:引用类型(共同一个地址);
3. 对象的key都是字符串类型;
4. 对象如何找属性|方法;
	查找规则:先在对象本身找 ===> 构造函数中找 ===> 对象原型中找 ===> 构造函数原型中找 ===> 对象上一层原型查找
考题一: ​
 [1,2,3] === [1,2,3]
考题二: ​
var obj1 = {
	a:'hellow'
}
var obj2 = obj1;
obj2.a = 'world';
console.log(obj1);
(function(){
	console.log(a);
	var a = 1;
})();
考题三: ​
var a = {}
var b = {
	key:'a'
}
var c = {
	key:'c'
}

a[b] = '123';
a[c] = '456';

console.log( a[b] );

面试题:JS作用域+this指向+原型的考题 ​

考题一:https://mp.weixin.qq.com/s/OIP4lPes0TjoI3xqW-0OSg ​
function Foo() {
    getName = function () {  //注意是全局的window.
        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();  //1  调用函数里面的Foo 因为没用申明getName 所以函数Foo里面 变成window.getName
getName();		  //1  函数Foo里面 变成window.getName 覆盖了var getName和function getName
new Foo.getName() //2
new Foo().getName();//3  先在对象本身找 ===> 构造函数中找 ===> 对象原型中找 ===> 构造函数原型中找 ===> 对象上一层原型查找
new new Foo().getName() //3
考题二: ​
var o = {
	a:10,
	b:{
		a:2,
		fn:function(){
			console.log( this.a );
			console.log( this );
		}
	}
}
o.b.fn();
考题三: ​
window.name = 'ByteDance';
function A(){
	this.name = 123;
}
A.prototype.getA = function(){
	console.log( this );
	return this.name + 1;
}
let a = new A();
let funcA = a.getA;
funcA();  //this代表window
考题四: ​
var length = 10;
function fn(){
	return this.length + 1;
}
var obj = {
	length:5,
	test1:function(){
		return fn();
	}
}
obj.test2 = fn;
console.log( obj.test1() );
console.log( fn()===obj.test2() );
console.log( obj.test1() == obj.test2() );

面试题:JS数组去重 ​

第一种 new Set ​
javascript
var fun = function (arr) {
  return [...new Set(arr)];
};
第二种 new Map ​
javascript
var fun = function (arr) {
  let map = new Map();
  let res = [];
  for (let i = 0; i < arr.length; i++) {
    if (!map.has(arr[i])) {
      map.set(arr[i], i);
      res.push(arr[i]);
    }
  }
  return arr;
};
第三种 两层for循环+splice ​
javascript
var fun = function (arr) {
  let len = arr.length;
  for (let i = 0; i < len; i++) {
    for (let j = i + 1; j < len; j++) {
      if (arr[i] === arr[j]) {
        arr.splice(j, 1);
        len--;
        j--;
        i--;
      }
    }
  }
  return arr;
};
第四种 indexOf ​
javascript
var fun = function (arr) {
  let res = [];
  for (let i = 0; i < arr.length; i++) {
    if (res.indexOf(arr[i]) == -1) {
      res.push(arr[i]);
    }
  }
  return res;
};
第五种 includes ​
javascript
var fun = function (arr) {
  let res = [];
  for (let i = 0; i < arr.length; i++) {
    if (!res.includes(arr[i])) {
      res.push(arr[i]);
    }
  }
  return res;
};
第六种 filter ​
javascript
var fun = function (arr) {
  return arr.filter((item, index) => {
    return arr.indexOf(item) == index;
  });
};
第七种 sort ​
javascript
var fun = function (arr) {
  arr = arr.sort();
  let res = [];
  for (let i = 0; i < arr.length; i++) {
    if (arr[i] !== arr[i - 1]) {
      res.push(arr[i]);
    }
  }
  return res;
};
引用 ​
var arr = [1,2,3,2,4,1];
console.log(  fun(arr) );

面试题:找出多维数组最大值 ​

function fnArr(arr){
	var newArr = [];
	arr.forEach((item,index)=>{
		newArr.push( Math.max(...item)  )
	})
	return newArr;
}
console.log(fnArr([
	[4,5,1,3],
	[13,27,18,26],
	[32,35,37,39],
	[1000,1001,857,1]
]));

面试题:遍历DOM节点,根据id返回对应dom树 ​

    <div id="box">
        <ul id="uls">
            <li>1</li>
            <li>2</li>
            <li>3</li>
        </ul>
        <p id="p1">
            <span>ppppp</span>
        </p>
    </div>
方式一:深度优先,递归操作实现 ​
    function findAllDom(parentNode, id) {
        if (parentNode) {
            let target = null;
            let children = Array.from(parentNode.children)
            if (parentNode.id == id) {
                return parentNode
            }
            for (let index = 0; index < children.length; index++) {
                target = findAllDom(children[index], id)
                if (target) return target
            }
        }
    }
    let myBox = document.getElementById("box");
    console.log(findAllDom(myBox, 'p1'))
方式二:深度优先 ===》使用栈(非递归操作) ​
    function allDom(parentNode, id) {
        if (!parentNode) {
            return null
        }
        if (parentNode.id == id) {
            return parentNode
        }
        let children = parentNode.children;
        let stack = [];
        for (let index = children.length; index > 0; index--) {
            stack.push(children[index - 1])
        }
        while (stack.length) {
            let node = stack.pop();
            if (node.id == id) {
                return node
            } else {
                if (node.children.length > 0) {
                    stack = Array.from(node.children).concat(stack)
                }
            }
        }
        return stack
    }
    let myBox = document.getElementById("box");
    console.log(allDom(myBox, 'uls'))

面试题:封装函数将字符串进行驼峰命名 ​

var str = 'ab_c-d_ef',
    reg = /[_-](\w)/g;
var str1 = str.replace(reg, function (a, b) {
    return b.toUpperCase();
})
 //已知有字符串foo='get-element-by-id',写一个function将其转化成驼峰表示法”getElementById”

      //自定义函数
      function toString(foo) {
        // 根据某个字符进行切割
        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"));

面试题:解析URL返回对象 ​

 function fParseQueryString(url) {
       let urls=url.split('?');
       let arr=urls[1].split('&');
       let obj={};
       for (let i=0; i<arr.length; i++){
           let brr=arr[i].split('=');
          obj[brr[0]]=brr[1];
       }
       return obj
    };
console.log(fParseQueryString('https://www.baidu.com/s?cl=3&tn=baidutop10&fr=top1000&rsv_idx=2&rsv_dl=fyb_n_homepage&sa=fyb_n_homepage&hisfilter=1&wd=%E5%90%84%E5%9C%B0%E8%B4%AF%E5%BD%BB%E5%8D%81%E4%B9%9D%E5%B1%8A%E5%85%AD%E4%B8%AD%E5%85%A8%E4%BC%9A%E7%B2%BE%E7%A5%9E%E7%BA%AA%E5%AE%9E'))

面试题:实现字符串反转 ​

let str = 'abcdef';
方式一: 使用split ​
function reversaStr(str) {
        return str.split('').reverse().join("")
    }
方式二: 使用扩展运算符(…) ​
function reversaStr(str) {
        return [...str].reverse().join("")
    }
方式三: 循环 ​
 function reversaStr(str){
      let str1='';
      for (let i = str.length-1; i >=0; i--) {
         str1+=str.charAt(i)
      }
      return str1
    }

面试题:旋转数组 ​

方式一: unshift ​
var rotate = function(nums, k) {
    nums.unshift(...nums.splice(nums.length - k))
    return nums;
};
方式二: splice ​
 var rotate = function(nums, k) {
	    nums.splice(0, 0, ...nums.splice(nums.length - k));
		return nums;
	};
方式三:for + unshift ​
var rotate = function(nums, k) {
	    for (var i = 0; i < k; i++) {
	        nums.unshift(nums.pop())
	    }
     return nums
	};
 let arr = [1, 2, 3, 4,5];
 rotate(arr,3);//[3, 4, 5, 1, 2]

面试题:给字符串新增方法实现功能 ​

给字符串对象定义一个addPrefix函数,当传入一个字符串str时,它会返回新的带有指定前缀的字符串,例如:

console.log( 'world'.addPrefix('hello') ) 控制台会输出helloworld

解答:
String.prototype.addPrefix = function(str){
	return str  + this;
}
console.log( 'world'.addPrefix('hello') )

面试题:检测一个对象是否有prop属性,没有就抛出异常,有的话返回true,并删掉该属性 ​

js
let obj = {
  a: 1,
  prop: 1,
};

function isProp(prop, obj) {
  if (obj.hasOwnProperty(prop)) {
    delete obj[prop];
  } else {
    throw new Error("没有该属性");
  }
}
isProp("prop", obj);
console.log(obj);

面试题:找出字符串出现最多次数的字符以及次数 ​

方式一: ​
var str = 'aaabbbbbccddddddddddx';
var obj = {};
for(var i=0;i<str.length;i++){
	var char = str.charAt(i);
	if( obj[char] ){
		obj[char]++;
	}else{
		obj[char] = 1;
	}
}
console.log( obj );
//统计出来最大值
var max = 0;
for( var key in obj ){
	if( max < obj[key] ){
		max = obj[key];
	}
}
//拿最大值去对比
for( var key in obj ){
	if( obj[key] == max ){
		console.log('最多的字符是'+key);
		console.log('出现的次数是'+max);
	}
}
方式二:new Map ​
const fun = (str) => {
        let map = new Map();
        let maxValue = '';
        let maxNum = 0;
        for (let item of str) {
            map.set(item, (map.get(item) || 0) + 1)
        }
        for (let [key, value] of map) {
            if (value > maxNum) {
                maxValue = key;
                maxNum = value
            }
        }
        return [maxValue, maxNum]
    }
    console.log(fun('abcabcabccc'))
方式三:for-of/for-in ​
const fun = (str) => {
        let obj = {};
        let maxValue = '';
        let maxNum = 0;
        for (let key of str) {
            obj[key] = !obj[key] ? 1 : obj[key] + 1
        }
        for (let key in obj) {
            if (obj[key] > maxNum) {
                maxValue = key;
                maxNum = obj[key]
            }
        }
        return [maxValue, maxNum]
    }
       console.log(fun('abcabcabccc'))
方式四:正则 ​
const fun = (str) => {
        //出现次数字符最多
        let maxValue = '';
        //出现次数字符最多的数字
        let maxNum = 0;
        //排序
        str=str.split("").sort().join("")
        //正则匹配
        let reg=/(\w)\1+/g;
        str.replace(reg, (val,item)=>{
            if(val.length>maxNum){
                maxNum=val.length
                maxValue=item
            }
        })
        console.log(str.match(reg))
        return [maxValue, maxNum]
    }
     console.log(fun('abcabcabccc'))

面试题:从localStorage中读取key为'hostarray'的数组,判读数组中是否存在主机地址1.1.1.1,如果不存在则将其插入数组开头 在将其存入localStorage ​

 function fun(key) {
    let arr = JSON.parse(localStorage.getItem(key)) || [];
    if (!arr || arr.length === 0) {
      localStorage.setItem(key, JSON.stringify(['1.1.1.1']))
      return
    }
    // 第一种indexOf
    // if (arr.indexOf('1.1.1.1') === -1) {
    //   arr.unshift('1.1.1.1')
    //   localStorage.setItem(key, JSON.stringify(arr))
    // }

    // 第二种includes
    // if(!arr.includes('1.1.1.1')){
    //   arr.unshift('1.1.1.1')
    //   localStorage.setItem(key, JSON.stringify(arr))
    // }

    // 第三种find
    // const isv = arr.find(elem => elem === '1.1.1.1')
    // if (!isv) {
    //   arr.unshift('1.1.1.1')
    //   localStorage.setItem(key, JSON.stringify(arr))
    // }

    // 第四种some
    const isv = arr.some(elem => elem === '1.1.1.1')
    if (!isv) {
      arr.unshift('1.1.1.1')
      localStorage.setItem(key, JSON.stringify(arr))
    }
  }
 fun('hostarray')

布局 ​

面试题:自适应 ​

淘宝无限适配【移动端】:淘宝无限适配 + 布局单位使用rem

面试题:响应式 ​

1. 是什么?
	一个URL可以响应多端
2. 语法结构
	@media only screen and (max-width: 1000px){
		ul li:last-child{
			display: none;
		}
	}

	only : 可以排除不支持媒体查询的浏览器
	screen : 设备类型
	max-width | max-height
	min-width | min-height
3. 响应式图片【性能优化】
	<picture>
		<source srcset="1.jpg" media='(min-width:1000px)'>
		<source srcset="2.jpg" media='(min-width:700px)'>
		<img srcset="3.jpg">
	</picture>

布局方案

一、什么情况下采用响应式布局

	数据不是特别多,用户量不是特别大,纯展示类的项目适合响应式布局

	例如:公司的官网、专题页面

	特别追求性能的项目,不太适合响应式,因为如果添加了很多的响应式就会造成加载速度变慢。

二、pc + 移动端应该做什么样的布局方案
	注意:访问量还可以或者比较大,类似于淘宝网。

	pc是一套,会加入一点点响应式。
	移动端是一套,会使用自适应的布局方式。

三、pc的设计图

	ui:1980
	笔记本电脑:1280
	ui图的宽度和电脑的宽度不对应该怎么办?
		1. 把ui图进行等比缩放,缩放成和电脑一样的尺寸
		2. 换1980的电脑

四、移动端的设计图

	宽度:750
	因为750设计图/2就是375,正好是iphone6的尺寸,我们要把iphone6的尺寸做为基准点。

分布式 ​

分布式 和 cap理论 ​

分布式 ​
分布式计算:两个或者多个软件共享信息,这些软件可以运行在同一台机器上,也可以通过网络连接起来共同实现计算

分布式系统:解决集中式 架构的性能瓶颈问题
核心:可扩展性, 通过对服务和存储的扩展,提高系统的处理能力

服务:  软性:专门某种语言 提供运行服务的
			php---> apache nginx
			java ---> tomcat
			硬性: 硬件服务器
通过对多态服务器的系统工作,完成高并发和大数据量的任务

分布式的特点:
	分布式系统 不出现单点故障  或  服务和存储无状态的特点:
	单点故障: 在系统中 ,一台机器出现问题,导致整个系统无法正常工作
	无状态:无状态的服务器可以满足系统需求,部分机器宕机 不影响全部 随时扩展
问题:
	节点之间通信  网络分区故障 数据不一致****
cap理论 ​
一个分布式系统:只能同时满足  一致性  可用性 和 分区容忍性  其中的两项
	一致性: 所有节点 同时 看到的数据是相同的,更新操作和返回客户的结果是一致的
	可用性: 任意时刻,读写操作都是成功的 即服务一直可用
			系统稳定性>99.9
			sla 服务水平协议  99.95%  故障时间 每月只能由 0.05% 时间
	分区容忍性:当部分节点消息丢失,出现分区故障,分布式系统仍然能正常运行

小结: 在分布式系统中,系统是层层拆分的,p(分区)固定的, cp应用模型是cp架构和ap架构的
	  保证 a 和 c 稳定性
高并发 ​
并发: 一个时间段内, 有多少进程在执行,由于时间对于计算机来说,是非常短暂的,人看起来 是同时执行的,所以我们认为是一起发生  并发
	  同一时刻有多少进程在同时执行   1微秒内

注意:如果只有一个cpu 是无法实现并行的,同一时刻 只能执行一个进程,如果执行多个进行,必须切换多个cpu ,可以同时开启多进程,这种称之为并行

高并发:可以在同一时间段内 处理大量的请求,10万请求/秒

node的高并发 和 分布式集群(线程 和 进程) ​

进程 ​
cpu承担运算, 操作系统是管理者,应用程序运行在操作系统之上的 一个具有独立功能的程序在一个数据集上依次动态执行的过程,是操作系统进行资源分配和调度一个独立单位 由程序(描述功能),数据集合(程序执行所需的数据和工作区),进程控制块(包含进程的描述信息和控制信息,唯一标识)

特证:
	动态性: 产生和消亡过程
	并发性:
	独立性: 独立单位
	结构性: 程序 数据 控制块

启动一个程序,同时可能启动一个以上的进程
线程 ​
线程是一个单独执行的任务吗,不会另外消耗多余的资源了
	线程之间可以共享资源
	线程可以创建和销毁另外一个线程
	线程可以并发执行

线程和进程的五个阶段: 创建 就绪 运行 阻塞 终止
区别: ​
一个进程有多个线程  线程是进程一个任务
进程之间是相互独立的,同一个进程下的线程是共享空间,线程可以相互创建和销毁
进程 是操作系统分配资源的最小单位  线程是程序执行的最小单位(线程只是一个任务)

线程切换速度 比进程快得多
多线程: ​
多进程:操作系统同时运行多个程序
多线程:在同一个程序中 有个任务在顺序轮流执行
多进程:操作系统能够同时运行多个任务
多线程:在同一个程序中 又多个线程在运行
主线程 ​
它可以产生其他子线程
通常主线程一般最后完成执行  重要功能 关闭各种子线程
为什么使用多线程 ​
线程启动和退出比较快,资源消耗比较少
线程调用更多的核心的硬件和软件对象
多线程优势 ​
占据时间较长的程序任务交给后台执行
在一个等待型的任务中, 用户输入 文件读写 网络收发消息 .... 线程资源消耗比较少
所有的应用软件中,线程都是占有重要作用的
多线程缺点 ​
线程过多,也会大量消耗资源   合理应用
由于线程可以互相创建---》 可能会形成阻塞  死锁

node特性 ​

单线程 ​
node中js主线程与其他线程(i/o线程),是无法共享状态的
node单线程优势:不用管其他线程  避免死锁  避免线程切换带来的资源消耗
缺陷: 无法高效利用 多核cpu   ,有可能引起cpu阻塞  , 一点出问题导致整个程序退出
利用多核cpu ​
第一种:使用child_process的核心模块cluster,child_process和net组合应用
	  在一台多核服务器上 创建多个进程,使用fork来充分利用每一个核心(处理好进程之间的通信)

第二种:将物理机划分为多态单核的虚拟机 通过pm2等工具,管理多态单核虚拟机形成的集群

cpu时间轮转  使用pm2工具 绕开坏点,执行正常的服务器的程序
异步I/O ​
node 具有异步I/O特性的  当遇到I/O请求的时候,node会分配给他一个线程,置于后台运行了
node去执行主线程上的其他任务,I/O返回的时候,node把返回传输出去
事物驱动 ​
主线程通过event loop事件循环 触发线程运行 这是node支持高并发的重要原因

分布式node架构 ​

node集群 ​
nginx(调度和负载均衡)--》node集群---》redis同步数据和状态

redis是操作内存的,读写速度非常快,但实际上 ,不可能让redis 过多的内存资源 数据管理 会添加mysql进行的

减轻内存的负担,项目运行中后期,需要对数据查询和分析的时候,mysql的优势很明显了(sql数据库)
注:短时间内 更新大量数据的时候,优先考虑redis 以达到快速存取的目的

nginx 是流量接入层: 对所有流量进行处理
	流量缓冲,分流和转发
	超时检测  建立链接超时  读取用户数据超时  后端响应超时  关闭链接超时.....

	在集群中 又坏点,隔离 修复 直到正常位置
	建立连接池和保存链接会话

	流量接入层----》 负载层 ---》根据时机情况发送到各台node机器上

提供的服务:
	文件上传下载
	线上配置各种环境
	设置定时任务
	镜像服务
	通信....
node 集群层 ​
编写和执行node代码,为用户提供后端服务
与数据交互,包括redis mysql 等数据库
管理和监控机器状态
数据库层 ​
创建数据和数据结构,方便node程序 增删改查各种数据
部署redis  且想node提供响应数据接口

apache tomcat .....
node集群层的使用 ​
单核运行
多线程操作 ​
单台机器上 如何让node 使用多核得cpu

node 但进程
  	32位操作系统  512M内存
  	64位 		 1G

node中cluster模块  主进程和n个worker进程,由主进程控制和协调 worker进程得运行

注意:
  	新建得链接 需要主进程完成,再有主进程把tcp链接 分配给worker完成