首页 > 字节效率工程 一面
头像
刀剑丛中闯
编辑于 2021-05-14 15:45
+ 关注

字节效率工程 一面

面完之后觉得自己是真的菜,很多东西确实都知道,但是说不明白,有点自闭
更新 4.27约了二面,来复盘一下

算法题:
1、合并有序数组,leetcode原题
2、看代码说输出顺序,就平常的题

async function async1() {
	
async function async1() {
  console.log('async1 start');//2
  await async2();//
  console.log('async1 end');//6
}
async function async2() {
  console.log('async2');//3
}

console.log('illegalscript start');//1
setTimeout(function() {
    console.log('setTimeout');//8
}, 0);  
async1();
new Promise(function(resolve) {
    console.log('promise1');//4
    resolve();
  }).then(function() {
    console.log('promise2');//7
});
console.log('illegalscript end');//5
3、菜🐔的代码看看就好,面试的时候没有写出来,想用递归没写出来,面试官说递归总要返回什么,我想不出来,换了个思路,但是数组部分也没写出来,后来补上的,面试官提醒我也没有写出来。。。。是真的有点菜没有想到那个点,写出来还给面试官发消息说写出来了,他说不用纠结,总之就是编程能力还是要重视的

const obj = {
    selector: { to: { toutiao: 'FE coder' } },
    target: [1, 2, { name: 'byted' }]
};
/* 运行代码 */
//   get(obj, 'selector.to.toutiao', 'target[0]', 'target[2].name')

/*  输出结果:
['FE coder', 1, 'byted'] */

function get(obj, ...args) {
    for (let i = 0; i < args.length; i++) {
        args[i] = args[i].replace(/\[/g, '.').replace(/\]/, '')
    }
    args = args.map(item => {
        return item.split('.')
    })
    let res = []
    for (let i = 0; i < args.length; i++) {
        res.push(help(args[i], obj))
    }
    console.log(res, args)
}
function help(arr, obj) {
    for (let i = 0; i < arr.length; i++) {
        obj = obj[arr[i]]
    }
    return obj
}
// help(["selector","to","toutiao"],0,obj)

基础:js和别的语言有什么区别
1、变量提升,js是运行前编译,编译完立刻执行,(不是提前编译,编译结果也不能移植),编译阶段找到所有的声明,提前放在相关联的作用域,然后顺序执行语句,js采取词法作用域,this是动态作用域--作用域链,你不知道的js里面比较详细
function foo(){
    console.log(a)//1
}
function bar() {
    var a = 2
    foo()
}
var a = 1
bar()
2、var重复声明,多次声明会被忽略
3、动态类型,
4、es5没有块级作用域
能想到的差不多就这样吧
var声明变量,一直声明是个什么情况
变量提升之后是放在哪里的
let const 和var的区别
1、var重复声明和变量提升,所以可以在未声明之前使用
2、let限定作用域(暂时性死区) {} 函数内部,禁止重复声明
3、常量声明,如果常量是引用类型,是可以改变其属性,
那怎么让引用类型的常量不可更改:Object.freeze()//相当于configurable为false,writable设置成false,但是对深层对象都没有用
闭包
//感觉这样看很清晰
function foo() {
  var a = 2
  function bar() {    //这里就已经产生了闭包,在bar中可以记住并访问foo的作用域 只是不能直接观察,所以return出去保存就可以看到
    console.log(a)
  }
 // bar()
  return bar
}
var baz = foo()
baz()//在定义自己的词法作用域以外的地方执行,
闭包是一个引用,对不属于自己作用域的一个保存,
对foo作用域的保持,就是闭包的引用,这个引用不在作用域定义的位置使用, 闭包就是一个把函数内部和外部连接起来的桥梁,
应用:回调函数,数据共享,缓存数据、柯里化(延迟执行),单例模式?
缺点:变量无法释放,造成内存泄漏

说到柯里化,顺便动手写一下,把接收多个参数的函数转换成多个接收一个参数的函数
function curry(func) {
    // 返回一个函数,接收新的参数
    return function curried(...args) {
        console.log(args, func.length)
        //参数满足条件直接调用
        if (args.length >= func.length) {
            return func.apply(this, args);
        } else {
        // 参数不满足条件 继续收集新的参数
            return function (...newArgs) {
                console.log(newArgs)
                return curried.apply(this, args.concat(newArgs));
            }
        }
    };
}

我说我后来学的时候有看书,js高级程序设计什么的,说说有什么难点,印象深刻的
promise 说说是干啥的

cookie 和local/sessionstroage有啥区别,
cookie是为http无状态服务的,由于http是无状态的,Cookie可以用来跟踪用户,由于每次请求浏览器都会自动携带Cookie,这样服务端就知道哪些请求是来自同一个用户了。
cookie是保存在客户端的一小段数据文本,以key-value的形式,整个值是字符串
cookie有很多属性可以进行操作: 
        domain:表示cookie的域,限定cookie能被访问地址,后端显示设置主域名之后,子域就可以访问到cookie
        path:指定可以共享cookie的子目录,默认根目录
        cookie的作用域与协议和端口无关
        Expires/Max-Age:cookie的有效时间,默认Session,Expires指具体的过期时间,Max-Age指多少秒之后过期,Max-Age的优先级更高
        HttpOnly:表示Cookie能否被js获取
        Secure:只有***L 和 HTTPS 协议的时候才会被发送
        SameSite:用于限制第三方 Cookie 的发送
cookie的安全隐患:csrf:利用浏览器自动带上cookie的特性 https://juejin.cn/post/6869573026980036616 
                xss: 通过可执行代码获取cookie https://juejin.cn/post/6867184627393265677 
                有源码的讲解
storage是本地储存,发送请求不会自动带上
cookie的大小一般4kb,storage一般5m
cookie的期限可以设置,sessionstorage是会话期有效,localsotorage是永久保存,手动删除
共同点:都不可以跨域
看到一个题,storage容量有限怎么解决:内嵌同源页面使用?套娃?
说到cookie要说下session:一般配对使用,一个用户创建一个session,服务器把sessionid发给客户端存在cookie里,session存在服务端,每次收到cookie获取session查找服务端的session找到就放行,可以保存状态
cookie里面存的啥,有什么安全隐患,怎么解决,我说了https,这个是咋解决的,非对称加密是为了什么,为了交换对称加密的密钥,这里说的挺差的
https:TSL/SSL + HTTP,对传输的数据进行加密,对服务端进行身份验证
算了 感觉自己写的不好,推荐两个链接,连着看 阮一峰的https,https://blog.csdn.net/update7/article/details/111187245
基本上能搞明白
如果用token的话完整一套下来的流程是怎样的,又是怎么验证的
说到token,我一直都有一个疑问,服务端收到token是怎么验证有效性的,一篇文章:一篇文章告诉你JWT的实现原理
上面cookie和session需要各种保存在客户端和服务端来做状态管理,token就只保存在客户端,服务端只是验证收到的这个token是否有效,以解析token的时间换取session的储存空间
步骤:
	
  1. 浏览器发起请求登陆

  2. 服务端验证身份,根据算法,将用户标识符打包生成 token, 并且返回给浏览器

  3. 浏览器发起请求获取用户资料,把刚刚拿到的 token 一起发送给服务器

  4. 服务器发现数据中有 token,验明正身

  5. 服务器返回该用户的用户资料

首先:JWT的组成 header-----加密算法,类型-----进行base64 payload-----标准声明(签发者-面向用户-接收方-过期时间等等)、公共声明(任意信息,因为可以被解密,不要放敏感信息)、私有声明(JWT提供者添加,可以被解密,不能存放敏感信息。)----通过base64 Signature----加密算法(header+'.'+payload+secret) 验证(我疑惑的点):解析JWT以后可以知道用户信息,比如能拿到uuid就能通过了? JWT防止篡改:Signature,再通过Signature的生成一次,对比就能知道,服务器的secret不能泄漏 为了防止csrf就不要放在cookie中, 还有个问题,如果token被截取到了又怎么办(有特殊场景可以把用户的user-agent(干扰码,每个客户端不一样,就不能解析别的token)和ip放进token进行验证?或者https?想不到别的了) Token - 服务端身份验证的流行方案:这篇有讲上面的问题
看简历用过vue,那你说说vue从实例化开始到看到页面一整个流程,这个理解错意思了----说了一堆初始化的工作
分阶段说比较好
1.初始化阶段:new Vue()到created之间的阶段
    1.1 配置:始化配置项,合并配置,如果有全局配置合并得到根组件的配置上
    1.2 initLifecycle:*组件关系属性的初始化,比如$parent root chidren这种*
    1.3 initEvents:自定义事件
    1.4 initRender:初始化插槽,获取this.$slots, this._c就是createElement方法,也就是h方法
    1.5 callHook:beforecreate函数
    1.6 initInjections:初始化inject选项,做响应式处理
    1.7 initState:响应式原理的核心,处理 props methods computed,data watch
    1.8 initProvide:处理provide
    1.9 callHook:create函数
2.模版编译阶段:在created钩子函数与beforMount钩子函数之间
    2.1 获取模版,将html编译成ast tree,将asttree解析成render函数,挂载到vm.$options.render
    2.2 mountComponent:
        2.2.1 判断vm.$options.render
        2.2.2 beforeMount函数
        2.2.3 updateComponent:调用了 vm_update(vm._render(),...),
        2.2.4 new Watcher(),此时会传入updateComponent函数,并随后执行此函数,执行后会发生一些函数执行,
              Vue._render:执行由vue-loader生成的render函数或者自己写的render函数,最终返回一个由createComponent(非createPatchFunction内部的)产生的vnode.
              createComponent(非createPatchFunction内部):创建组件虚拟节点,此函数返回一个vnode,表示vue组件的vnode.
              vm._update:接收上面的vnode参数,这里面会触发VM.__patch__函数,这个函数里面最终返回的结果就是我们在html页面写的空的div,但是里面有了真实的内容,此时页面可以看到内容了,
        2.2.5 触发mount钩子函数,这个mount钩子每个组件实例会在自己的insert hook中调用
3.挂载阶段:beforeMount钩子函数到mounted钩子函数之间
4.卸载阶段:调用vm.$destroy方法后,Vue.js的生命周期会进入卸载阶段。
这里面好多小点,比如computed的缓存原理,和watch的区别,响应式原理,provide/inject原理
computed的缓存原理:1、初始化computed的时候,遍历拿到里面的key,是函数直接赋值,不是函数获取getter,
                  2、把每个key都实例化一个watcher,传入一个对象{vm,getter,null,懒执行配置}
                  3、执行的时候,默认watcher.dirty = true,得到函数执行结果,赋值给watch.value,将watcher.dirty置为false,一次渲染中,只执行一次computed,后续访问不会执行,直到下一次更新下会执行,watcher.update之后才会把ditry置为true,不然每次执行都直接返回value
                  4、将key代理到vue实例上,支持this.computedKey访问

说了之后就问computed是怎么做到缓存的,双响绑定原理,感觉应该说完整一点,只说了核心部分就没头没尾的
一些细节就是我回答了什么他就顺着问
别的又记不得了,还停留在太菜了情绪中太菜了太菜了

反问我就问面试官对我们这种学的不久的人的建议,他说代码能力还是很重要的,还有基础,就不用急于去弄什么源码框架的,对于所有人来说都是,像刚刚你递归用的不好就不应该在面试过程中使用,这样就不太好

更多模拟面试

全部评论

(3) 回帖
加载中...
话题 回帖

推荐话题

相关热帖

近期热帖

历年真题 真题热练榜 24小时
技术(软件)/信息技术类
查看全部

近期精华帖

热门推荐