前端刷题过程中遇到的重点题记录

前言

我找工作期间遇到的所有前端相关的重点问题,可以说是想找到一个还不错的工作的话,至少以下所有问题都需要会

1.手写深度比较,模拟lodash isEqual

关于深度比较的理解:如果obj1和obj2的属性、值全部相等,但是令他们 = = =的时候,还是返回false,因为他们的地址不同,深度比较就是能对两个地址不同,值相同的对象进行比较,返回true。

function isObject(obj){
    return typeof obj === 'object' && obj !== null;
}

function isEqual(obj1,obj2){
    if(!isObject(obj1)||!isObject(obj2)){
        return obj1 === obj2
    }
    if(obj1 === obj2)  return true;
    const objkey1 = Object.keys(obj1);
    const objkey2 = Object.keys(obj2);
    if(objkey1.length !== objkey2.length) return false;
    for(let key in obj1){
        const re  = isEqual(obj1[key],obj2[key]);
        if(!re){
            return false
        }
    }
    return true;
}

2.数组的pop push unshift shift

pop:删除末尾元素,返回删除的元素
shift:删除首个元素,返回删除的元素
push:末尾添加元素,返回数组长度
unshift:首位添加元素,返回数组长度

纯函数:不改变源数组(没有副作用),返回一个数组。以下是一些纯函数:
some every

const arr = [10,20,30,40];

const arr1 = arr.concat([50,60,70]);//合并数组
const arr2 = arr.map(num => num*10);//对数组中的每个数执行一个新函数,然后返回新数组
const arr3 = arr.filter(num => num >25);//对数组中的每个数执行新函数,返回值为true的数组成新数组
const arr4 = arr.slice(2,4);//切割数组,返回切下来的部分

一些非纯函数:
pop push unshift shift forEach(如果数组的值全是基本数据类型的话就是纯函数,如果数组中还有引用类型的话,那就不是纯函数)
reverse
reduce

3.数组slice和splice的区别

const arr = [10,20,30,40,50];

const arr1 = arr.slice();//不传参类似于深拷贝
const arr2 = arr.slice(1,4);
const arr3 = arr.slice(2);//截取数组下标为2的一直到最后一个
const arr4 = arr.slice(-2); //截取最后两个

//splice 非纯函数
const spliceRes = arr.splice(1,2,'a','b','c');
const spliceRes2 = arr.splice(1,2)
console.log(spliceRes,arr);//[20,30] [10,'a','b','c',40,50]
console.log(spliceRes2);//返回剪掉的部分

4.[10,20,30].map(parseInt)的返回值

const res = [10,20,30].map(parseInt);
console.log(res);//[10,NaN,NaN]

// 等价于
[10,20,30].map((n, index) =>{
    return parseInt(n, index)
})

parseInt的第二个参数如果是0,则以10为基数来解析,如果以0x开头则以16为基数,如果小于2或者大于36,返回NaN.

5.http的八种请求(ajax请求get和post的区别)

在这里插入图片描述
1、OPTIONS
返回服务器针对特定资源所支持的HTTP请求方法,也可以利用向web服务器发送‘*’的请求来测试服务器的功能性
2、HEAD
向服务器索与GET请求相一致的响应,只不过响应体将不会被返回。这一方法可以再不必传输整个响应内容的情况下,就可以获取包含在响应小消息头中的元信息。
3、GET
向特定的资源发出请求。注意:GET方法不应当被用于产生“副作用”的操作中,例如在Web Application中,其中一个原因是GET可能会被网络蜘蛛等随意访问。Loadrunner中对应get请求函数:web_link和web_url
4、POST
向指定资源提交数据进行处理请求(例如提交表单或者上传文件)。数据被包含在请求体中。POST请求可能会导致新的资源的建立和/或已有资源的修改。 Loadrunner中对应POST请求函数:web_submit_data,web_submit_form
5、PUT
向指定资源位置上传其最新内容
6、DELETE
请求服务器删除Request-URL所标识的资源
7、TRACE
回显服务器收到的请求,主要用于测试或诊断
8、CONNECT
HTTP/1.1协议中预留给能够将连接改为管道方式的代理服务器。
注意:
1)方法名称是区分大小写的,当某个请求所针对的资源不支持对应的请求方法的时候,服务器应当返回状态码405(Mothod Not Allowed);当服务器不认识或者不支持对应的请求方法时,应返回状态码501(Not Implemented)。
2)HTTP服务器至少应该实现GET和HEAD/POST方法,其他方法都是可选的,此外除上述方法,特定的HTTP服务器支持扩展自定义的

GET和POST的区别
1.get是从服务器上获取数据,post是向服务器传送数据。

2.get是把参数数据队列加到提交表单的ACTION属性所指的URL中,值和表单内各个字段一一对应,在URL中可以看到。post是通过HTTPpost机制,将表单内各个字段与其内容放置在HTML HEADER内一起传送到ACTION属性所指的URL地址。用户看不到这个过程。

3.对于get方式,服务器端用Request.QueryString获取变量的值,对于post方式,服务器端用Request.Form获取提交的数据。

4.get传送的数据量较小,不能大于2KB。post传送的数据量较大,一般被默认为不受限制。但理论上,IIS4中最大量为80KB,IIS5中为100KB。(这里有看到其他文章介绍get和post的传送数据大小跟各个浏览器、操作系统以及服务器的限制有关)

5.get安全性非常低,post安全性较高。

6.函数call和apply的区别

fn.call(this, p1, p2, p3)
fn.apply(this, arguments)
就是传参方式不同

7.new Object()和Object.create()的区别

{}等同于 new Object(),原型是Object.prototype
object.create(null)没有原型
object.create({…})可以指定原型,传入的参数即为新创建的空对象的原型

8.判断字符串以字母开头,后面字母数字下划线,长度6-30(一些简单的正则表达式)

//邮政编码

/\d{6}/ //\d匹配数字

//小写英文字母

/^[a-z]+$/

//英文字母
/^[a-zA-Z]+$/

//日期格式
/^\d{4}-\d{1,2}-\d{1,2}$/

//用户名(\w 在正则表达式中表示一个“字”(数字,字符,下划线) 
/^[a-zA-Z]\w{5,17}$/ 

//简单的IP地址匹配
/\d+\.\d+\.\d+\.\d+/

//匹配电话号码
/^1[3456789]\d{9}$/

//匹配科学计数法
str.replace(/\B(?=((\d{3})+)$)/g,',')

// aaaa-aaa-bbb转为aaaaAaaBbb
var str2 = str.replace(/-\b\w/g,function(th){
    th = th.slice(1);
    return th.toUpperCase();
})

9.手写字符串trim保证浏览器兼容性

trim就是用于删除字符串两端的空白

 String.prototype.trim = function(){
          return this.replace(/^\s+/,'').replace(/\s+$/,'');
      }

10.如何捕获JS中的异常

//手动捕获
try{
//todo
} catch(ex){
console.error(ex) //手动捕获 catch
}finally {
// todo
}
//自动捕获
window.onerror = function(message, source, lineNum, colNum, error)
//缺点:第一,对跨域的JS,如CDN,不会有详细的报错信息
    // 第二,对于压缩的js,还要配合 sourceMap 反查到未压缩的代码的行、列

11.获取当前页面url参数

1.传统方式,查找location.search
2.新API,URLSearchParams

//传统方式
function  query(name){
    const search = location.search.substr(1); //类似 array.slice,用于去掉问号
    const reg = new RegExp('(^|&)${name}=([^&]*)(&|$)','i')
    const res = search.match(reg);
    if(res == null){
        return null
    }
    return res[2]
}
query('a')

//URLSearchParams
function query(name){
    const search = location.search
    const p = new URLSearchParams(search);
    return p.get(name);
}

console.log(query('a'))

12.手写flatern考虑多层级

function flat(arr){
    const isDeep = arr.some(item => item instanceof Array)
    if(!isDeep){
        return arr
    }

    const res = Array.prototype.concat.apply([],arr);
    //arr作为apply方法的第二个参数,本身是一个数组,数组中的每一个元素(还是数组,即二维数组的第二维)会被作为参数依次传入到concat中,效果等同于[].concat(1, 2, 3, [4, 5, 6], 7, 8, [9, 10])。利用apply方法,我们将单重循环优化为了一行代码
    return flat(res)
}

