查看原文
其他

百度某部门面试原题

前端之神 2023-02-12

The following article is from 前端早茶 Author 广东靓仔

关注公众号「前端之神」,简历指导,模拟面试,学习群

一、背景

    这套题目是广东靓仔认识的一位前端妹子经过“一番努力”Get到的,感谢~

这套题目,比较实用的,接下来广东靓仔跟小伙伴一起来看看这套百度某部门的技术一面原题。

二、原题

设置元素的backgroud 哪些区域颜色会改变

background填充区域默认为contentpaddingborder区域。

然而该行为由background-clip属性决定,默认为border-box该属性对应的

background填充对应区域如下:


FOUC 无样式闪烁(文档样式短暂失效)@import

如果使用import方法对CSS进行导入,会导致某些页面在Windows 下的Internet Explorer出现一些奇怪的现象:以无样式显示页面内容的瞬间闪烁,这种现象称之为文档样式短暂失效(Flash of Unstyled Content),简称为FOUC。


原因大致为:
1:使用import方法导入样式表;
2:将样式表放在页面底部;
3:有几个样式表,放在html结构的不同位置;

其实原理很清楚:

当样式表晚于结构性html加载,当加载到此样式表时,页面将停止之前的渲染。此样式表被下载和解析后,将重新渲染页面,也就出现了短暂的花屏现象。


解决方法:

使用LINK标签将样式表放在文档HEAD中。

重绘重排区别

重绘不一定需要重排(比如颜色的改变)
重排必然导致重绘(比如改变网页位置


重排(Reflow):

当渲染树的一部分必须更新并且节点的尺寸发生了变化,浏览器会使渲染树中受到影响的部分失效,并重新构造渲染树。


重绘(Repaint):

是在一个元素的外观被改变所触发的浏览器行为,浏览器会根据元素的新属性重新绘制,使元素呈现新的外观。比如改变某个元素的背景色、文字颜色、边框颜色等等


减少重排次数和缩小重排影响范围解决方式:

1. 将多次改变样式属性的操作,合成一次操作。
2. 将需要多次重排的元素,嗯,position属性。设为absolute。或fixed。使其脱离文档流,这样,他的变化就不会影响到其他的元素。
3. 在内存中多次操作节点。完成后再添加到文档中去。
4. 如果对一个元素进行复杂的操作,可以将display属性设为none嗯使其隐藏。操作完后再显示。
5. 在需要经常获取那些引起浏览器重排的属性值时,要缓存到变量。

你们项目中Token是怎么拿到的

  • 用户登陆,发送手机号码和验证码
  • 后台接收参数,查找用户,用户存在就生成token,返回给前端
  • 前端登陆成功,把token存到vuex(做持久化)
  • 使用axios拦截器,读取vuex中的token,并放入请求头
  • 请求其他接口,就会带上token
  • 后台在需要登陆的接口上,获取token,解密token获得userId,返回前端需要的数据
  • 用户在下次使用app,如果token还在有效期内,不需要重新登陆


有不同的或者更好的方案也可以回答,发散题,自由发挥

cookie是什么?

cookie 是存储在浏览器中的纯文本,浏览器的安装目录下会专门有一个 cookie 文件夹来存放各个域下设置的cookie。
存储量很小4kb

拓展说明,加分项:

    当网页要发http请求时,浏览器会先检查是否有相应的cookie,有则自动添加在request header中的cookie字段中。 这些是浏览器自动帮我们做的,而且每一次http请求浏览器都会自动帮我们做。
所以对于那设置“每次请求都要携带的信息(最典型的就是身份认证信息)”就特别适合放在cookie中,其他类型的数据就不适合了。

时效性

expires 是 http/1.0协议中的选项,在新的http/1.1协议中expires已经由 max-age选项代替,两者的作用都是限制cookie 的有效时间。
expires的值是一个时间点(cookie失效时刻= expires ),而max-age 的值是一个以秒为单位时间段(cookie 失效时刻= 创建时刻+ max-age )。

httpOnly

设置cookie是否能通过 js 去访问。默认情况下,cookie不会带httpOnly选项(即为空),所以默认情况下,客户端是可以通过js代码去访问(包括读取、修改、删除等)这个cookie的。当cookie带httpOnly选项时,客户端则无法通过js代码去访问(包括读取、修改、删除等)这个cookie。

Js数据类型有哪些 

值类型(基本类型):
字符串(String)、数字(Number)、布尔(Boolean)、对空(Null)、未定义(Undefined)、Symbol。

引用数据类型:
对象(Object)、数组(Array)、函数(Function)。


基本类型引用类型区别 

基本类型
基本类型的访问是按值访问的,就是说我们可以操作保存在变量中的实际的值。基本类型有以下几个特点:
  1. 基本类型的值是不可变得:   
    2.基本类型的比较是值的比较:
    3.基本类型的变量是存放在栈区的(栈区指内存里的栈内存)

引用类型
引用类型可以拥有属性和方法,属性又可以包含基本类型和引用类型。引用类型的有以下一些特性:
1.引用类型的值是可变的
2.引用类型的值是同时保存在栈内存和堆内存中的对象
3.引用类型的比较是引用的比较

判断一个对象是不是数组

方法1:

根据对象的class属性来判断

let obj = []
console.log(Object.prototype.toString.call(obj) === '[object Array]')

方法2:

Array.isArray直接判断

let obj = []
console.log(Array.isArray(obj))

js数组遍历都有哪些方法

这里列举12种,具体如下所示:


1.for循环

for(i = 0,len=arr.length; i < len; i++) {   
}


2.foreach循环

// 没有返回值,对原数组无影响
arr.forEach((item,index,array)=>{
    //执行代码
})
// 参数:value数组中的当前项, index当前项的索引, array原始数组;


3.map循环

var ary = [12,23,24,42,1]; 
var res = ary.map(function (item,index,ary ) 
    return item*10
}) 
console.log(res);//-->[120,230,240,420,10];  原数组拷贝了一份,并进行了修改
console.log(ary);//-->[12,23,24,42,1];  原数组并未发生变化


