面试题(更新中)

HTTP协议各版本差异以及图示_http协议版本_阿汤哥的程序之路的博客-CSDN博客

Vue3 性能比Vue2好的原因(diff算法优化、静态提升、事件侦听器缓存)

在Vue2.0当中,当数据发生变化,它就会新生成一个DOM树,并和之前的DOM树进行比较,找到不同的节点然后更新。但这比较的过程是全量的比较,也就是每个节点都会彼此比较。但其中很显然的是,有些节点中的内容是不会发生改变的,那我们对其进行比较就肯定消耗了时间。所以在Vue3.0当中,就对这部分内容进行了优化:在创建虚拟DOM树的时候,会根据DOM中的内容会不会发生变化,添加一个静态标记。那么之后在与上次虚拟节点进行对比的时候,就只会对比这些带有静态标记的节点。

静态提升 hoistStatic
Vue3中使用了静态提升后,对于不参与更新的元素,只会被创建一次,在渲染时直接复用即可:

事件侦听器缓存 cacheHandlers

默认情况下onClick会被视为动态绑定,所以每次都会去追踪它的变化,但是因为是同一个函数,所以没必要去追踪它的变化,想办法将它直接缓存起来复用就会提升性能。

继承的多方式:

原型链继承:

prototype 

问题:引用类型的属性被所有实例共享

构造函数:

function Parent (name) {
    this.name = name;
}

function Child (name) {
    Parent.call(this, name);
}
var child1 = new Child('kevin');

优点:

1.避免了引用类型的属性被所有实例共享

2.可以在 Child 中向 Parent 传参

缺点:

方法都在构造函数中定义,每次创建实例都会创建一遍方法

组合继承:

原型链继承和构造函数继承结合

原型式继承

function createObj(o) {
    function F(){}
    F.prototype = o;
    return new F();
}

缺点:

包含引用类型的属性值始终都会共享相应的值,这点跟原型链继承一样。

寄生式继承

function createObj (o) {
    var clone = Object.create(o);
    clone.sayName = function () {
        console.log('hi');
    }
    return clone;
}

寄生组合式继承

虚拟dom中key的作用:

key是dom的标识,当状态中的数据发生变化,react会根据[新数据生成新的虚拟DOM] 随后React进行[新虚拟DOM]与[旧虚拟DOM]的diff比较,比较规则如下:

旧虚拟DOM中找到了与新虚拟DOM相同的key:

(1).若虚拟DOM中内容没变。直接使用之前的真实DOM

(2).若虚拟DOM中内容变了,则生成新的真实DOM,随后替换掉页面中之前的真实DOM

旧虚拟DOM中未找到与新虚拟DOM相同的key

根据数据创建新的真实DOM,随后渲染到到页面

用index作为key可能会引发的问题:

1. 若对数据进行:逆序添加、逆序刷除等破坏顺序操作:会产生没有必要的真实DOM更新==>界面效果没问题,但效率低。

2. 如果结构中还包含输入类.....  会产生错误DOM更新==>界面有问题。

3.最好使用每条数据的唯一. 标识作为key。

本地存储(存储token):

http是无状态的,那么就没办法记录用户的状态,比如是否登录。

token:对用户名密码加密得到的

本地存储不能跨域传递

本地存储任一页面都能取值

本地存储不能存对象(转字符串)

sessionStorage(5M):

  • sessionStorage.setItem("token","123456") 存值
  • console.log(sessionStorage.getItem("token"))取值
  • localStorage.removeItem("token") 删除
  • localStorage.clear()
  • 浏览器关闭,取消

localStorage(5M):

  • localStorage.setItem("token","123456")
  • console.log(sessionStorage.getItem("token"))
  • sessionStorage.removeItem("token")
  • sessionStorage.clear()
  • 永久有效,除非自己主动清除localStorage信息。

cookie(4K):

session

  • session是保存在服务端的
  • session的运行依赖sessionId,而sessionId又保存在cookie中,所以如果禁用的cookie,session也是不能用的,不过硬要用也可以,可以把sessionId保存在URL中
  • session一般用来跟踪用户的状态
  • session 的安全性更高,保存在服务端,不过一般为使服务端性能更加,会考虑部分信息保存在cookie中
     

Vue的性能优化有哪些

  1. 尽量减少data中的数据,data中的数据都会增加getter和setter,会收集对应的watcher
  2. v-if和v-for不能连用
  3. 如果需要使用v-for给每项元素绑定事件时使用事件代理
  4. SPA 页面采用keep-alive缓存组件
  5. key保证唯一
  6. 使用路由懒加载、异步组件
  7. 防抖、节流
  8. 第三方模块按需导入
  9. 图片懒加载<img v-lazy="/static/img/1.png">
  10. 变量本地化const base = this.base // 不要频繁引用this.base