13.数组去重

//传统方式
function unique(arr){
    const res = [];
    arr.forEach(item => {
        if(res.indexOf(item)<0){
            res.push(item)
        }
    });
    return res
}

//使用set的方式(set无序,不能重复)
function unique(){
    const set  = new Set(arr);
    return [...set];
}

14.介绍RAF requetAnimationFrame

要想动画流畅。更新频率要60帧/s,即16.67ms更新一次视图
setTimeout 要手动控制频率,而RAF浏览器会自动控制
后台标签或隐藏iframe中,RAF会暂停
,而setTimeout依然执行

//3s把宽度从 100px 变为 640px, 即增加540px
//60帧/s, 3s 180帧  一帧变化3px

//setTimeout
let curWidth = 100,
    maxWidth = 640,
    div1 = document.getElementById('div1');

function animate(){
    curWidth = curWidth + 3;
    div1.style.width = curWidth + 'px';
    if(curWidth<maxWidth){
        setTimeout(animate,16.7) //时间需要自己控制
    }
}
animate()

//RAF
function animate(){
    curWidth = curWidth + 3;
    div1.style.width = curWidth + 'px';
    if(curWidth<maxWidth){
        window.requestAnimationFrame(animate);//时间不用自己控制
    }
}
animate()

15.CSS实现动画

1.transition实现
transition的速度属性:linear(匀速)、ease(从慢到快再变慢)、ease-in(慢开始)、ease-out(慢结束)

.div1{
            width: 200px;
            height: 200px;
            background-color: red;
            transition: width 2s linear 0.2s;
        }
        .div1:hover{
            width:400px;
        }

2.framkeys实现

.div1{
            width: 200px;
            height: 200px;
            background-color:red;
            animation: mymove 2s infinite;
        }

        @keyframes mymove{
            0%{width: 0px;}
            50%{width: 200px;}
            100%{width: 400px;}
        }

CSS动画和JS动画做比较:
(1)JS动画:优点:1.JS动画控制能力很强,可以在动画播放过程中对动画进行控制,使其开始或停止。(aminition可以通过aminition-play-state暂停)
2.动画效果比CSS3动画丰富,有些动画只有JS动画才能实现,比如曲线运动,冲击闪烁等。
3.CSS3有兼容性问题,而JS大多时候没有兼容性问题。
缺点:1.JS在浏览器的主线程中运行,而主线程还有其他的js脚本,样式布局,绘制任务等,对其干扰可能导致线程出现阻塞,从而造成丢帧的情况。
2.JS动画代码复杂度高于CSS3动画。

(2)CSS动画:缺点:1.运行过程较弱,无法附加绑定回调函数,CSS3动画只能暂停,不能在动画中寻找一个特定的事件点,不能在半路反转动画,不能变换事件尺度,不能在特定的位置添加回调函数或是绑定回放事件,无进度报告。
2.代码冗长。想用CSS3实现稍微复杂一点的动画,最后CSS代码都会变得特别笨重。
优点:浏览器会对CSS3的动画做一些优化(比如专门新建一个图层用来跑动画)

16.CSS的浮动

浮动就是给元素添加float:xxx,使它脱离文档流。那么为什么有时候需要清除浮动呢?
例如,我们在设置前端样式的时候,如果给父盒子设定高度,后续如果需要向父盒子中间添加内容,那么就需要重新修改父盒子的高度,甚至重新排列其他元素,这样就很麻烦,所以一般不设置父元素高度。
然而父元素不设置高度,子元素浮动的话,就撑不开父元素,会导致其他元素占据父元素的位置,因此需要清除浮动。
清除浮动的几种方法
1额外标签法
在最后一个浮动标签后,新加一个标签,给其设置clear:both:

<div class="clear"></div>
.clear{
  clear:both;
  }

2.给父盒子添加overflow:hidden;触发BFC(块级格式化上下文)
在这里记录一下什么是BFC:
BFC是一个独立的布局环境,其中的元素布局是不受外界的影响,并且在一个BFC中,块盒与行盒(行盒由一行中所有的内联元素所组成)都会垂直的沿着其父元素的边框排列。
W3C对BFC的定义如下:
浮动元素和绝对定位元素,非块级盒子的块级容器(例如 inline-blocks, table-cells, 和 table-captions),以及overflow值不为“visible"
满足以下任意条件之一,即可触发BFC:
1、float的值不是none。
2、position的值不是static或者relative。
3、display的值是inline-block、table-cell、flex、table-caption或者inline-flex
4、overflow的值不是visible

3.使用after伪元素清除浮动(常用)

 .clearfix:after{
            content: "";
            height: 0;
            display: block;
            visibility: hidden;
            clear: both;
        }

4.使用after和before双伪元素清除浮动

 .clearfix:after,.clearfix:before{
            content: "";
            display: table;
        }
        .clearfix:after{
            clear: both;
        }
        .clearfix{
            *zoom: 1;
        }

17.移动端适配

主要目的:在不同的屏幕下,不用缩放也能正常显示整个页面
参考:https://www.jianshu.com/p/b13d811a6a76
https://segmentfault.com/a/1190000019138515
设备像素比(dpr)=物理像素/设备独立像素,devicePixelRatio的值为2,也就是说1个css像素相当于2个物理像素

// 设置理想视口,使得DOM宽度(layout viewport)与屏幕宽度(visual viewport)一样大,DOM文档主宽度即为屏幕宽度,1个CSS像素(1px)由多少设备像素显示由具体设备而不同;
<meta name="viewport" content="width=device-width,user-scalable=no,initial-scale=1.0,maximum-scale=1.0,minimum-scale=1.0">

1.通过媒体查询的方式即CSS3的meida queries
它主要是通过查询设备的宽度来执行不同的 css 代码,最终达到界面的配置。核心语法是:
eg:@media screen and (min-width:350px){
html{font-size:342%;}
}
@media screen and (min-width:350px)表示当移动设备的宽度大于350px的时候页面将使用花括号内的样式,即将html根元素的字号设置为342%

2.flex弹性布局
它的viewport(理想视口)是固定的:<meta name="viewport" content="width=device-width,initial-scale=1,maximum-scale=1,minimum-scale=1.0,user-scalable=no">
高度定死,宽度自适应,元素都采用px做单位。

3.rem + viewport 缩放
这也是淘宝使用的方案,根据屏幕宽度设定 rem 值,需要适配的元素都使用 rem 为单位,不需要适配的元素还是使用 px 为单位。(1em = 16px)
实现原理:根据rem将页面放大dpr倍, 然后viewport设置为1/dpr.

4、vw vh

18.react的生命周期函数

1.数据初始化
getDefaultProps()
getInitialState()
2.页面挂载
componentWillMount() 页面即将挂载的时候——可以修改state
render()
componentDidMount()页面挂载完成
3.数据更新
对于states:
shouldcomponetUpdate() 返回false,则不更新state,返回true,继续
componentWillUpdate()
render()
componentDidUpdate()
4.组件将要销毁时
componentWillUnmount()

对于props,会在一开始,比state多一个componentWillReceive()

19.盒子模型

html中会有很多标签,其实每一个标签都可以看成是一个盒子,每个盒子包括内容(content)、内边距(padding)、边框(border)、外边距(margin)
盒子的总宽高=width+padding+border+margin

box-sizing的用法
告诉浏览器如何计算一个元素的总宽度和总高度,一般情况下是标准盒模型 box-sizing: content-box
如果设置成box-sizing: border-box 属性那就是IE盒模型,此时:
width/height = content + border + padding

20.CSS的权重计算问题

1.important声明的规则
2.内嵌在HTML元素的stylesg属性里面的声明
3.ID选择器声明的规则
4.使用了类选择器、伪元素选择器、伪类选择器的
5.使用了元素选择器
6.只含有一个通用选择器
7.同一类型的选择器遵循就近原则

21.块级元素和行内元素