4.forof遍历

for (var value of myArray) {
console.log(value);
}


5.filter遍历

不会改变原始数组,返回新数组
var arr = [73,84,5622,100]
var newArr = arr.filter(item => item>80)   //得到新数组 [84, 100]
console.log(newArr,arr)


6.every遍历

every()是对数组中的每一项运行给定函数,如果该函数对每一项返回true,则返回true。

var arr = [ 123456 ]; 
console.log( arr.every( function( item, index, array )
        return item > 3
    })); 
// false


7.some遍历

some()是对数组中每一项运行指定函数,如果该函数对任一项返回true,则返回true。
var arr = [ 123456 ]; 
   
console.log( arr.some( function( item, index, array )
  return item > 3
})); 
// true


8.reduce

      reduce() 方法接收一个函数作为累加器(accumulator),数组中的每个值(从左到右)开始缩减,最终为一个值。
var total = [0,1,2,3,4].reduce((a, b)=>a + b); //10

     reduce接受一个函数,函数有四个参数,分别是:上一次的值,当前值,当前值的索引,数组

[01234].reduce(function(previousValue, currentValue, index, array){
 return previousValue + currentValue;
});


9.reduceRight

reduceRight()方法的功能和reduce()功能是一样的,不同的是reduceRight()从数组的末尾向前将数组中的数组项做累加。


reduceRight()首次调用回调函数callbackfn时,prevValue curValue 可以是两个值之一。如果调用 reduceRight() 时提供了 initialValue 参数,则 prevValue 等于 initialValuecurValue 等于数组中的最后一个值。如果没有提供 initialValue 参数,则 prevValue 等于数组最后一个值, curValue 等于数组中倒数第二个值。
var arr = [0,1,2,3,4];
 
arr.reduceRight(function (preValue,curValue,index,array) {
    return preValue + curValue;
}); // 10


10.find

find()方法返回数组中符合测试函数条件的第一个元素。否则返回undefined。
var stu = [
    {
        name'张三',
        gender'男',
        age20
    },
    {
        name'王小毛',
        gender'男',
        age20
    },
    {
        name'李四',
        gender'男',
        age20
    }
]
stu.find((element) => (element.name == '李四'))
//返回结果为
//{name: "李四", gender: "男", age: 20}


11.findIndex