BFC 原理

具有 BFC 特性的元素可以看作是隔离了的独立容器,容器里面的元素不会在布局上影响到外面的元素

触发 BFC

  • body 根元素
  • 浮动元素:float 除 none 以外的值
  • 绝对定位元素:position (absolute、fixed)
  • display 为 inline-block、table-cells、flex
  • overflow 除了 visible 以外的值 (hidden、auto、scroll)

同一个 BFC 下外边距会发生折叠

BFC 可以包含浮动的元素(清除浮动)

BFC 可以阻止元素被浮动元素覆盖

[] == ! [] 的结果为什么会是true

js中的两等于,⼀定是先进⾏类型转换,然后再⽐较。
1. null == undefined 
2. 如果有⼀个操作数是 NaN ,则相等操作符返回 false ,⽽不相等操作符返回 true。
3. 如果两个操作数都是对象,指向同⼀个对象,则相等操作符返回 true ;否则, 返回 false
完整分析流程
①、!的优先级是⼤于 ==       ! [] -->f alse
②、如果有⼀个操作数是布尔值,先将其转换为数值 false转换为 0 ,⽽ true 转换为 1 相当于 [] == 0
③、如果⼀个操作数是对象,另⼀个操作数不是,则调⽤对象的valueOf()⽅法,如果对象没有 valueOf() ⽅法,则调⽤ toString(), [].toString() -> '', '' == 0
④、如果⼀个操作数是字符串,另⼀个操作数是数值,在⽐较相等性之前 先将字符串转换为数值) Number('') -> 返回的是 0 

js数组的reduce

计算数组中每个元素出现的次数

let arr = ['name', 'age', 'long', 'short', 'long', 'name', 'name']
        let arrResult = arr.reduce((pre, cur) => {
            console.log(pre, cur)
            if (cur in pre) {
                pre[cur]++
            } else {
                pre[cur] = 1
            }
            return pre
        }, {})
        console.log(arrResult)

去除数组中重复的元素

 let arrResult = arr.reduce((pre, cur) => {
            if (!pre.includes(cur)) {
                pre.push(cur)
            }
            return pre;
        }, [])
        console.log(arrResult)

盒模型

css的 每个盒模型有内容 content ,填充 padding ,边框 border ,外边距 margin 组成
css 盒模型有两种, IE 盒模型和 w3c 标准盒模型,
其中 IE 模型的 width=content+padding+border,
⽽标准盒模型 width=content
margin 是⾃身容器边框到另⼀个容器容器边框的距离,就是容器的外边距
padding 是⾃身容器边框到⾃身内容之间的距离,是为内边距
box-sizing:border-box(标准和盒模型-->IE盒模型)

如何实现元素居中

//第一种
position: absolute;
top: 0;
bottom: 0;
left: 0;
right: 0;
margin: auto;

//第二种
display: flex;
align-items: center;
flex-direction: column


//第三种
//给父元素添加 position: relative;相对定位。
//给自身元素添加position: absolute;绝对定位。
//top: 50%;使自身元素距离上方“父元素的50%高度”的高度。
//left: 50%;使自身元素距离上方“父元素的50%宽度”的宽度。
//transform: translate(-50%,-50%);使自身元素再往左,往上平移自身元素的50%宽度和高度。
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%,-50%);

垂直居中

1. verticle-align:middle 元素的 display inline-block。
2.display:flex ⽗元素 display:flex; ⽽⼦元素 align-self:center;
3.line-height
4.绝对定位百分⽐加 margin负数
5.绝对定位百分⽐加transform: translateY(-50%)

水平居中:

text-align: center; 

margin: 0 auto; 

left:50%;margin-left: -元素宽度的一半px; 或者设置transform: translateX(-50%);

display: flex; justify-content: center;

三种减低⻚⾯加载时间的⽅法

1. 压缩 css js ⽂件
2. 合并 js css ⽂件,减少 http 请求
3. 外部 js css ⽂件放在最底下
4. 减少 dom 操作,尽可能⽤变量替代不必要的 dom 操作

for in 循环和for of循环的区别

for-in是ES5标准,遍历的是key(可遍历对象、数组或字符串的key);
for-of是ES6标准,遍历的是value(可遍历对象、数组或字符串的value)

事件委托/事件代理

利用事件的冒泡传播机制(触发当前元素的某一个行为,它父级所有元素的相关行为都会被触发),如果一个容器中有很多元素都要绑定点击事件,我们没有必要一个个的绑定了,只需要给最外层容器绑定一个点击事件即可