1.常见的块级元素有h1~h6、p、div、ul、ol、li
特点:1)总是从新行开始
2)高度、行高、内外边距可控
3)宽度默认为容器的百分之百
4)可以容纳内联元素和其他块级元素

2.常见的行内元素a、span、i、del、ins、s、u、b、em
特点:1)和相邻元素在同一行
2)高、宽无效,水平方向的padding和margin有效,垂直方向的无效
3)宽度为它本身内容的宽度
4)只能容纳文本和其他行内元素

3.行内块元素img、input、td
特点:1)和相邻元素在一行 但是之间留有空白
2)宽度为它本身内容的宽度
3)高度、行高、内外边距都可控
行内块元素就是有块级标签的性质,但是在一行中

给行内元素和块级元素设置float的区别就在于,给块级元素设置flaot,块级元素会层叠在父元素的左上角去显示,而行内元素float之后则像是变成了行内块元素,它可以设置自己的宽高和内外边距

22.JS实现每秒打印一个数

for(let i = 0;i<5;i++){
    setTimeout(() =>{
        console.log(i)
    },1000*i)
}

23.判断对象是否为空对象

1.对这个对象进行遍历

for(let i in obj){
    return true
}
return false;

2.使用JSON.stringify()转化为字符串来判断

if(JSON.stringify(obj)=== '{}'){
    return true
}
return false;

3.使用ES6的新属性Object.keys()

if(Object.keys(obj).length === 0){
    return true
}
return false;

24.position的属性

absolute绝对定位,相对最近一个定位属性为非static的父元素的左上角定位
fixed绝对定位,相对浏览器的右上角
relative相对定位,相对他本身正常的位置
static默认值
inherit继承父元素的position

absolute会使元素完全脱离文档流,在文档中不再占位置。
relative不会使元素脱离文档流,它原有的位置保留,即使改变位置也不会占用新的位置

25.元素实现垂直居中的六个办法

1.如果只有一行文字,那就设置文字的lingheight = 父元素的height就行了,text-align:center
2.弹性布局flex,父元素设置display:flex;设置justify-content(水平)和align-items(垂直)的属性为center
3.知道盒子的宽高时:绝对定位+边距。子元素absolute, top和left设置为50%,之后再将margin-top和margin-left设置为自身大小一半的负数,举例如下

box3{
            position: absolute;
            width:100px;
            height: 50px;
            top:50%;
            left:50%;
            margin-left:-50px;
            margin-top:-25px;
        }

4.当不知道盒子的宽高时,弥补3中不足的办法就是:绝对定位+transform

box4{
            position: absolute;
            width:100px;
            height: 50px;
            top:50%;
            left:50%;
            transform: translate(-50%,-50%)
        }

5.绝对定位+margin:auto :将top、right、left、bottom全设为0,再设置 margin:auto就会进行垂直水平居中。(为块区域设置top: 0; left: 0; bottom: 0; right: 0; 将给浏览器重新分配一个边界框,此时该块block将填充其父元素的所有可用空间。)
6,.让父元素变成table-cell

.box6{
    display: table-cell;
    vertical-align: middle;
    text-align: center;        
}

26.实现三列布局(左右固定,中间自适应)

方法一:对左右分别使用float:left和float:right,float使左右两个元素脱离文档流,中间元素正常在正常文档流中。对中间文档流使用margin指定左右外边距进行定位,中间文档流一定要放在最后

方法二:将左右两边使用absolute定位,因为绝对定位使其脱离文档流,后面的middle会自然流动到他们上面,然后使用margin属性,留出左右元素的宽度,既可以使中间元素自适应屏幕宽度。

方法三:使用flex布局(*使用flex布局之后float、clear和vertical-align属性都会失效)
父元素设置display:flex,中间元素设置flex:1,即缩放比例为1,自适应填满所有剩余空间,左右两边正常给值就行

27innerHTML和innerText的区别

1.document.getElementById('box').innerText; 
//获取文本内容(如有html 直接过滤掉)
document.getElementById('box').innerHTML; 
//获取文本(不过滤HTML,有HTML标签将直接显示)
2.document.getElementById('box').innerText ='<div>Mr.Lee</div>'; 
//设置文本(如有html会进行转义)
document.getElementById('box').innerHTML = '<b>123</b>'; 
//可解析成HTML

28.js宽松模式和严格模式区别

如果顶层(不在任何函数体内)代码使用了"use strict" 指令,那么他们就是严格代码。
如果函数体定义所处的代码是严格代码或者函数体使用了"use strict"指令,那么函数体的代码也是严格代码。

严格模式和非严格模式之间的区别如下:
*在严格模式中禁止使用with语句
*在严格模式中,所有的变量都要先声明,如果给一个未声明的变量、函数、函数参数、 catch从句参数或全局对象的属性赋值,将会抛出一个引用错误异常(在非严格模式中,这种隐式声明的全局变量的方法是给全局对象新添加一个新属性)。
*在严格模式中,调用的函数(不是方法)中的一个this值是undefined。(在非严格模式中, 调用的函数中的this值总是全局对象)。
可以利用这种特性来判断JavaScript实现是否支持严格模式:
var hasStrictMode = (function(){“use strict”;retuen this===undefined}());
*同样,在严格模式中,当通过call()或apply()来调用函数中时,其中this值就是通过call()或apply()传入的第一个参数(在非严格模式中,null和undefined值被全局对象和转换为对象的非对象值所替代)
*在严格模式中,给只读属性赋值和给不可扩展的对象创建新成员都将抛出一个类型错误异常(在非严格模式中,这些操作只是简单地操作失败,不会报错)。
*在严格模式中,传入eval()的代码不能在调用程序所在的上下文中声明变量或定义函数,而在非严格模式中是可以这样做的。相反,变量和函数的定义是在eval()创建的新作用域中,这个作用域是在eval()返回时就弃用了。
*在严格模式中,函数里的arguments对象拥有传入函数值的静态副本。在非严格模式中,arguments对象具有“魔术般”的行为,arguments里的数组元素和函数参数都是指向同一个值的引用。
*在严格模式中,当delete运算符后跟随非法的标识符(比如变量、函数、函数参数)时,将会抛出一个语法错误异常(在非严格模式中,这种delete表达式什么也没做,并返回false)。
*在严格模式中,试图删除一个不可配置的属性将抛出一个类型错误异常(在非严格模式中,delete表达式操作失败,并返回false)。
*在严格模式中,在一个对象直接量中定义两个或多个同名属性将产生一个语法错误(在非严格模式下不会报错)
*在严格模式中,函数声明中存在两个或多个同名的参数将产生一个语法错误(在非严格模式中不会报错)
*在严格模式中是不允许使用八进制整数直接量(以0位前缀,而不是0x为前缀)的(在非严格模式中某些实现是允许八进制整数直接量的)
*在严格模式中,标识符eval和arguments当做关键字,它们的值是不能更改的。不能给这些标识符赋值,也不能把它们声明为变量、用做函数名、用做函数参数或用做catch快的标识符。
*在严格模式中限制了对调用栈的检测能力,在严格模式的函数中,arguments.caller和arguments.callee都会抛出一个类型错误异常。严格模式的函数同样具有caller和arguments属性,当访问这两个属性时将抛出类型错误异常(有一些JavaScript的实现在非严格模式里定义了这些非标准的属性)

29.http状态码

100:请求者应该继续提出请求。此状态码表示服务器已经收到请求的第一部分,等待剩余的请求
200:服务器收到请求并正常返回
204:服务器收到请求并正常返回,但是返回的资源里没有响应的主体部分(没有资源可以返回)
206:客户端进行了范围请求(GET),客户端正常处理并返回了这部分资源
301:资源永久重定向,需要使用新的url
302:资源临时重定向
303:资源临时重定向(只能用GET获取资源)
304:协商缓存状态码,服务端成功处理请求,且跟上次请求的资源相比,资源没有改变
400:请求包含语法错误
401:未经许可,需要http认证
403:http认证通过,但没有请求该资源的权限
404:资源未找到
500:服务器处理请求时出现了错误,也可能是web端存在BUG或某些临时错误
503:服务器处于超负荷工作状态或停机维护

30.如何创建一个长度为100,内容为0-99的数组