对于数组中的每个元素,findIndex 方法都会调用一次回调函数(采用升序索引顺序),直到有元素返回 true。只要有一个元素返回 truefindIndex 立即返回该返回 true 的元素的索引值。如果数组中没有任何元素返回 true,则 findIndex 返回 -1。

findIndex 不会改变数组对象。

[1,2,3].findIndex(x => x == 4);
// Returns an index value of -1.


12.keys,values,entries

 ES6 提供三个新的方法 —— entries(),keys()和values() —— 用于遍历数组。它们都返回一个遍历器对象,可以用for...of循环进行遍历,唯一的区别是keys()是对键名的遍历、values()是对键值的遍历,entries()是对键值对的遍历

for (let index of ['a''b'].keys()) {
console.log(index);
}
// 0
// 1

for (let elem of ['a''b'].values()) {
console.log(elem);
}
// 'a'
// 'b'

for (let [index, elem] of ['a''b'].entries()) {
console.log(index, elem);
}
// 0 "a"
// 1 "b"

Js事件循环机制

Event Loop 包含两类:

1. 一类是基于 Browsing Context ,

2. 一种是基于 Worker 

二者是独立运行的。 


JavaScript 是一门单线程语言,异步操作都是放到事件循环队列里面,等待主执行栈来执行的,并没有专门的异步执行线程。


任务队列

任务可以分为同步任务和异步任务,同步任务,顾名思义,就是立即执行的任务,同步任务一般会直接进入到主线程中执行;

而异步任务,就是异步执行的任务,比如ajax网络请求,setTimeout 定时函数等都属于异步任务,异步任务会通过任务队列( Event Queue )的机制来进行协调。

在事件循环中,每进行一次循环操作称为tick,通过阅读规范可知,每一次 tick 的任务处理模型是比较复杂的,其关键的步骤可以总结如下:

  1. 在此次 tick 中选择最先进入队列的任务( oldest task ),如果有则执行(一次)
  2. 检查是否存在 Microtasks ,如果存在则不停地执行,直至清空Microtask Queue
  3. 更新 render
  4. 主线程重复执行上述步骤

深浅拷⻉贝区别

浅拷贝(Shallow Copy):

仅拷贝对象的非对象属性(基本类型属性)、不可变对象属性,但是不拷贝对象的对象属性(不含不可变对象) ,即为浅拷贝。

    以下这些函数得到的都是浅拷贝:

Object.assign、Array.prototype.slice()、Array.prototype.concat()


深拷贝(Deep Copy):

对基本数据类型进行值传递,对引用数据类型,创建一个新的对象,并复制其内容,此为深拷贝。

简单理解:深拷贝会拷贝所有的属性。深拷贝前后两个对象互不影响。

JSON.parse(JSON.stringify())、手写递归函数、函数库lodash

箭头函数特点

1. 省略function换成=> 一个参数的时候()可以省略 一个return的时候{}可以省略
2. 不绑定this,其中的this指向函数定义位置的上下文this
3. 内部不存在arguments和new.target,使用的都是外部的
4. 没有原型,占用内存空间小

Js垃圾回收方法

Javascript具有自动垃圾回收机制(GC:Garbage Collecation)。
原理:垃圾收集器会定期(周期性)找出那些不在继续使用的变量,然后释放其内存。

(1)标记清除法

    在函数声明一个变量的时候,就将这个变量标记为“进入环境”。
(2)引用计数法
 引用计数的含义是跟踪记录每个值被引用的次数。当这个值的引用次数变成0时,就可以将其占用的内存空间回收回来。

Vuex更新流程

vuex的工作流程就是:

(1)通过dispatch去提交一个actions,

(2)actions接收到这个事件之后,在actions中可以执行一些异步|同步操作,根据不同的情况去分发给不同的mutations,

(3)actions通过commit去触发mutations,

(4)mutations去更新state数据,state更新之后,就会通知vue进行渲染


拓展:

不能在mutations执行异步操作

Vuex中所有的状态更新的唯一途径都是mutation,异步操作通过 Action 来提交 mutation实现,这样使得我们可以方便地跟踪每一个状态的变化,从而让我们能够实现一些工具帮助我们更好地了解我们的应用。