线程和进程

线程是最小的执行单元,进程是最小的资源管理单元
一个线程只能属于一个进程,而一个进程可以有多个线程,但至少有一个线程(一般情况)
一个进程对应多个线程最为常见,Linux、Windows等是这么实现的.其实理论上这种关系并不是一定的,可以存在多个进程对应一个线程,例如一些分布式操作系统的研究使用过这种方式,让线程能从一个地址空间转移到另一个地址空间,甚至跨机器调用不同的进程入口

如何实现数组扁平化

什么是数组扁平化?
[‘a’,‘b’,‘c’] //这是一个拥有3个元素的数组,是一个一维数组(不存在数组嵌套)。[[‘a’,‘b’],[‘c’,‘d’],[‘e’,‘f’]] 从整体上看是一个数组,但是其中的元素又是数组,即数组中嵌套数组,这就是二维数组
以此类推·····
[‘a’,[‘b’,[‘c’]]]//3维数组 [‘a’,[‘b’,[‘c’,[…]]]]//n维数组 数组扁平化就是把多维数组转化成一维数组。
通过es5递归实现

let result = [];
 function fn(ary) {
    for(let i = 0; i < ary.length; i++) }{
    let item = ary[i];
    if (Array.isArray(ary[i])){
    fn(item);
    } else {
        result.push(item);
        }
    }
}

es6 +reduce+递归实现

let arr=[[1,2,3],4,5,[6,7,[8,9]]];
function bianping(arr){
    return arr.reduce((res,item) =>{
        return res.concat(Array.isArray(item)?bianping(item):item)
    },[])
}
console.log(bianping(arr));

js中的深拷贝和浅拷贝

深拷贝递归地复制新对象中的所有值或属性,而浅拷贝只复制引用关系。
在深拷贝中,新对象中的更改不会影响原始对象,而在浅拷贝中,新对象中的更改,原始对象中也会跟着改。
在深拷贝中,原始对象不与新对象共享相同的属性,而在浅拷贝中,它们具有相同的属性。
slice方法和concat方法可以实现普通数组的深赋值,但是如果是二维数组就无法深复制object.assigin() //该方法在只有一层时,进行的是深拷贝

下面这个例子证明slice无法真正实现深复制

var arr1=[1,2,3,['1','2','3']];
var arr2=arr1.slice(0);
 arr1[3][0]=0;
 console.log(arr1);//[1,2,3,['0','2','3']]
 console.log(arr2);//[1,2,3,['0','2','3']]

如何实现深拷贝:

1.JSON.stringfy JSON.parse

var arr1 = ['red','green'];
var arr2 = JSON.parse(JSON.stringify(arr1));//复制
console.log(arr2)//['red','green'];
arr1.push('black') ;//改变color1的值
console.log(arr2)//["red", "green"]
console.log(arr1)//["red", "green", "black"]

2.递归

function deepClone(obj){
    //判断参数是不是一个对象
    let objClone = obj instanceof Object?{}:[];
    if(obj && typeof obj==="object"){
        for(key in obj){
            if(obj.hasOwnProperty(key)){
                //判断ojb子元素是否为对象,如果是,递归复制
                if(obj[key]&&typeof obj[key] ==="object"){
                    objClone[key] = deepClone(obj[key]);
                }else{
                    //如果不是,简单复制
                    objClone[key] = obj[key];
                }
            }
        }
    }
    return objClone;
}    
var a ={
    x:1,
    y:2
};
b=deepClone(a);
a.x=3
console.log(a);
console.log(b);

3.ES6扩展运算符

4.jqery里面的extend方法:

var b = $.extend(true, {}, a);

// 第一个参数true为深拷贝,第二个参数为目标对象,第三个参数为源对象

JS是单线程的,那么JS是如何实现并发请求的?

因为有消息队列和事件循环的存在。

消息队列指的是一个先进先出的队列,在这个队列中可以存在各种消息。

事件循环指的是主线程重复从消息队列中获取消息、执行的过程。

js中的event loop(事件循环)

js作为单线程语言。所有的任务可以分为两种,一种是同步任务,另外一种是异步任务。

同步任务指的是,在主线程上,排队执行的任务,只有前一个任务执行完毕,才能执行后一个任务;

异步任务指的是,不进入主线程,而进入“任务队列”(task queue)的任务,只有“任务队列”通知主线程,某个异步任务可以执行了,该任务才会进入主线程执行。

异步任务分类为宏任务(macro-task)和微任务(micro-task)。