1.循环,不用多说
2.ES6写法:Array.from(Array(100).keys())

31.将列表子元素的顺序反转

方法一:利用appendChild,但是这种方法会频繁的操作DOM

 let ul = document.getElementById('target');
    let lis = document.getElementsByTagName('li');
    let len = lis.length-1;
    while(len>=0){
        ul.appendChild(lis[len])
        len--;
    }

方法二:使用文档片段

 let ul = document.getElementById('target');
        let lis = document.getElementsByTagName('li');
        let fragment = document.createDocumentFragment();
        for(let i = lis.length-1;i>=0;i--){
            fragment.appendChild(lis[i])
        }
        ul.appendChild(fragment)

32.new 运算符做了哪些工作?

1.创建一个空对象
let obj = Object.create()
2.将新对象的隐式原型指向构造函数的原型对象
obj.__proto__ = Func.prototype;
3.将构造函数的this指向新创建的对象
Func.call(obj)
4.判断构造函数的返回值,如果没有返回值或者返回的是值类型,那就返回新创建的对象,如果返回值为对象类型,那就返回原本的返回值

object.create()是将传入的参数传递给创建对象的隐式原型

手写new

function myNew(Func){
    let obj = Object.create(Func.prototype);
    let arg = [...arguments].slice(1);
    let re = Func.call(obj,...arg);
    return typeof re === 'object' ? re:obj
}

引申:1)创建一个对象的方式 {}、new Object()。这两种方式无法进行传参,创建相似的对象需要写很多重复代码,而且无法判断自定义对象的类型。优点是前者可读性较强,且速度快。
构造函数。这种方式允许传参,且可以判断自定义对象的类型。不过缺点是每 创 建一个对象,都会开辟一个空间,有些公共方法这样做会浪费内存空间。所幸的是原型链的机制解决了这个问题。 Object.create() 此方法将新对象的proto更改并指向create的入参对象。可以接收null为参数,这样 得到的对象并不会继承对象原型。

33.meta标签的作用

1.meta里的数据是供机器解读的,告诉机器该如何解析这个页面
2.还有一个用途是可以添加服务器发送到浏览器的http头部内容,

http-equiv属性是添加http头部内容,对一些自定义的,或者需要额外添加的http头部内容,需要发送到浏览器中,我们就可以是使用这个属性,如:

<meta http-equiv="Refresh" content="5;url=http://blog.yangchen123h.cn" />

第二个可选属性是name,这个属性是供浏览器进行解析,对于一些浏览器兼容性问题,name属性是最常用的,当然有个前提就是浏览器能够解析你写进去的name属性才可以如:

<meta name="viewport" content="width=device-width, initial-scale=1.0">

当有http-equiv或name属性的时候,一定要有content属性对其进行说明

34.html语义化

HTML的语义化总结为: 用最恰当的标签来标记内容
HTML语义化的原因
1.即使在没有CSS样式的条件下,也能很好地呈现出内容结构、代码结构;
2.语义化HTML会使HTML结构变的清晰,有利于维护代码和添加样式;
3.方便其他设备解析(如屏幕阅读器、盲人阅读器、移动设备)以意义的方式来渲染网页;
4.提升搜索引擎优化(SEO)的效果。和搜索引擎建立良好沟通,有助于爬虫抓取更多的有效信息:爬虫依赖于标签来确定上下文和各个关键字的权重;
5.便于团队开发和维护,语义化更具可读性,是下一步把网页的重要动向,遵循W3C标准的团队都遵循这个标准,可以减少差异化。
6.通常语义化HTML会使代码变的更少,使页面加载更快。
常用的语义化标签包括

<header></header>头部
<nav></nav>导航栏
<section></section>区块(有语义化的div)
<main></main>主要区域
<artical></artical>主要内容
<aside></aside>侧边栏
<footer></footer>底部

35.数据结构分为类

共8种:数组、栈、队列、链表、树、散列表、堆、图

36.虚拟DOM

虚拟DOM的步骤
1.获取state中的数据
2.生成JSX模板
3.生成虚拟DOM(本质是一个JS对象)
4.state和JSX结合生成真实DOM
5.state中数据发生改变,生成新的虚拟DOM
6.比对新的虚拟DOM和原来的虚拟DOM,找出区别
7.修改真实DOM,改变区别

Diff算法原理:同层比较,若这一层不同,则下面的子节点全部替换
优点:1)比较两个JS对象,提升性能
2)使跨平台成为可能,react生成虚拟节点后会调用不同的解析库解析,浏览器用react-dom,app用react-native

37.CSS实现三角形

1.实现正三角形

#triangle-up {
    width: 0;
    height: 0;
    border-left: 50px solid transparent;
    border-right: 50px solid transparent;
    border-bottom: 100px solid red;
}

2.实现倒三角形

#triangle-down {
    width: 0;
    height: 0;
    border-left: 50px solid transparent;
    border-right: 50px solid transparent;
    border-top: 100px solid red;
}

38.常见的数据结构及应用

参考这篇博客:https://www.cnblogs.com/zhuochong/p/11630439.html
哈希表:https://blog.csdn.net/u011109881/article/details/80379505(原理)
https://blog.csdn.net/mez_Blog/article/details/103410649(例题)

39.介绍HTTP有什么字段

参考:https://blog.csdn.net/ynd_sg/article/details/82182951

40.TCP的拥塞控制

慢开始,拥塞避免、快重传、快恢复
参考:https://www.cnblogs.com/wuchanming/p/4422779.html

41.实现一个元素在页面中不停地旋转

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
       .div1{
           width:100px;
           height: 100px;
           background-color: red;
           margin: 30px;
       }

       @keyframes myrotate{
           form{
               transform: rotate(0);
           }to{
               transform: rotate(360deg);
           }
       }
       
       .div1:hover{
        animation: myrotate 1.2s linear infinite;
       }
    </style>
</head>
<body>
    <div class="div1"></div>
</body>
</html>

42.animation和transition的区别

1.transtion是过渡,是样式值的变化过程,只有开始和结束。animation其实也叫关键帧,可以结合@keyframe设置每一帧的样式
2.transition必须结合hover或者js代码才能触发,而animation 配合 @keyframe 可以不触发时间就触发这个过程
3.aminition可以设置很多属性,例如循环次数和动画状态,但是transition只能触发一次
4.关于性能方面:涉及到width height position等,animation会引起重排和重绘,但是transition不会引起重排

43.fixed定位在移动端可能出现的问题

解决问题的关键就是:fixed元素内部必须嵌套一个position:absolute元素,用来装载内容,目的就是为了让内容脱离fixed文档流,屏蔽一些fixed的坑

1.fixed定位的容器内不能带有input,这是常见的bug。
解决方法: 在input聚焦的时候去掉fixed定位状态,改为absolute。

2.fixed+可滚动的容器内会导致fixed定位的子元素在滚动时定位失效,滚动完成后才正常回到fixed的位置。
解决方法:尽量不要在可滚动的容器内包含fixed定位的子元素。

3.ios不支持onresize事件

44.px em rem vh vw的理解

px:像素是相对于显示器屏幕分辨率而言的相对长度单位.

em :相对于父元素的单位,父元素的font-size为40px,子元素的font-size为0.5em,那么子元素的font-size为20px

rem:相对于html的根节点

vh:相对于视口高度 ,1vh = 视口高度的1%

vw:相对于视口宽度,1vw = 视口宽度的1%

45.时间复杂度:代表算法运行时间随数据规模增长的趋势,并不代表算法真正的运行时间

46.CDN及其加速原理

CDN的全称是(Content Delivery Network),即内容分发网络。其目的是通过在现有的Internet中增加一层新的CACHE(缓存)层,将网站的内容发布到最接近用户的网络”边缘“的节点,使用户可以就近取得所需的内容,提高用户访问网站的响应速度。从技术上全面解决由于网络带宽小、用户访问量大、网点分布不均等原因,提高用户访问网站的响应速度。
简单的说,CDN的工作原理就是将您源站的资源缓存到位于全球各地的CDN节点上,用户请求资源时,就近返回节点上缓存的资源,而不需要每个用户的请求都回您的源站获取,避免网络拥塞、缓解源站压力,保证用户访问资源的速度和体验
参考:https://www.jianshu.com/p/1dae6e1680ff