每个mutation执行完成后都会对应到一个新的状态变更,这样devtools就可以打个快照存下来,然后就可以实现 time-travel 了。如果mutation支持异步操作,就没有办法知道状态是何时更新的,无法很好的进行状态的追踪,给调试带来困难。

vue keep-alive组件有什么用

用于保留组件状态或避免重新渲染(缓存的作用)

两个属性includeexclude

  • include:字符串或者正则表达式。只有匹配的组件会被缓存

  • exclude:字符串或者正则表达式。任何匹配的组件都不会被缓存。

二者都可以用逗号分割字符串、正则表达式或者一个数组。

<!-- 逗号分隔字符串 -->
<keep-alive include="a,b">
  <component :is="view"></component>
</keep-alive>


<!-- 正则表达式 (使用 `v-bind`) -->
<keep-alive :include="/a|b/">
  <component :is="view"></component>
</keep-alive>


<!-- 数组 (使用 `v-bind`) -->
<keep-alive :include="['a', 'b']">
  <component :is="view"></component>
</keep-alive>

如何监听一个变量的变化 长度 index

defineProperty

var a = { watchValue:0 };
var lastTimeValue=a.watchValue;
Object.defineProperty(a, 'watchValue', {
  getfunction() {
    console.log('get:' + watchValue);
    return watchValue;
  },
  setfunction(value) {
    watchValue = value;
    if(lastTimeValue!=watchValue){
        lastTimeValue=watchValue;
        console.log('value changed!! set: ' + watchValue);
    }
  }
});


proxy

var observe1 = (object, onChange) => {
  const handler = {
    get(target, property, receiver) {
      try {
        return new Proxy(target[property], handler);
      } catch (err) {
        return Reflect.get(target, property, receiver);
      }
    },
    set(target, key, value, receiver) {
      onChange(value);
      return Reflect.set(target, key, value, receiver);
    }
  };
  return new Proxy(object, handler);
};

var obj = {
  foofalse,
  a: {
    x:{y4},
    b:[{cfalse}]
  }
};

var watchedObj = observe1(obj,(val)=>{
  console.log(`哈哈哈,监听到值变化为${val}了`);
});
watchedObj.foo = true
watchedObj.a.x.y = 5// 监听到值变化为5了
watchedObj.a.b[0].c = true;

webpack lorder / plugin

webpack是一个模块打包器(module bundler),提供了一个核心,核心提供了很多开箱即用的功能,同时它可以用loader和plugin来扩展。


loader的使用方式

1:在配置文件webpack.config.js中配置

module.exports = {
  module: {
    rules: [
      {
        test/\.txt$/,
        use'raw-loader'
      }
    ]
  }
}

2:通过命令行参数方式

webpack --module-bind 'txt=raw-loader'

3:通过内联使用

import txt from 'raw-loader!./file.txt';

webpack常用的loader

样式:style-loader、css-loader、less-loader、sass-loader等
文件:raw-loader、file-loader 、url-loader等
编译:babel-loader、coffee-loader 、ts-loader等
校验测试:mocha-loader、jshint-loader 、eslint-loader等
比如下面配置,可以匹配.scss的文件,分别经过sass-loader、css-loader、style-loader的处理。
sass-loader转化sass为css文件,并且包一层module.exports成为一个js module。
style-loader将创建一个style标签将css文件嵌入到html中。
css-loader则处理其中的@import和url()。
module.exports = {
  module: {
    rules: [
        {
          test/\.scss$/,
          use:[
              {loader:'style-loader'},
              {loader:'css-loader',options:{sourceMap:true,modules:true}},
              {loader:'sass-loader',options:{sourceMap:true}}
          ],
          exclude:/node_modules/
      }
    ]
  }
}

webpack常用的plugin

首先webpack内置UglifyJsPlugin,压缩和混淆代码。
webpack内置CommonsChunkPlugin,提高打包效率,将第三方库和业务代码分开打包。
ProvidePlugin:自动加载模块,代替require和import


写一个webpack插件步骤如下:

1. 编写一个JavaScript命名函数。

2. 在它的原型上定义一个apply方法。

3. 指定挂载的webpack事件钩子。

4. 处理webpack内部实例的特定数据。

5. 功能完成后调用webpack提供的回调。