宏任务:整体的Script setTimeout setInterval
微任务:Promise.then  process.nextTick

注意:Promise是同步任务

有微则微,无微则宏

setTimeout(function(){
    console.log('1')
});
new Promise(function(resolve){
    console.log('2');
    resolve();
}).then(function(){
    console.log('3')
});
console.log('4');
new Promise(function(resolve){
    console.log('5');
    resolve();
}).then(function(){
    console.log('6')
});
setTimeout(function(){
    console.log('7')
});
function bar(){
    console.log('8')
    foo()
}
function foo(){
    console.log('9')
}
console.log('10')
bar()
setTimeout(() => {
      console.log('1');
      new Promise(function (resolve, reject) {
        console.log('2');
        setTimeout(() => {
          console.log('3');
        }, 0);
        resolve();
      }).then(function () {
        console.log('4')
      })
    }, 0);
    console.log('5'); //5 7 10 8 1 2 4 6 3
    setTimeout(() => {
      console.log('6');
    }, 0);
    new Promise(function (resolve, reject) {
      console.log('7');
      // reject();
      resolve();
    }).then(function () {
      console.log('8')
    }).catch(function () {
      console.log('9')
    })
    console.log('10');
console.log("AAAA");
setTimeout(() => console.log("BBBB"), 1000);
const start = new Date();
while (new Date() - start < 3000) {}
console.log("CCCC");
setTimeout(() => console.log("DDDD"), 0);
new Promise((resolve, reject) => {
  console.log("EEEE");
  foo.bar(100);
 })
.then(() => console.log("FFFF"))
.then(() => console.log("GGGG"))
.catch(() => console.log("HHHH"));
console.log("IIII");

//输出结果:
AAAA
CCCC
EEEE
IIII
HHHH
BBBB
DDDD

原型链污染

在一个应用中,如果攻击者控制并修改了一个对象的原型,那么将可以影响所有和这个对象来自同一个类、父祖类的对象。这种攻击方式就是原型链污染。

> var a = {admin:1}
undefined
> a.admin
1
> a.__proto__.admin = 2
2
> var b = {}
undefined
> b.admin
2

计算结果:

 let a={n:1}
 let b=a;
 a.x=a={a:2}
 console.log(a.x)
 console.log(b.x)

点的优先级大于=,new的优先级

{n:1,x:undefined}.x={n:2}

var a=10;
   var foo={
      a:20,
      bar:function(){
          var a=30;
          return this.a
      }
    }
console.log(foo.bar())
console.log((foo.bar)())
console.log((foo.bar=foo.bar)())
console.log((foo.bar,foo.bar)())

括号改变运算顺序

经过赋值运算后都为函数,并非对象的引用

  var tmp = 2;
        var obj = {
            tmp: 3,
            fn() {
                this.tmp *= 2
                tmp *= 2;
                console.log(1, tmp)
                console.log(2, this.tmp)
            }

        }
        var func = obj.fn
        func()
 async function async1() {
            console.log("async1 start");
            await async2();
            console.log("async1 end")
        }
        async function async2() {
            console.log("async2")
        }
        console.log("script start")
        setTimeout(function () {
            console.log("setTimeout")
        }, 0);
        async1();
        new Promise(function (resolve) {
            console.log("promise 1");
            resolve();
        }).then(function () {
            console.log("promise 2")
        })
        console.log("script end")
function Foo(){
      getName=function(){alert(1)}
      return this
    }
    Foo.getName =function(){alert(2)}
    Foo.prototype.getName=function(){alert(3)}
    var getName=function(){
      alert(4)
    }
    function getName(){
      alert(5)
    }

    Foo.getName()
    getName()
    Foo().getName()
    getName()
    new Foo.getName()
    new Foo().getName()
    new new Foo().getName()

数组去重

 //数组去重
        function repetition1(arr){
            for(var j=0;j<arr.length-1;j++){
                for(var i=j+1;i<arr.length;i++){
                    if(arr[j]==arr[i]){
                        arr.splice(i,1)
                        i--
                    }
                }   
            }
            console.log(arr)
        }
 
        function repetition2(arr){
            var arr1=[];
            arr.map(function(item1,index){
                if(arr1.indexOf(arr[index])==-1){
                    arr1.push(arr[index])
                }
            })
            console.log(arr1)
        }
         
        function repetition3(arr){
            for(var i=0;i<arr.length-1;i++){
                for(var j=arr.length;j>i;j--){
                    if(arr[i]==arr[j]){
                        arr.splice(j,1)   
                    }
                }        
            }
            console.log(arr)
        }
        function repetition5(arr){
        var arr1=arr.filter(function(item,index){return arr.indexOf(item)===index}) 
        console.log(arr1)
        }
        var arr=[45,23,666,45,88,00,66,23,66,66,666,"你","天使","你","e","w"];
        console.log([...new Set(arr)])