47.前端性能优化

1.减少http请求,如:
假设导航栏上有五幅图片,点击每张图片都会进入一个链接,这样五张导航的图片在加载时会产生5个HTTP请求。然而,使用一个图片地图可以提高效率,这样就只需要一个HTTP请求。将所有点击提交到同一个url,同时提交用户点击的x、y坐标,服务器端根据坐标映射响应
2.使用精灵图
3.使用CDN
4.将JS放在底部,减少首屏时间,因为HTML的解析是从上到下的,如果html放在body前面,就会导致先解析JS,后加载DOM树
5.图片懒加载(在图片没有进入可视区域时,先不给<img>的src赋值,这样浏览器就不会发送请求了,等到图片进入可视区域再给src赋值。)具体实现方法:

<img src = './loading.jpg' data-src = './myimg.jpg'>
 window.onload = function(){
            var imgs = document.querySelectorAll('img');
            function getTop(e){
                let T = e.offsetTop;
                while(e = e.offsetParent){
                    T += e.offsetTop;
                }
                return T;
            }
            function lazyLoad(){
                let h = document.documentElement.innerHeight;
                let s = document.documentElement.scrollTop||document.body.scrollTop;
                for(let i =0;i<imgs.length;i++){
                if(h+s>getTop(imgs[i])){
                    imgs[i].src = imgs.getAttribute('data-src');
                }
            }
            }
            window.onscroll = function(){
                lazyLoad(images);
            }
        }

6.浏览器使用缓存:CSS、JavaScript、Logo、图标这些静态资源文件更新的频率都比较低,而这些文件又几乎是每次HTTP请求都需要的,如果将这些文件缓存在浏览器中,可以极好地改善性能
7.减少对DOM的操作
8.尽量使用CSS动画而不是JS动画,因为JS动画会频繁的操作DOM,而且CSS动画不占

48.JSONP

主要还是利用link\img\script不受同源策略限制
参考:https://blog.csdn.net/badmoonc/article/details/82289252

手写JSONP:

var JSONP = function(url,params,callback){
    var querystring = url.indexOf('?') === -1? '?':'&';

    for(let key in params){
        querystring += key + '=' + params[key] + '&';
    }

    let random = Math.random().toString().replace('.','');
    let cbval = 'my_jsonp' + random;
    let cb = 'callback=' +cbval;

    querystring += cb;

    let script = document.createElement('script');
    script.src = url + querystring;
    document.body.appendChild(script);

    window[cbval] = function(params){
        callback(params);
        document.body.removeChild(script)
    }
}

JSONP('www.baidu.com',{query:'贴吧'},function(){console.log(params)})

48.html5新增

参考:https://www.cnblogs.com/binguo666/p/10928907.html

49.BFC

BFC的布局规则

  • 内部的Box会在垂直方向,一个接一个地放置。
  • Box垂直方向的距离由margin决定。属于同一个BFC的两个相邻Box的margin会发生重叠。
  • 每个盒子(块盒与行盒)的margin box的左边,与包含块border box的左边相接触(对于从左往右的格式化,否则相反)。即使存在浮动也是如此。
  • BFC的区域不会与float box重叠
  • BFC就是页面上的一个隔离的独立容器,容器里面的子元素不会影响到外面的元素。反之也如此。
  • 计算BFC的高度时,浮动元素也参与计算。
    - 如何创建BFC
    1、float的值不是none。
    2、position的值不是static或者relative。
    3、display的值是inline-block、table-cell、flex、table-caption或者inline-flex
    4、overflow的值不是visible
    可以解决内边距塌陷的问题:
    边距塌陷:两个相邻的盒子呈现上下级(取margin较大的那个)关系或者是父子(子盒子外边距会加到父盒子上)关系时,外边距不会相加

50.取出两个数组中的不同元素

 function getArrDifference(arr1,arr2){
            return arr1.concat(arr2).filter((i,v,arr) =>{
                return arr.indexOf(i) === arr.lastIndexOf(i);
            })
        }

51.encodeURI()和encodeURIComponent() 区别

参考:https://blog.csdn.net/qq_34629352/article/details/78959707

52.作用域链

在 Javascript 中,作用域分为 全局作用域 和 函数作用域
一般情况下,变量取值到创建 这个变量的函数的作用域中取值。
但是如果在当前作用域中没有查到值,就会向上级作用域去查,直到查到全局作用域,这么一个查找过程形成的链条就叫做作用域链。

53.React中三个方法获取setState更新之后的state

React的setState方法是个异步方法.所以,若是在setState之后立即访问state,往往是不能得到更新之后的state值的
1.利用setTimeout

componentDidMount(){
setTimeout(()=>{
    this.setState({value:this.state.value+1})
    console.log(this.state.value)
},0)

就是把整片代码全部包在setTimeout里面.这样react就会自动强制更新
2.利用setState的回调函数

// setState(updater,[callback])

this.setState(({value}) =>{
    value:value+1,
}),() =>{
    console.log(this.State.value)
})

3.利用promise对方法2进行封装

  setStatePromise(updator) {
    return new Promise( function (resolve,reject){
      this.setState(updator,resolve);
    }.bind(this))
  }
  componentDidMount(){
    this.setStatePromise(({value}) => ({
      value:value+1
    })).then(() => {
      console.log(this.state.value);
    });
  }

三种方法背后的原理
setState是一个异步方法.由队列实现.
它有Batch模式(批量更新模式),和普通模式.
普通模式下,setState能够即时更新state.
Batch模式下,setState会将队列中的state进行合并,然后就会出各种状况.
setTimeout就是一个强制使用普通模式的方法.

54.redux异步实现方案

1.创建store和reducer
2.用connect建立连接
3.去组件中实现请求
connect能够将store中的数据和组件连接起来,其中connect接收两个参数
第一个参数是:mapStateToProps:把store中的数据映射到这个组件变成props,所以如果要取store中的数据就需要通过this.props.参数
第二个参数是:mapDispatchToProps:将store.dispatch方法挂载到props上
读到这里,大家一定不难发现,其实后者是可以改变store中的数据,然后通过第一个方法能够获取到store中改变的数据,既然改变数据,大多是需要一些方法,所以mapDispatchToProps中常常返回一个方法
4.接收store中的数据改变

redux-chunk:可以将dispatch()的参数定义为函数的中间件

55.react-router的几种配置方式

参考:https://blog.csdn.net/weixin_43858880/article/details/90600539

56.Promise中的then第二个参数和catch有什么区别?

reject是promise方法,catch是promise实例方法
1.主要区别就是,如果在then的第一个函数里抛出了异常,后面的catch能捕获到,而then的第二个函数捕获不到
2.then的第二个参数和catch捕获错误信息的时候会就近原则,如果是promise内部报错,reject抛出错误后,then的第二个参数和catch方法都存在的情况下,只有then的第二个参数能捕获到,如果then的第二个参数不存在,则catch方法会捕获到。

57.函数柯里化

函数柯里化是把接受多个参数的函数变换成接受一个单一参数(最初函数的第一个参数)的函数,并且返回接受余下的参数而且返回结果的新函数的技术。
柯里化封装通用方法:

function currying(fn,currArgs){
    return function(){
        let args = [...arguments];

        if(currArgs !== undefined){
            args = args.concat(currArgs);
        }

        if(args.length<fn.length){
            return currying(fn,args)
        }
        return fn.apply(null,args)
    }
}

function sum(a,b,c){
    console.log(a+b+c)
}

const fn = currying(sum);

fn(1,2,3);
fn(1,2)(3);

58.loader和plugin的区别

  1. loader虽然是扩展了 webpack ,但是它只专注于转化文件(transform)这一个领域,完成压缩,打包,语言翻译。
    plugin也是为了扩展webpack的功能,但是 plugin 是作用于webpack本身上的。而且plugin不仅只局限在打包,资源的加载上,它的功能要更加丰富。从打包优化和压缩,到重新定义环境变量,功能强大到可以用来处理各种各样的任务。
    2.loader运行在打包文件之前(loader为在模块加载时的预处理文件) plugins在整个编译周期都起作用。
    plugins的原理:https://www.jianshu.com/p/e21e36d9e00b