编写插件之前要理解compiler和compilation两个对象,以及webpack生命周期的各个阶段和钩子,plugin比loader强大,通过plugin你可以访问compliler和compilation过程,通过钩子拦截webpack的执行。

package.json package.lock.json 区别

package.json

Node.js 项目遵循模块化的架构,当我们创建了一个 Node.js 项目,意味着创建了一个模块,这个模块的描述文件,被称为 package.json。


 属性说明

  • name - 包名;
  • version - 包的版本号;
  • description - 包的描述;
  • homepage - 包的官网URL;
  • author - 包的作者,它的值是你在 https://npmjs.org 网站的有效账户名,遵循“账户名<邮件>”的规则,例如:zhangsan <zhangsan@163.com>;
  • contributors - 包的其他贡献者;
  • dependencies / devDependencies - 生产/开发环境依赖包列表。它们将会被安装在 node_module 目录下;
  • repository - 包代码的 Repo 信息,包括 type 和 URL,type 可以是 git 或 svn,URL 则是包的 Repo 地址;
  • main - main 字段指定了程序的主入口文件,这个字段的默认值是模块根目录下面的 index.js;
  • keywords - 关键字

devDependencies、dependencies、peerDependencies的区别

  • devDependencies是只会在开发环境下依赖的模块,生产环境不会被打入包内。安装时,加上--save-dev
  • dependencies依赖的包不仅开发环境能使用,生产环境也能使用。安装时,加上--save
  • peerDependencies是用来发布npm插件时指定所需要兼容的宿主包的版本。


package.lock.json

当我们安装依赖时,package-lock.json 文件会自动生成。
package-lock.json 文件中记录了下载源地址,可以加快我们的 npm install 速度。

怎么转化less为css

Less 是一门 CSS 预处理语言,它扩充了 CSS 语言,增加了诸如变量、混合(mixin)、函数等功能,让 CSS 更易维护、方便制作主题、扩充。


webpack的配置如下:

module: {
        rules: [{
            test/\.less$/,
            use: ["style-loader""css-loader""less-loader"]
//编译方向从右到左less-loader=>css-loader=>style-loader
        }, {
            test/\.js$/,
            exclude/node_modules/,
            loader'babel-loader',
        }]
    }

把样式文件less转为css并且单独提取出来(不放置在bundle.js中)

const ExtractTextPlugin = require('extract-text-webpack-plugin');
module.exports = {
 plugins: [
        new ExtractTextPlugin('style.css')
        //if you want to pass in options, you can do so:
        //new ExtractTextPlugin({
        //  filename: 'style.css'
        //})

    ]
}

地址栏输入一个url到页面渲染过程

1、HTTP 请求准备阶段

  • 构建请求--浏览器构建请求行信息,准备发起网络请求 GET /index.html HTTP1.1
  • 查找缓存--如果浏览器发现请问资源在浏览器中存在副本,根据强缓存规则,如没有过期那么直接返回资源,如何查找失败进入下一个环节:

    --准备 ip 地址和端口

    --DNS(域名和ip的映射系统) 域名解析,拿到ip之后找端口,默认为80

    --建立tcp链接(三次握手)

    --如果是https 还需要建立TLS连接

2、HTTP 发送请求

浏览器向服务端发起http请求,把请求头和请求行一起发送个服务器,服务端解析请求头如发现cache-control和etag(if-none-match),if-modified(if-modified-since)字段就会判断缓存是否过期,如果没有返回304,否则返回200

3、HTTP 响应返回

  • 浏览器拿到响应数据,首先判断是否是4XX或者5XX是就报错,如果是3XX就重定向,2XX就开始解析文件,如果是gzip就解压文件
  • TCP断开连接
  • 4次挥手

  • 浏览器解析渲染

  • 建立根据html建立dom树和css树,如果遇到script首选判断是否defer和async否则会阻塞渲染并编译执行js,如果没有则组合生成render tree,最后浏览器开启GPU进行绘制合成图层,将内容显示屏幕。

content-type作用

Content-Type 实体头部用于指示资源的MIME类型 media type 。


在响应中,Content-Type标头告诉客户端实际返回的内容的内容类型。浏览器会在某些情况下进行MIME查找,并不一定遵循此标题的值;为了防止这种行为,可以将标题 X-Content-Type-Options 设置为 nosniff。