1、for+splice

2、set

3、indexof

4、filter+indexof

类数组-->数组

1、Array.from

2、Array.prototype.slice.call()

3、[...x]

4、Array.prototype.concate.apply([],arraylike)

防抖和节流(响应跟不上触发频率

 防抖:

防抖动是将多次执行变为最后一次执行

  • 搜索框搜索输入。只需要用户最后一次输入完再发送请求
  • 手机号、邮箱格式的输入验证检测
  • 窗口大小的 resize 。只需窗口调整完成后,计算窗口的大小,防止重复渲染。
<script>
function debounce(callback,delay){
  var t=null
  return function(){
    clearTimeout(t)
    t=setTimeout(callback,500)
  } 
}
window.onscroll=debounce(function(){
  console.log(1)
},500)
</script>

节流:

节流是将多次执行变成每隔一段时间执行。

  • 滚动加载,加载更多或滚动到底部监听
  • 谷歌搜索框,搜索联想功能
  • 高频点击提交,表单重复提交
  • 省市信息对应字母快速选择
<script>
function debounce(callback,delay){
  var t=new Date().getTime()
  return function(){
    var n=new Date().getTime()
    if(n-t>delay){
      callback();
      t=n;
    }
  } 
}
window.onscroll=debounce(function(){
  console.log(1)
},500)
</script>


function throttle(fn) {
    let canRun = true; 
    return function () {
        if (!canRun) return; 
        canRun = false; 
        setTimeout(() => { 
            fn()
            canRun = true;
        }, 500);
    };
}
window.addEventListener('resize', throttle(function(){
 console.log('节流');
}));

原型与继承、原型链

只有函数才有原型,原型是用来存放共有属性的,原型是一个属性,它的值是个对象
每一个对象都有一个__proto__(隐式原型)的属性,这个属性指向创建该对象的构造函数的prototype(如果不能确定他是谁的实例,都是Object的实例)
原型链:对象实例的隐式原型指向创建改对象的构造函数的原型对象,这样一层一层的指向关系形成的链叫原型链。

 

垃圾回收机制:

垃圾回收:JavaScript代码运行时,需要分配内存空间来储存变量和值。当变量不在参与运行时,就需要系统收回被占用的内存空间,这就是垃圾回收。

标记清除 标记整理清除 引用清除 复制整理

减少垃圾回收

  • 对数组进行优化:在清空一个数组时,最简单的方法就是给其赋值为[ ],但是与此同时会创建一个新的空对象,可以将数组的长度设置为0,以此来达到清空数组的目的。
  • object进行优化:对象尽量复用,对于不再使用的对象,就将其设置为null,尽快被回收。
  • 清除定时器
  • dom引用
  • 闭包

Javascript中 callee和 caller 的作用?

callee是函数arguments对象内的指针,它指向当前的函数,使得在函数内部递归调用当前函数时,不需要调用函数名称,减少函数内部对于函数名的依赖

caller是函数的一个属性,它指向调用当前函数的函数,如果当前函数在其他函数内被调用,则返回调用它的那个函数,如果是在全局环境下被调用,则返回 null

我们可以利用caller的特性跟踪函数的调用链

http常见的状态码有那些?分别代表是什么意思?

http由请求头和请求体组成

1xx : Hold on (等着)

2xx : Here you go (执行完了,没毛病,拿着结果回去吧)

3xx : Go away (你要的不在我这儿,去别处找)

4xx : You fucked up (你丫出问题了)

5xx : I fucked up (我特么出问题了)

200 OK 服务器成功处理了请求(这个是我们见到最多的)

304 Not Modified:服务端的资源与客户端上一次请求的一致,不需要重新传输,客户端使用本地缓存的即可

400 Bad Request:用于告诉客户端它发送了一个错误的请求

404 Not Found (页面丢失) 未找到资源

500 Internal Server Error:服务器内部出现了错误

501 Internal Server Error 服务器遇到一个错误,使其无法对请求提供服务

写 Vue 项目时为什么要在列表组件中写 key,其作用是什么?

  • 第一种情况是 v-if 中使用 key。使用 key 的元素不会被复用。
  • 第二种情况是 v-for 中使用 key。高效的实现复用。diff 操作可以更准确、更快速

        不能用index和random

        diff算法通过tag和key判断是否是sameNode

        减少渲染次数,提高渲染性能

 var,let和const之间的区别

块级作用域:块作用域由 { }包括,let和const具有块级作用域,var不存在块级作用域。块级作用域解决了ES5中的两个问题:

内层变量可能覆盖外层变量
用来计数的循环变量泄露为全局变量
变量提升:var存在变量提升,let和const不存在变量提升,即在变量只能在声明之后使用,否则会报错。

重复声明:var声明变量时,可以重复声明变量,后声明的同名变量会覆盖之前声明的变量。const和let不允许重复声明变量。

暂时性死区:在代码块内,使用let命令声明变量之前,该变量不可用。这在语法上,称为暂时性死区。

初始值设置:在变量声明时,var 和 let 可以不用设置初始值。而const声明变量必须设置初始值。

指针指向:let和const都是ES6新增的用于创建变量的语法。 let创建的变量是可以更改指针指向(可以重新赋值)。但const声明的变量是不允许改变指针的指向。

const保证的并不是变量的值不能改动,而是变量指向的那个内存地址不能改动。

对于基本类型的数据(数值、字符串、布尔值),其值就保存在变量指向的那个内存地址,因此等同于常量。

但对于引用类型的数据(主要是对象和数组)来说,变量指向数据的内存地址,保存的只是一个指针,const只能保证这个指针是固定不变的。

箭头函数和普通函数的区别:

a. 箭头函数和普通函数的样式不同,箭头函数语法更加简洁、清晰,箭头函数是=>定义函数,普通函数是function定义函数。

b. 箭头函数定义的时候this值就确定了,永久不变。

c. 箭头函数不能作为构造函数使用,也不能使用new关键字

d. 箭头函数没有自己的arguments。

e. call、apply、bind 并不会影响其 this 的指向。

f. 箭头函数没有原型prototype。

g.箭头函数不会函数提升

面向对象和面向过程的区别

面向对象=》 组件(方法1,方法2,方法3)

面向过程=》 顺序

this指向

ES5: 谁调用指向谁,方式不同指向不同

ES6:无this向

function Person(name){
  this.name=name   //Person
  console.log(this)
}
let p=new Person();
let obj={
  print:Person
}
Person()   //window
obj.print()   //object
setInterval(Person,5000)  //window
Person.call(document)    //document

new:

var obj={}
//_this=obj
this.name=name
return obj

箭头函数:当箭头函数不存在,找this

eval("var a=1;alert(a)")动态运行代码

少用,安全问题

eval 全局作用域

"use strict" eval产生自己的作用域

依次输出123456

 for (let i = 0; i < 6; i++){
     setTimeout(function(){
     console.log(i)
     },1000)
 }

 for (var i = 0; i < 6; i++) {
    (function(i) {
       setTimeout(function () {
           console.log(i)
       }, 1000)
    })(i)
 }

安全:

1、过滤特殊字符串

2、禁止拼接sql

3、innerText而非innerHtml

4、token验证

dom树:

vnode={

        tag:

        prop:{}

        children:{}

}

get和post的区别

a. GET 是将参数写在 URL 中 ? 的后面,并用 & 分隔不同参数;Get是通过地址栏来传值,而Post是通过提交表单来传值。

b. GET请求提交的数据有长度限制,POST请求没有内容长度限制。

c. GET请求返回的内容会被浏览器缓存起来。而每次提交POST请求,浏览器不会缓存POST请求返回的内容。

d. GET对数据进行查询,POST主要对数据进行增删改!

e. 关于安全性,GET 请求方式从浏览器的 URL 地址就可以看到参数;所以post更安全,其实无论是 GET 还是 POST 其实都是不安全的,因为 HTTP 协议是明文传输,只要拦截封包便能轻易获取重要资讯。想要安全传输资料,必须使用 SSL/TLS来加密封包,也就是 HTTPS。
f. 对于GET方式的请求,浏览器会把http header和data一并发送出去,服务端响应200,请求成功。

对于POST方式的请求,浏览器会先发送http header给服务端,告诉服务端等一下会有数据过来,服务端响应100 continue,告诉浏览器我已经准备接收数据,浏览器再post发送一个data给服务端,服务端响应200,请求成功。

g:get效率高!

1物理像素的实现

1、像素比=物理像素/css像素(px)

2.在移动中,不同设备其dpr即像素比不一样
通过操作meta标签上的缩放比

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


 width: 100rem;/*用上相对单位 100rem相当于100px*/
 border-bottom: 1px solid #666;


<script>
    window.onload = function () {
      //获取像素比
      var dpr = window.devicePixelRatio;
      //缩放比例
      var scale = 1 / dpr;
      //获取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 = dpr + 'px';/*通过设置根元素字体大小*/
    }
  </script>

2,媒体查询

@media screen and (-webkit-min-device-pixel-ratio:2){

trandform:scalseY(0.5)

}

JavaScript代码的整个执行过程,分为两个阶段

代码编译阶段由编译器完成(词法分析,语法分析,可执行代码生成,作用域规则确定)

执行阶段由引擎完成(执行上下文创建,代码执行,垃圾回收)

执行上下文(execute context)EC

每当函数被调用,就会进入一个执行上下文。

  • 全局环境:JavaScript代码运行起来会首先进入该环境
  • 函数环境:当函数被调用执行时,会进入当前函数中执行代码
  • eval

JavaScript引擎会以函数调用栈(call stack)的方式来处理它们,栈底永远都是全局上下文,而栈顶就是当前正在执行的上下文。处于栈顶的上下文执行完毕之后,就会自动出栈

执行上下文的生命周期可以分为两个阶段:

  • 创建阶段
            创建变量对象(Variable Object) 声明提升,为变量分配栈空间

                        建立arguments对象。。

                        函数声明,如果函数名的属性已经存在,那么该属性将会被新的引用所覆盖。

                        变量声明,如果该变量名的属性已经存在,则会直接跳过,原属性值不会被修改。

                建立作用域链

                        作用域链,是由当前环境与上层环境的一系列变量对象组成(单向通道),它保证了当前执行环境对符合访问权限的变量和函数的有序访问。

                确定this的指向

未进入执行阶段之前,变量对象中的属性都不能访问!但是进入执行阶段之后,变量对象转变为了活动对象,里面的属性都能被访问了,然后开始进行执行阶段的操作。

  • 代码执行阶段
            变量赋值,

                函数引用,

                执行其他代码。

                执行完毕后出栈,等待被回收

内存空间管理

JavaScript的内存生命周期

1. 分配你所需要的内存

2. 使用分配到的内存(读、写)

3. 不需要时将其释放、归还(null)

函数声明会覆盖变量声明;

立即调用的函数表达式有一个独立的作用域,函数名称与内部变量名冲突,永远指向函数本身;

网络OSI七层模型都有哪些?

  • 应用层
  • 表示层
  • 会话层
  • 传输层(TCP
  • 网络层
  • 数据链路层
  • 物理层

http1.0和http1.1,还有http2有什么区别

  • http0.9只能进行get请求
  • http1.0添加了POST,HEAD,OPTION,PUT,DELETE等
  • http1.1增加了长连接keep-alive,增加了host域,而且节约带宽
  • http2 多路复用,头部压缩,服务器推送

http和https的区别

超文本传输协议,由请求头和请求体组成

http:明文  快   tcp三次连接(3个包)

https:ssl(数字证书)+http(3+9)个包

http无状态无连接,而且是明文传输,不安全
https传输内容加密,身份验证,保证数据完整性
https实现原理⭐⭐⭐⭐⭐
首先客户端向服务端发起一个随机值,以及一个加密算法
服务端收到后返回一个协商好的加密算法,以及另一个随机值
服务端在发送一个公钥CA
客户端收到以后先验证CA是否有效,如果无效则报错弹窗,有过有效则进行下一步操作
客户端使用之前的两个随机值和一个预主密钥组成一个会话密钥,在通过服务端传来的公钥加密把会话密钥发送给服务端
服务端收到后使用私钥解密,得到两个随机值和预主密钥,然后组装成会话密钥
客户端在向服务端发起一条信息,这条信息使用会话秘钥加密,用来验证服务端时候能收到加密的信息
服务端收到信息后返回一个会话秘钥加密的信息
都收到以后SSL层连接建立成功

tcp 和udp有什么区别⭐⭐⭐⭐⭐

连接方面

tcp面向连接,udp不需要连接
tcp需要三次握手四次挥手请求连接
可靠性

tcp是可靠传输;一旦传输过程中丢包的话会进行重传
udp是不可靠传输,但会最大努力交付
工作效率

UDP实时性高,比TCP工作效率高
因为不需要建立连接,更不需要复杂的握手挥手以及复杂的算法,也没有重传机制
是否支持多对多

TCP是点对点的
UDP支持一对一,一对多,多对多
首部大小

tcp首部占20字节
udp首部占8字节

什么是xss?什么是csrf?⭐⭐⭐⭐⭐

xss脚本注入
不需要你做任何的登录认证,它会通过合法的操作(比如在url中输入、在评论框中输入),向你的页面注入脚本(可能是js、hmtl代码块等)。
防御
编码:对用户输入的数据进行HTML Entity 编码。把字符转换成 转义字符。Encode的作用是将$var等一些字符进行转化,使得浏览器在最终输出结果上是一样的。
过滤:移除用户输入的和事件相关的属性。
csrf跨域请求伪造
在未退出A网站的前提下访问B,B使用A的cookie去访问服务器
防御:token,每次用户提交表单时需要带上token(伪造者访问不到),如果token不合法,则服务器拒绝请求

['1', '2', '3'].map(parseInt):

其中第一个参数代表当前被处理的元素,而第二个参数代表该元素的索引。

  • 而parseInt则是用来解析字符串的,使字符串成为指定基数的整数。
    parseInt(string, radix)
    接收两个参数,第一个表示被处理的值(字符串),第二个表示为解析时的基数。

  1. parseInt('1', 0) //radix为0时,且string参数不以“0x”和“0”开头时,按照10为基数处理。这个时候返回1
  2. parseInt('2', 1) //基数为1(1进制)表示的数中,最大值小于2,所以无法解析,返回NaN
  3. parseInt('3', 2) //基数为2(2进制)表示的数中,最大值小于3,所以无法解析,返回NaN
  • map函数返回的是一个数组,所以最后结果为[1, NaN, NaN]

var arr = [ [1, 2, 2], [3, 4, 5, 5], [6, 7, 8, 9, [11, 12, [12, 13, [14] ] ] ], 10];编写一个程序将数组扁平化去并除其中重复部分数据,最终得到一个升序且不重复的数组

Array.from(new Set(arr.flat(Infinity))).sort((a,b)=>{ return a-b})

arr.toString().split(",").sort((a,b)=>{ return a-b}).map(Number)

var flatArr = arr.toString().split(",");//扁平化

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
React面试可以包括以下内容: 1. 什么是React?它的核心概念是什么? React是一个用于构建用户界面的JavaScript库。它的核心概念是组件化和虚拟DOM。 2. 什么是React组件?如何创建一个React函数组件和一个React类组件? React组件是一种可重用且独立的代码块,用于处理特定的UI逻辑。创建一个React函数组件可以使用函数声明的方式,例如: ```jsx function MyComponent() { return <div>Hello, World!</div>; } ``` 创建一个React类组件可以使用ES6类的方式,例如: ```jsx class MyComponent extends React.Component { render() { return <div>Hello, World!</div>; } } ``` 3. 什么是JSX?如何在React使用JSX? JSX是一种JavaScript的扩展语法,类似于HTML的写法,用于描述React组件的结构。在React使用JSX时,可以直接在JavaScript代码编写类似HTML的标记。例如: ```jsx function MyComponent() { return <div>Hello, World!</div>; } ``` 4. 什么是状态(state)和属性(props)?它们之间有什么区别? 状态是组件内部管理的数据,可以通过`setState()`方法进行更新。属性是从父组件传递给子组件的数据,是只读的。区别在于状态可以在组件内部改变,而属性是外部传入的数据。 5. React的生命周期方法有哪些?分别在何时调用? React的生命周期方法包括:`componentDidMount`、`componentDidUpdate`、`componentWillUnmount`等。`componentDidMount`在组件挂载后调用,`componentDidUpdate`在组件更新后调用,`componentWillUnmount`在组件卸载前调用。 6. 什么是React Router?如何在React实现页面路由? React Router是用于实现单页应用页面路由的库。可以通过安装React Router并使用`<Router>`、`<Route>`等组件来定义路由规则和渲染组件。 7. 什么是React Hooks?它们的作用是什么? React Hooks是React 16.8版本引入的一种新特性,它们可以使函数组件具有类组件的功能。常用的Hooks包括`useState`、`useEffect`、`useContext`等,用于管理状态、执行副作用和访问上下文。 8. React如何处理表单输入? 可以使用受控组件或非受控组件来处理表单输入。受控组件将表单数据绑定到组件状态,并通过事件处理函数更新状态。非受控组件使用ref来获取表单输入的值。 9. 什么是React的虚拟DOM?它的作用是什么? React的虚拟DOM是一个轻量级的JavaScript对象,用于表示真实DOM的结构和属性。通过比较虚拟DOM的变化,React可以高效地更新真实DOM,并最小化对浏览器的操作,提高性能。 10. 如何优化React应用的性能? 可以通过使用React.memo来避免不必要的组件渲染,使用shouldComponentUpdate或React.memo进行性能优化。还可以使用React的代码分割和懒加载功能,减少初始加载的代码量。另外,使用React DevTools来分析组件性能,并进行必要的性能优化。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值