59.script标签的defer和async

1.<script src="example.js"></script>
   没有defer或async属性,浏览器会立即加载并执行相应的脚本。也就是说在渲染script标签之后的文档之前,不等待后续加载的文档元素,读到就开始加载和执行,此举会阻塞后续文档的加载;
2.<script async src="example.js"></script>
   有了async属性,表示后续文档的加载和渲染与js脚本的加载和执行是并行进行的,即异步执行;
3.<script defer src="example.js"></script>
有了defer属性,加载后续文档的过程和js脚本的加载(此时仅加载不执行)是并行进行的(异步),js脚本的执行需要等到文档所有元素解析完成之后,DOMContentLoaded事件触发执行之前。

60.手写继承

function Animal(name){
    this.name = name||'Animal';
    this.sleep = function(){
        console.log(this.name+'正在睡觉');
    }
}
Animal.prototype.eat = function(food){
    console.log(this.name+'likes'+food);
}

方法一:原型式继承

function Cat(){
    this.name = 'cat';
}
Cat.prototype =Animal.prototype;

let cat  = new Cat();
console.log(cat.name);//cat
cat.sleep();//报错
cat.eat('fish');//catlikesfish

1.由于是等号赋值,存在共享问题,改变其中一个原型对象上的值,另一个也会改变
2.直接在原型链上继承,只能获得原型对象上的成员。注意,构造函数内部this定义 以及外部原型对象上的成员都是实例属性,可以被实例对象继承。构造函数内部let/var 定义的成员属于私有成员,实例对象继承不了。
方法二:原型链式继承

function Cat(){
    this.name = 'cat';
}

Cat.prototype = new Animal();

let cat  = new Cat();
console.log(cat.name);
cat.sleep();//cat正在睡觉
cat.eat('fish');

解决了方法一中只能获得原型对象上成员的问题,但数据共享还是存在。而且, 无法通过传参给子类成员赋值
方法三:构造函数继承

function Cat(name){
    Animal.call(this,name)
    this.name = name||'cat';
}

let cat  = new Cat();
console.log(cat.name);
cat.sleep();
cat.eat('fish');//报错

好处:解决了前两个方法中的无法传参的问题。 解决了上面数据共享的问题。 可以通过调用多个父类构造函数实现多继承。
坏处:.不能继承父类构造函数原型对象上的成员。 因为没有用到原型,所以每个子类都有父类成员的副本,消耗内存。而且实例并不是父类的实例,只是子类的实例
方法四:组合式继承

function Cat(name){
  Animal.call(this);
  this.name = name || 'Tom';
}
Cat.prototype = new Animal();
var cat = new Cat();
console.log(cat.name);
console.log(cat.sleep());
cat.eat('fish');
console.log(cat instanceof Animal); // true
console.log(cat instanceof Cat); // true

弥补了方式3的缺陷,可以继承实例属性/方法,也可以继承原型属性/方法
既是子类的实例,也是父类的实例
不存在引用属性共享问题
可传参
函数可复用
缺点:调用了两次父类构造函数,生成了两份实例(子类实例将子类原型上的那份屏蔽了)
方法五:寄生式组合继承

function Cat(name){
    Animal.call(this)
    this.name = name||'cat';
}

(function(){
    var Super = function(){};
    Super.prototype = Animal.prototype;
    Cat.prototype = new Super();
})();

let cat  = new Cat();
console.log(cat.name);
cat.sleep();
cat.eat('fish');

通过寄生方式,砍掉父类的实例属性,这样,在调用两次父类的构造的时候,就不会初始化两次实例方法/属性,避免的组合继承的缺点
方法六:ES6的class继承

class parent{
    constructor(a){
        this.fend1 = a;
    }
    fend2 = 2;
    func1 = function(){console.log('parent')}
}

class Child extends parent{
    constructor(a,b){
        super(a);
        this.fend3 = b;
    }
    fend4 = 4;
    func2 = function(){console.log('child')}
}

ES5和ES6继承的区别:
1.ES5的继承实质上是先创建子类的实例对象,然后再将父类的方法添加到this上(Parent.apply(this)).
2.ES6的继承机制完全不同,实质上是先创建父类的实例对象this(所以必须先调用父类的super()方法),然后再用子类的构造函数修改this。
3.ES5的继承时通过原型或构造函数机制来实现。
4.ES6通过class关键字定义类,里面有构造方法,类之间通过extends关键字实现继承。子类必须在constructor方法中调用super方法,否则新建实例报错。因为子类没有自己的this对象,而是继承了父类的this对象,然后对其进行加工。如果不调用super方法,子类得不到this对象。

注意super关键字指代父类的实例,即父类的this对象。
注意:在子类构造函数中,调用super后,才可使用this关键字,否则报错。

61.flex的的各种属性

参考:http://www.ruanyifeng.com/blog/2015/07/flex-grammar.html

62.HTTP content-type

Content-Type(内容类型),一般是指网页中存在的 Content-Type,用于定义网络文件的类型和网页的编码,决定浏览器将以什么形式、什么编码读取这个文件,这就是经常看到一些 PHP 网页点击的结果却是下载一个文件或一张图片的原因。

Content-Type 标头告诉客户端实际返回的内容的内容类型。
格式:

Content-Type: text/html; charset=utf-8
Content-Type: multipart/form-data; boundary=something

63.await和async

async 返回的是一个Promise对象
await 是在async内部使用的,await 后面接的是一个Promise对象,但await 执行时,async 会暂停执行,直到Promise状态为resolved

function 摇色子(){
    return new Promise((resolve, reject)=>{
        let sino = parseInt(Math.random() * 6 +1)
        setTimeout(()=>{
            resolve(sino)
        },3000)
    })
}
async function test(){
    let n =await 摇色子()
    console.log(n)
}
test()

上面这段代码async中使await 摇色子()先执行,等到三秒后执行完再把得到的结果赋值给左边的n,也就是说test函数需要三秒钟才执行完成,所以test函数是异步的,因此前面必须写async

如果不是 promise , await会阻塞后面的代码,先执行async外面的同步代码,同步代码执行完,再回到async内部,把这个非promise的东西,作为 await表达式的结果。
如果它等到的是一个 promise 对象,await 也会暂停async后面的代码,先执行async外面的同步代码,等着 Promise 对象 fulfilled,然后把 resolve 的参数作为 await 表达式的运算结果。

function fn(){
    return new Promise(resolve=>{
        console.log(1)
    })
}
async function f1(){
    await fn()
    console.log(2)
}
f1()
console.log(3)
//1
//3

这个代码因为fn是属于同步的,所以先打印出1,然后是3,但是因为没有resolve结果,所以await拿不到值,因此不会打印2

await和async的作用
在没有await的情况下使用async,它会立即执行,返回一个promise对象,并且不会阻塞后面的语句,那就和普通的返回promise对象没有什么区别
加上await之后就可以阻塞后面的代码,相当于用同步的思维去处理异步的代码

64手写instanceof和indexof

instanceOf:

function myInstanceOf(L,R){
    if(typeof L !== 'Object'){
        return false;
    }
    L = L.__proto__;
    let Rp = R.prototype;
    while(true){
        if(L == null){
            return false
        }
        if(L === Rp){
            return true
        }
        L = L.__proto__;
    }
}

手写indexOf:

String.prototype.myIndexOf = function(data){
    let str = this;
    let flag;
    for(let i = 0;i<str.length;i++){
        if(data.charAt(0) === str.charAt(i)){
            let t = 1,j = i+1;
            while(t<data.length){
                if(data.charAt(t) !== str.charAt(j)){
                    flag = null;
                    break;
                }else{
                    flag = i;
                }
                t++;
                j++;
            }
            if(flag) return flag;
        }  
    }
    return -1;
}

65.React获取真实DOM的方法

1.通过在标签中添加ref属性

class Index extends Component {
  onClick(event){
      const inputDom = this.refs.submit;
      console.log(inputDom);
  }
  render(){
    return (
        <div>
          <input ref='submit' type='button' value='getDom' onClick={this.onClick.bind(this)}/>
        </div>
    )
  }

通过this.refs.submit来获取input

2.在标签中写入一个匿名函数

class Input extends Component {
 
