主题
面试题代码题
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
<style>
*{
margin: 0;
padding: 0;
}
body{
width: 100vw;
height: 100vh;
}
.container>div{
float: left;
}
.c{
width: 100%;
height: 100vh;
background-color: aqua;
}
.l,.r{
width: 200px;
height: 100vh;
}
.l{
background-color: red;
margin-left: -100%;
}
.r{
background-color: blue;
margin-left: -200px;
}
.main{
padding-left: 200px;
}
</style>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完成