在请求中 (如POST 或 PUT),客户端告诉服务器实际发送的数据类型。

Content-Type 的值类型:

1.1 application/json:消息主体是序列化后的 JSON 字符串 

1.2 application/x-www-form-urlencoded:数据被编码为名称/值对。这是标准的编码格式 

1.3 multipart/form-data: 需要在表单中进行文件上传时,就需要使用该格式。常见的媒体格式是上传文件之时使用的 

1.4 text/plain:数据以纯文本形式(text/json/xml/html)进行编码,其中不含任何控件或格式字符

介绍知道的状态码,状态码301、302区别

状态码分为5类:
1**信息,服务器收到请求,需要请求者继续执行操作
2**成功,操作被成功接收并处理
3**重定向,需要进一步的操作以完成请求
4**客户端错误,请求包含语法错误或无法完成请求
5**服务器错误,服务器在处理请求的过程中发生了错误

301:永久移动)请求的网页已被永久移动到新位置。服务器返回此响应(作为对GET或HEAD请求的响应)时,会自动将请求者转到新位置。

302:临时移动)服务器目前正从不同位置的网页响应请求,但请求者应继续使用原有位置来进行以后的请求。此代码与响应GET和HEAD请求的301代码类似,会自动将请求者转到不同的位置。


HTTP状态码301与302的区别:

1、它们之间关键区别在,资源是否存在有效性;

2、301资源还在只是换了一个位置,返回的是新位置的内容;

3、302资源暂时失效,返回的是一个临时的代替页上。

sessionstorage localstorage区别

1.生命周期

localStorage的生命周期是永久的,关闭页面或浏览器之后localStorage中的数据也不会消失。localStorage除非主动删除数据,否则数据永远不会消失。

sessionStorage的生命周期是仅在当前会话下有效。sessionStorage引入了一个“浏览器窗口”的概念,sessionStorage是在同源的窗口中始终存在的数据。只要这个浏览器窗口没有关闭,即使刷新页面或者进入同源另一个页面,数据依然存在。但是sessionStorage在关闭了浏览器窗口后就会被销毁。同时独立的打开同一个窗口同一个页面,sessionStorage也是不一样的。


2.存储大小

localStorage和sessionStorage的存储数据大小一般都是:5MB


3.存储位置

localStorage和sessionStorage都保存在客户端,不与服务器进行交互通信


4.存储内容类型

localStorage和sessionStorage只能存储字符串类型,对于复杂的对象可以使用ECMAScript提供的JSON对象的stringify和parse来处理


5.获取方式

localStorage:window.localStorage

sessionStorage:window.sessionStorage


6.应用场景

localStorage:常用于长期登录(+判断用户是否已登录),适合长期保存在本地的数据

sessionStorage:敏感账号一次性登录

浏览器为啥第二次访问就快了

主要原因是这些网站把很多资源都缓存在了本地,浏览器缓存直接使用本地副本来回应请求,而不会产生真实的网络请求,从而节省了时间。同时,DNS 数据也被浏览器缓存了,这又省去了 DNS 查询环节。


DNS 缓存和页面资源缓存这两块数据是会被浏览器缓存的。

1)、DNS 缓存比较简单,它主要就是在浏览器本地把对应的 IP 和域名关联起来。

2)、重点看下浏览器资源缓存,下面是缓存处理的过程:

怎么减少页面加载时间

1、压缩css、js文件

2、合并js、css文件,减少http请求

3、外部js、css文件放在最底下

4、减少dom操作,尽可能用变量替代不必要的dom操作

5、优化图像(格式选择、懒加载等等)

6、使用CDN

7、使用缓存

8、减少 http 请求(合并文件,合并图片)

9、标明高度和宽度

10、网址后加斜杠

11、优化TCP协议

遇到的棘手的问题,完成了什么工作

开放性题目,自由作答。

三、最后

    这套题目,考到的知识点比较细,所以我们在平时学习的时候要多多去挖掘,"蜻蜓点水 "的背后是要深入。

关注我,一起携手进阶


您可能也对以下帖子感兴趣

文章有问题?点此查看未经处理的缓存