  componentDidMount() {
    console.log(this.textInput);
  }
 
  render() {
    return (
      <input
        type="text"
        ref={input => this.textInput = input}
      />
    );
  }

通过this.textInput来获取
3.在标签中加入一个回调函数

class CustomTextInput extends Component {
 
  constructor(props) {
    super(props);
    this.textInput = React.createRef();
  }
 
  render() {
    return (
      <input
        type="text"
        ref={this.textInput}
      />
    );

66.使元素消失的方法有哪些

1 opacity:0,该元素隐藏起来了,但不会改变页面布局,并且,如果该元素已经绑定一些事件,如click事件,那么点击该区域,也能触发点击事件的
2 visibility:hidden,该元素隐藏起来了,但不会改变页面布局,但是不会触发该元素已经绑定的事件
3 display:none,把元素隐藏起来,并且会改变页面布局,可以理解成在页面中把该元素删除掉。

67.cookie有哪些字段可以设置

name:设置cookie的名称
domain:设置cookie的域名
value:cookie的值
path:设置对应域名下的路径
expiers/Max-Age:设置cookie的失效时间,不设置的话默认为session,也就是关闭浏览器的时候跟session一起失效
httpOlny:设置是否允许JavaScript操作cookie
secure:设置是否只能通过https传递此条cookie

68.react的hooks

参考:https://www.jianshu.com/p/76901410645a
react hooks是react 16.8引入的新特性,它允许在不写class的情况下,操作state和其他特性

import React, { useState  } from 'react';
 
function Example() {
    // 声明一个名为“count”的新状态变量
    const [count, setCount] = useState(0);
 
    return (
        <div>
            <p>You clicked {count} times</p>
            <button onClick={() => setCount(count + 1)}>
                Click me
            </button>
        </div>
    );
}
 
export default Example;

1.语法:const [state, setState] = useState(initialState)

  • 传入唯一的参数: initialState,可以是数字,字符串等,也可以是对象或者数组。
  • 返回的是包含两个元素的数组:第一个元素,state 变量,setState 修改 state值的方法。

与在类中使用 setState 的异同点:

  • 相同点:也是异步的,例如在 onClick 事件中,调用两次 setState,数据只改变一次。
  • 不同点:类中的 setState 是合并,而函数组件中的 setState 是替换。

2.useEffect(() => { doSomething });
两个参数:

第一个是一个函数,是在第一次渲染以及之后更新渲染之后会进行的副作用。

这个函数可能会有返回值,倘若有返回值,返回值也必须是一个函数,会在组件被销毁时执行。
第二个参数是可选的,是一个数组,数组中存放的是第一个函数中使用的某些副作用属性。用来优化 useEffect

如果使用此优化,请确保该数组包含外部作用域中随时间变化且 effect 使用的任何值。 否则,您的代码将引用先前渲染中的旧值。
如果要运行 effect 并仅将其清理一次(在装载和卸载时),则可以将空数组([])作为第二个参数传递。 这告诉React你的 effect 不依赖于来自 props 或 state 的任何值,所以它永远不需要重新运行。

69.react-router的实现原理

实现URL与UI界面的同步。其中在react-router中,URL对应Location对象,而UI是由react components来决定的,这样就转变成location与components之间的同步问题.

以browserHistory(一种history类型:一个 history 知道如何去监听浏览器地址栏的变化, 并解析这个 URL 转化为 location 对象)为例:
在这里插入图片描述

参考:https://www.jianshu.com/p/d991a4a55ae1

70.手写promise,promise.all,promise.race

function promise(exector){
    let self = this;
    this.status = 'pending';
    this.value = undefined;
    this.reason = undifined;
    this.onfulfilledcallback = [];
    this.onrejectedcallback = [];
    let resolve = (value)=>{
        if(this.status == 'pending'){
            this.status == 'fulfilled'
            this.value = value;
            this.onfulfilledcallback.forEach(fn => fn())
        }
    }
    let reject =  (value)=>{
        if(this.status == 'pending'){
            this.status == 'rejected'
                this.reason = reason;
                this.onrejectedcallback.forEach(fn => fn())
       }
    }
    try{
        exector(resolve,reject)
    }catch(e){
        reject(e)
    }
}

promise.prototype.then = function(onresolved,onrejected){
    if(this.status == 'fulfilled'){
        onresolved(this.value)
    }else if(this.status == 'rejected'){
        onrejected(this.reason)
    }else if(this.status === 'pending'){
        this.onfulfilledcallback.push(() =>{
            onresolved(this.value)
        })
        this.onrejectedcallback.push(() =>{
            onrejected(this.reason)
        })
    }
}

function all(promises){
    return new Promise((resolve,reject) =>{
        let res =  [];
        let index;
        if(promises.length === 0){
            resolve(res)
        }else{
            for(let i = o;i<promises.length;i++){
                Promise.resolve(promises[i]).then(data =>{
                    res.push(data);
                    index++;
                    if(index === promises.length){
                        resolve(res)
                    }
                },err =>{
                    reject(err);
                    return;
                })
            }
        }
    })
}
myPromise.prototype.race = function(promises){
    return new myPromise((resolve,reject) =>{
        promises.forEach((promise) =>{
            myPromise.resolve(promise).then((data) =>{
                resolve(data)
            },err =>{
                reject(err);
            })
        })
    })
}

71.cookie和locastorage和session的区别

参考:https://www.cnblogs.com/jing-tian/p/10991431.html
cookie和session的区别:
1、cookie数据存放在客户的浏览器上,session数据放在服务器上
2、cookie不是很安全,别人可以分析存放在本地的cookie并进行cookie欺骗,考虑到安全应当使用session
3、session会在一定时间内保存在服务器上,当访问增多,会比较占用你服务器的性能,考虑到减轻服务器性能方面,应当使用cookie
4、单个cookie保存的数*据不能超过4K,很多浏览器都限制一个站点最多保存20个cookie
5、建议将登录信息等重要信息存放为session,其他信息如果需要保留,可以放在cookie中
6、session保存在服务器,客户端不知道其中的信心;cookie保存在客户端,服务器能够知道其中的信息
7、session中保存的是对象,cookie中保存的是字符串
8、session不能区分路径,同一个用户在访问一个网站期间,所有的session在任何一个地方都可以访问到,而cookie中如果设置了路径参数,那么同一个网站中不同路径下的cookie互相是访问不到的。
9、COOKIE:是服务端向客户端写入的小的片段信息。cookie信息保存在服务器缓存区,不会在客户端显现。当你第一次登陆一个网站,服务器向你的机器写得片段信息。你可以在Internet选项中找到存放cookie的文件夹。如果不删除,cookie就一直在这个文件夹中。
10、session需要借助cookie才能正常工作。如果客户端完全禁止cookie,session将失效。 但是如果服务器端启用了url编码,也就是用 URLEncoder.encode()把所有的url编码了,则会在url后面出现如下类似的东西 index.jsp:jsessionid=fdsaffjdlks;jaf;lkdjsf 服务器通过这个进行session的判断.
11.Cookie支持跨域名访问,例如将domain属性设置为“.biaodianfu.com”,则以“.biaodianfu.com”为后缀的一切域名均能够访问该Cookie。跨域名Cookie如今被普遍用在网络中,例如Google、Baidu、Sina等,而Session则不会支持跨域名访问。Session仅在他所在的域名内有效。仅运用Cookie或者仅运用Session可能完成不了理想的效果。这时应该尝试一下同时运用Cookie与Session。Cookie与Session的搭配运用在实践项目中会完成很多意想不到的效果。

三、web Storage和Cookie的区别

72.defineProperty

let obj = {
    a: 1,
}

Object.defineProperty(obj,'b',{
    value:2,
    // writable: true,
    enumerable: false,
})

console.log(obj);
obj.b = 3;
console.log(Object.keys(obj));

1、简单点就是 设置属性的值value,
2、writable 给的说明是如果设置为 false, 不可以采用 数据运算符 进行赋值
3、configurable 给的说明是 如果为 false , 那么不可以修改, 不可以删除.
4、是否可枚举enumerable

73.addEventListener和click的区别

1.onclick不能对事件捕获或事件冒泡进行控制,只能使用事件冒泡,无法切换成事件捕获
而addEventListener可以通过第三个参数true(事件捕获)或者false(事件冒泡)来切换
事件捕获阶段的话就会先触发ul上的事件,再触发li上的事件。事件冒泡阶段的话则相反。
2.解除事件绑定
对于onclick,直接 dd.onclick = null;
对于addEventListener则需要,Element.removeEventListener(sEvent,fnHandler,false);
3.onclick一次只能对一个元素绑定一个处理程序,后面如果再用onclick绑定了相同的元素,原来的事件会被覆盖
addEventListener可以为某个元素绑定多个事件而不会覆盖之前绑定的处理程序 (按照顺序执行)

74.typeof原理

变量类型是以二进制存储在计算机中的, 在 JavaScript 中二进制前三位都为 0 的话会被判断为 object 类型, null 的二进制表示是全 0, 自然前三位也是 0, 所以执行 typeof 时会返回“object”。
000:对象
1:整数
010:浮点数
100:字符串
110:布尔

75.input标签的type值举例

1.checkbox 定义复选框
2.radio 定义单选按钮
3.button 定义可点击按钮
4.hidden 定义隐藏的输入字段
5.image 定义图像形式的提交按钮
6.password 定义密码字段
7.reset 定义重置按钮
8.submit 定义提交按钮
9.text 定义单行的输入字段,用户可在其中输入文本

76.DOM本身的API

1.页面修改API:
appendChild,removeChild,insertBefore,replaceChild
2.节点查询型API总结
document.getElementById
document.getElementByName
document.getElementByTagName
document.getElementByClassName
3.节点关系型API
parenetNode
childNodes
children(子节点都是element)
4.元素属性API
getAttribute
setAtrribute
5.插入型API
innerHTML
innerText

77.CSS设置透明度的方法

1.opacity:0.5
值越高,透明度越低。会改变当前节点和其所有子节点的透明度
2.rgba(0,0,0,0.5)
选择器匹配到的节点,当且仅当匹配到的节点,不包括其孩子节点,透明度为50%,(0,0,0)表黑色,而(255,255,255)表白色。

78.响应式布局的实现方式

参考:https://www.cnblogs.com/lanhuo666/p/10697104.html

79.如何设置一个宽高呈百分比的盒子

   <style>
    .container{ 
       width:200px;
       position:relative;
       display: inline-block; /*触发BFC防止边距塌陷 */
       border: 1px solid red;
    }
    .dummy{
       margin-bottom: 100%;
    }
    .content{
       position:absolute;
       left:0;
       right:0;
       top:0;
       bottom: 0;
    }
    </style>
</head>
<body>
    <div class='container'>
        <div class='dummy'>
        </div>
        <div class="content">
            content<br/>
            content<br/>
            content<br/>
        </div>
    </div>

主要是利用margin写为百分比的时候,这个百分比的值是按父元素的宽度来算的

80.null和undefined的区别

  • null表示没有对象,即该处不应该有值
    1) 作为函数的参数,表示该函数的参数不是对象
    2) 作为对象原型链的终点

