走笔字节,面后便是海阔天空

前言

HE({(1$R8`)CAZ90X)_MDRB.png

好的,初生牛犊不怕虎,前端小白面字节。你问我咋这么自信的,哈哈哈一切都是内推的机缘巧合。20下午体验了字节实习生一面,总体感受是面试官人超好,不会的题目还会尽心引导,然后的都在尽量挖掘我的闪光点(实话实说,太菜了要加强学习)。举个栗子来说就是,字节的面试体验就是无论你的回答是好还是坏,都会让你觉得你能过。哈哈哈哈哈哈要不是我知道自己不太行,在面试官的 ‘温柔’ 下,我还以为我过了哈哈哈。良好体验+学习成长,这是意义所在!

现在介绍一下部分面试题(改)

面试题

变量提升+原型链

这题比较基础,又是很经典的题,考察的内容很多,原型链,声明提升,运算符优先级等等

// 1  构造函数  内部变量指向匿名函数
function Fun() {
    getName = function () { 
        console.log(1);
     };
    return this;
}
// 2 定义全局变量 getName  
var getName;
// 3 定义一个getName 函数 函数声明提升
function getName() {
    console.log(5);
}
// 4 给构造函数定义一个属性  getName 
Fun.getName = function () {
    console.log(2);
};
// 5 在构造函数的原型上定义 一个getName方法
Fun.prototype.getName = function () {
    console.log(3);
};
// 6  getName变量指向一个匿名函数 
getName = function () {
    console.log(4);
};
getName();//4
Fun.getName()// 2
Fun().getName(); // 1
getName(); // 1
new Fun.getName();//2
new Fun().getName();//3
new new Fun().getName();//3
复制代码

分析一下题目:

  • getName(); // 4 代码块2 变量声明提升到最前 getName (实际为undefined) ;代码块3 定义函数声明提升 getName函数 ,函数声明的优先级高于变量声明,所以把代码块2 覆盖应当输出 5,那为什么实际上输出 4 呢? 因为代码块 6 把又把变量getName指向匿名函数,所以再次覆盖了,举个栗子理解下。
var getName ;
var getName = function () {
    console.log(5);
}
console.log(getName); // [Function: getName]
getName() // 5
---------------
function getName() {
    console.log(5);
}
var getName  = 1;
console.log(getName); // 1
getName() // 报错
复制代码

在上述栗子中,这叫覆盖,重新赋值。

  • Fun.getName(); // 2 直接调用代码块 4 构造函数的静态方法 输出结果 为 2

  • Fun().getName(); // 1 调用构造函数Fun(),然后给全局的getName()重新赋值,函数内部的 return this 把整个函数内容返回到了上层作用域(window) ,所以等于全局上的getName() 已经修改为 输出 1

  • getName(); // 1 上一步已经修改全局 ,输出 1

  • new Fun.getName(); //2 .的执行顺序高,先执行 Fun.getName() 后返回 2 ,再被 new 进行实例化所以 new的过程就相当于 把Fun.getName()执行了一遍输出2,然后返回了一个空的实例(new函数调用时,会执行这个函数,所以打印输出2)

  • new Fun().getName(); //3 这里 new 调用构造函数, 所以new关键字最后会生成一个实例对象fun.getName(),然后顺着原型链从自身到__proto__找属性。 所以找到 原型链上:

Fun.prototype.getName = function () {
    console.log(3);
};
复制代码
  • new new Fun().getName(); //3 这里相当于 new ((new Fun()).getName)() => new (fun.getName)() => new (Fun.prototype.getName(){…}) 返回 3

promise.all手写

这题对于大佬来说吧其实不难,不过呢面试的时候我才看懂手写.then的链式调用后面就没继续看了….在上一篇文章里(悔不当初….)

面试官对不起!我终于会了Promise…(一面凉经泪目)

//resolve方法
Promise.resolve = function(val){
  return new Promise((resolve,reject)=>{
    resolve(val)
  });
}
//reject方法
Promise.reject = function(val){
  return new Promise((resolve,reject)=>{
    reject(val)
  });
}
//race方法 
Promise.race = function(promises){
  return new Promise((resolve,reject)=>{
    for(let i=0;i<promises.length;i++){
      promises[i].then(resolve,reject)
    };
  })
}
//all方法(获取所有的promise,都执行then,把结果放到数组,一起返回)
Promise.all = function(promises){
  let arr = [];
  let i = 0;
  function processData(index,data){
    arr[index] = data;
    i++;
    if(i == promises.length){
      resolve(arr);
    };
  };
  return new Promise((resolve,reject)=>{
    for(let i=0;i<promises.length;i++){
      promises[i].then(data=>{
        processData(i,data);
      },reject);
    };
  });
}
复制代码

参考

手写深拷贝

何为深拷贝,浅拷贝?

浅拷贝

  • 浅拷贝是创建一个新对象,这个对象有着原始对象属性值的一份精确拷贝。如果属性是基本类型,拷贝的就是基本类型的值,如果属性是引用类型,拷贝的就是内存地址 ,所以如果其中一个对象改变了这个地址,就会影响到另一个对象。

    • 借用大佬的图片进行理解

image.png

深拷贝

  • 深拷贝是将一个对象从内存中完整的拷贝一份出来,从堆内存中开辟一个新的区域存放新对象,且修改新对象不会影响原对象。
    • 借用大佬的图片进行理解

image.png

实现

浅拷贝实现

  • 简单赋值
var arr = [1,2,3];
var newArr = arr;
newArr[1] = "二";
console.log(arr);    //  [ 1, '二', 3 ]
console.log(newArr);    //  [ 1, '二', 3 ]
console.log(arr==newArr);   //  true
console.log(arr===newArr);  //  true
复制代码
  • Object.assign():把任意多个的源对象自身的可枚举属性拷贝给目标对象,然后返回目标对象。
var a = { age: 18, name: 'yy', info: { address: 'beijing', sports: 'basketball' } };
var b = Object.assign(a);
b.info.address = 'shenzhen';
b.age = 22
console.log(a); // {age: 22,name: 'yy',info: { address: 'shenzhen', sports: 'basketball' } }
console.log(b); // {age: 22,name: 'yy',info: { address: 'shenzhen', sports: 'basketball' } }b
复制代码
  • 数组方法 concat 和 slice

当数组内为基本数据类型时,则是a数组变,b数组不变,但是实际上还是浅拷贝,因为当数组内部有引用类型时,拷贝出来数组中的对象还是共享同一内存地址。

let a = [1,2,3,4];
let b = a.concat();
a[0] = 0;
console.log(a);  // [ 0, 2, 3, 4 ]
console.log(b);  // [ 1, 2, 3, 4 ]

let a1 = [1,2,[3,4],{name:'HH'}];
let b1 = a1.concat();
a1[3].name = 'YY';
a1[0] = 0;
console.log(a1); // [ 0, 2, [ 3, 4 ], { name: 'YY' } ]
console.log(b1); // [ 1, 2, [ 3, 4 ], { name: 'YY' } ]



let a2 = [1,2,3,4];
let b2 = a2.slice();
a2[0] = 0;
console.log(a2);  // [ 0, 2, 3, 4 ]
console.log(b2);  // [ 1, 2, 3, 4 ]

let a3 = [1, 3, {
    name: ' HH'
    }];
let a4 = a3.slice();
a3[2].name = 'YY'
a3[0] = 0
console.log(a3); // [ 0, 3, { name: 'YY' } ]
console.log(a4); // [ 1, 3, { name: 'YY' } ]
复制代码
  • 扩展运算符
let obj1 = { name: 'HH', address:{x:'beijing',y:'wuhan'}}
let obj2= {... obj1}
obj1.address.x = 'shenzhen';
obj1.name = 'YY'
console.log(obj1) // { name: 'YY', address: { x: 'shenzhen', y: 'wuhan' } }
console.log(obj2) // { name: 'HH', address: { x: 'shenzhen', y: 'wuhan' } }
复制代码

深拷贝实现

  • JSON.parse(JSON.stringify(obj))可以对数组或对象深拷贝,但它的使用也是有局限性的,不能深拷贝含有undefined、function、symbol值的对象
  • 函数库lodash的_.cloneDeep方法
手写实现
  • 原理:遍历对象、数组直到里边都是基本数据类型,然后再去复制,就是深度拷贝
  1. 简单版
  • 如果是基本类型,无需继续拷贝,直接返回
  • 如果是引用类型,创建一个新的对象,遍历需要克隆的对象,将需要克隆对象的属性执行深拷贝后依次添加到新对象上。
function deepClone(obj) {
    if (typeof obj !== 'object') return;
    var newObj = obj instanceof Array ? [] : {};
    for (var key in obj) {
        if (obj.hasOwnProperty(key)) {
            newObj[key] = typeof obj[key] === 'object' ? deepClone(obj[key]) : obj[key];
        }
    }
    return newObj;
}
复制代码

2.终极版
基于简单版的基础上,考虑了内置对象比如 Date、RegExp 等对象和函数以及解决了循环引用的问题。

const isObject = (target) => (typeof target === "object" || typeof target === "function") && target !== null;

function deepClone(target, map = new WeakMap()) {
    if (map.get(target)) {
        return target;
    }
    // 获取当前值的构造函数:获取它的类型
    let constructor = target.constructor;
    // 检测当前对象target是否与正则、日期格式对象匹配
    if (/^(RegExp|Date)$/i.test(constructor.name)) {
        // 创建一个新的特殊对象(正则类/日期类)的实例
        return new constructor(target);  
    }
    if (isObject(target)) {
        map.set(target, true);  // 为循环引用的对象做标记
        const cloneTarget = Array.isArray(target) ? [] : {};
        for (let prop in target) {
            if (target.hasOwnProperty(prop)) {
                cloneTarget[prop] = deepClone(target[prop], map);
            }
        }
        return cloneTarget;
    } else {
        return target;
    }
}

复制代码

参考一

参考二

CSS 盒模型

所有HTML元素可以看作盒子,CSS盒模型本质上是一个盒子,封装周围的HTML元素,它包括:边距,边框,填充,和实际内容。
盒模型允许我们在其它元素和周围元素边框之间的空间放置元素。

image.png

  • Margin(外边距) – 清除边框外的区域,外边距是透明的。
  • Border(边框) – 围绕在内边距和内容外的边框。
  • Padding(内边距) – 清除内容周围的区域,内边距是透明的。
  • Content(内容) – 盒子的内容,显示文本和图像。

盒模型是什么?

页面就是由一个个盒模型堆砌起来的,每个HTML元素都可以叫做盒模型,盒模型由外而内包括:边距(margin)、边框(border)、填充(padding)、内容(content)。它在页面中所占的实际宽度是margin + border + paddint + content 的宽度相加。

一般来说:
当设置了一个宽度后,只是设置内容区域的宽度和高度,下面这个栗子

div {
    width: 300px;
    border: 25px solid green;
    padding: 25px;
    margin: 25px;
}
复制代码

实际盒子的大小为:
总元素的宽度(450px)=宽度(300px)+左填充(25px)+右填充(25px)+左边框(25px)+右边框(25px)+左边距(25px)+右边距(25px)

那么不一般的情况的?

W3C标准盒模型和IE的盒模型的区别

W3C标准盒模型 : width指content部分的宽度

image.png

IE盒模型 : width表示content+padding+border这三个部分的宽度

image.png

结合实际的话,IE盒模型更符合日常生活,盒子的宽度应该包括content+padding+border,所以在W3C在CSS3中也增加了box-sizing属性,包含两个属性content-box 和 border-box。

  • box-sizing: content-box 是W3C盒子模型
  • box-sizing: border-box 是IE盒子模型

BFC的了解

BFC的基本概念

BFC——块级格式化上下文。它是 W3C CSS 2.1 规范中的一个概念,它决定了元素如何对其内容进行定位,以及与其他元素的关系和相互作用。通俗的讲,就是一个特殊的块,内部有自己的布局方式,不受外边元素的影响。

原理

  • BFC内部的盒子,会在垂直方向,一个接一个地放置。。
  • BFC就是页面上的一个独立容器,容器里面的子元素不会影响到外面的元素,外边的也不会影响里边的。
  • BFC的区域不会与float box重叠。
  • 计算BFC的高度时,浮动元素也被计算在内
  • Box垂直方向的距离由margin决定。属于同一个BFC的两个相邻Box的margin会发生重叠。

如何创建BFC

  • 1、float的值不是none。
  • 2、position的值不是static或者relative。
  • 3、display的值是inline-block、table-cell、flex、table-caption或者inline-flex
  • 4、overflow的值不是visible

使用场景

  • 1.利用BFC避免margin重叠。
  • 2.清除浮动
  • 3.自适应布局

具体实现有兴趣的小伙伴可以。

参考一

参考二

其他面试题

  • 项目,为什么要做这个,有什么难点
  • CSS flex布局
  • 大数相加
  • for in 和 for of

总结

字节面试官给人的感觉就是温文尔雅,如沐春风,只是我还是太菜了,还得加强学习,总的来说这是一次非常宝贵的学习经历,学习到很多。面试时不要慌,不要冷场,主动把面试官引导到自己了解的知识点,惭愧当时我手写就吓傻了话都不会说了。相信肯定有很多优秀的小伙伴想去字节而不敢去面,大家不要怕,在下前端小白也是一枚字节‘落榜生’了,字节对实习生的要求主要还是基础能力鸭,个人感觉字节对于年轻人还是有有好大的信任和支持的,大家冲鸭!

还有就是把一个好的idea然后把它做成项目展示给面试官,从为什么做,从何何来,遇到的难点等问题一 一介绍给面试官,这会体现出独特的属于你个人的魅力,哈哈哈说不定就….

© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享