  • undefined表示缺少值,即此处应该有值,但没有定义
    1)定义了形参,没有传实参,显示undefined
    2)对象属性名不存在时,显示undefined
    3)函数没有写返回值,即没有写return,拿到的是undefined
    4)写了return,但没有赋值,拿到的是undefined

  • null和undefined转换成number数据类型
    null 默认转成 0
    undefined 默认转成 NaN

81.DOM节点类型

1.元素节点
nodeName: 元素节点的名称大写,eg:DIV(大写)
nodeType:1
nodeValue:null
2.属性节点
nodeName: 属性名
nodeType:2
nodeValue:属性值
3.文本节点(也就是插入在元素节点中的文字)
nodeName: 选择器名
nodeType:3
nodeValue:文本内容
4.注释节点
nodeName: ‘#comment’
nodeType:8
nodeValue:注释内容
5.文档节点(指向document对象)
nodeName: ‘#document’
nodeType:9
nodeValue:null
6.文档类型节点(文档的doctype有关的所有信息)
nodeName: html
nodeType:10
nodeValue:null

82.前端路由的原理

参考:https://www.cnblogs.com/tugenhua0707/p/10859214.html(hash和history)
参考2:https://www.cnblogs.com/lguow/p/10921564.html(前端路由原理)
history404的解决办法:
https://blog.csdn.net/localhost_8000/article/details/90368839

hash是URL中带#号的部分,改变 URL 中的 hash 部分不会引起页面刷新

通过 hashchange 事件监听 URL 的变化,改变 URL 的方式只有这几种:通过浏览器前进后退改变 URL、通过<a>标签改变 URL、通过window.location改变URL,这几种情况改变 URL 都会触发 hashchange 事件

history 提供了 pushState 和 replaceState 两个方法,这两个方法改变 URL 的 path 部分不会引起页面刷新

history 提供类似 hashchange 事件的 popstate 事件,但 popstate 事件有些不同:通过浏览器前进后退改变 URL 时会触发 popstate 事件,通过pushState/replaceState或<a>标签改变 URL 不会触发 popstate 事件。好在我们可以拦截 pushState/replaceState的调用和<a>标签的点击事件来检测 URL 变化,所以监听 URL 变化可以实现,只是没有 hashchange 那么方便。

83.网站seo

参考:https://www.jianshu.com/p/6d1879cd84e1

seo即搜索引擎优化,简单地说就是总结搜索引擎的排名规律,是网站更符合百度、谷歌等搜索引擎的‘蜘蛛’,从而让他抓取你网站的连接地址。

84.Node事件循环

参考:https://blog.csdn.net/u013055396/article/details/79689706

Node 只有一个主线程,事件循环是在主线程上完成的。开始执行脚本时,会先进行事件循环的初始化,但是这时事件循环还没有开始,会先完成下面的事情:
同步任务、发出异步请求、规划定时器生效的时间、执行process.nextTick()等等。最后,上面这些事情都干完了,事件循环就正式开始了。事件循环会无限
次地执行,一轮又一轮。只有异步任务的回调函数队列清空了,才会停止执行。每一轮的事件循环,分成六个阶段,这些阶段会依次执行:
每个阶段都有一个先进先出的回调函数队列。只有一个阶段的回调函数队列清空了,该执行的回调函数都执行了,事件循环才会进入下一个阶段。简单介绍一下
每个阶段的含义:
(1)timers:这个是定时器阶段,处理setTimeout()和setInterval()的回调函数。进入这个阶段后,主线程会检查一下当前时间,是否满足定时器的条件。
如果满足就执行回调函数,否则就离开这个阶段。
(2)I/O callbacks:除了举出的这些操作回调函数,其他的回调函数都在这个阶段执行:setTimeout() 和 setInterval() 的回调函数、
setImmediate() 的回调函数、用于关闭请求的回调函数,比如 socket.on(‘close’, …)
(3)idle, prepare:该阶段只供 libuv 内部调用,这里可以忽略。
(4)Poll:这个阶段是轮询时间,用于等待还未返回的 I/O 事件,比如服务器的回应、用户移动鼠标等等。这个阶段的时间会比较长。如果没有其他异步任
务要处理(比如到期的定时器),会一直停留在这个阶段,等待 I/O 请求返回结果。
(5)check:该阶段执行 setImmediate() 的回调函数。
(6)close callbacks:该阶段执行关闭请求的回调函数,比如 socket.on(‘close’, …)。

和浏览器事件循环的区别
浏览器环境下,microtask 的任务队列是每个 macrotask 执行完之后执行。而在 Node.js 中,microtask 会在事件循环的各个阶段之间执行,也就是一个阶段执行完毕,就会去执行 microtask 队列的任务。

  • 3
    点赞
  • 0
    评论
  • 27
    收藏
  • 一键三连
    一键三连
  • 扫一扫,分享海报

©️2021 CSDN 皮肤主题: 1024 设计师:白松林 返回首页
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值