2024年前端最全深夜爆肝JS好文!2024字节跳动春招面试题深度讲解(1),web开发基础教程

后话

开源分享:【大厂前端面试题解析+核心总结学习笔记+真实项目实战+最新讲解视频】

对于面试,说几句个人观点。

面试,说到底是一种考试。正如我们一直批判应试教育脱离教育的本质,为了面试学习技术也脱离了技术的初心。但考试对于人才选拔的有效性是毋庸置疑的,几千年来一直如此。除非你有实力向公司证明你足够优秀,否则,还是得乖乖准备面试。这也并不妨碍你在通过面试之后按自己的方式学习。
其实在面试准备阶段,个人的收获是很大的,我也认为这是一种不错的学习方式。首先,面试问题大部分基础而且深入,这些是平时工作的基础。就好像我们之前一直不明白学习语文的意义,但它的意义就在每天的谈话间。

所谓面试造火箭,工作拧螺丝。面试往往有更高的要求,也迫使我们更专心更深入地去学习一些知识,也何尝不是一种好事。

在这里插入图片描述

1.2 解构是深拷贝吗?为什么?

  • 这里就是面试官给你挖坑了,考察你的基础扎实程度。

  • 我们先来看一组代码:

数组解构赋值

let arr2 = [1,2,3,4];

let newArr2 = […arr2]; //此处是解构赋值

newArr2.push(5);

console.log(arr2, newArr2) // arr2的结果: 1,2,3,4 newArr2的结果: 1,2,3,4,5

对象解构赋值

let objA = {

name: ‘小明’,

age: 8

}

let {name , age} = objA;

name = ‘小花’;

age = 10;

console.log(name, age, objA); // 1.name为小花,2.age为10 3.objA没有变化

  • 据上可得:无论是数组还是对象,经过解构赋值之后的新变量,两者之间相互没有影响,那么我们是否可以下定义了:解构赋值是深拷贝?

  • 不要急,我们再来看一组代码:

let arr3 = [[1,2],[3,4],[5,6]];

let newArr3 = […arr3];

newArr3[0][1] = 33333;

console.log(newArr2, arr2)

打印结果是:

在这里插入图片描述

  • 我们可以看到:两组数据相互影响了

  • 那么问题就来了,为什么上面的代码可以实现互不影响,下面却不行?

  • 答案是:解构不是真正的深拷贝,是伪深拷贝

  • 结论:解构只能深拷贝一维数组与一维对象,多维数组和对象无效

1.3 如何实现一个深拷贝?

这里有两种方式

  1. JSON()的相关API,代码如下:

let list = [

{id: 1, stuName: ‘小明’, class:‘五年二班’},

{id: 2, stuName: ‘小红’, class:‘五年三班’},

{id: 3, stuName: ‘小绿’, class:‘五年四班’}

]

// JSON.stringify : 对象转json字符串

// JSON.parse : 将json字符串转换成json对象

let newList = JSON.parse(JSON.stringify(list));

let newObj = {

id: 4,

stuName: ‘小白’,

class: ‘五年四班’

}

newList.push(newObj)

newList[2].class = ‘六年一班’;

console.log(list, newList)

打印结果如下:

在这里插入图片描述

  • 由此可见,JSON相关方法,确实可以实现深拷贝。

  • 但是此类方法只能适用于部分场景

  • 如果对象里有 function这种关键字是不行的,JSON()方法会将它转化为字符串,那么,自然不行,性质都不一样了

2. 用原生JS写一个真正的深拷贝,适用于所有场景:

  • 原理简单粗暴:将对象里的值一个一个取过来,重新定义

  • 代码如下:

// 标准的深拷贝

function deepClone(source){

// 判断复制的目标是数组还是对象

const targetObj = source.constructor === Array ? [] : {};

// 遍历目标

for(let keys in source){

if(source.hasOwnProperty(keys)){

// 如果值是对象,就递归一下

if(source[keys] && typeof source[keys] === ‘object’){

targetObj[keys] = source[keys].constructor === Array ? [] : {};

targetObj[keys] = deepClone(source[keys]);

}else{

// 如果不是,就直接赋值 (基本类型)

targetObj[keys] = source[keys];

}

}

}

return targetObj;

}

  • 测试是否管用:

let objD = {

name: ‘小猪’,

age: 20,

detail: {

color: ‘白色’,

type: ‘种猪’

}

}

let newObjD = deepClone(objD);

newObjD.detail.color = “黑色”;

console.log(objD, newObjD)

  • 实际结果:

在这里插入图片描述

  • 实验表明,确实是管用的

  • FAQ:深拷贝的代码务必手写下来,真的很重要

2. 原型与原型链


1.1 原型是什么?有什么用?

  • 原型 prototype是 js 中极其重要的概念之一,也是面试高频问题点,也是比较容易引起混淆的地方

  • 原型的概念:

  • 首先,我们明确原型是一个对象

  • 每个函数都有一个属性叫做原型(函数特有的),这个属性指向一个对象

  • 原型是函数对象的属性,不是所有对象的属性,对象经过构造函数new出来,那么这个new出来的对象的构造函数有一个属性叫原型

  • 当哦我们定义一个函数的时候,这个函数的原型属性也就被定义出来了,并且可以使用它。如果不对它进行显示赋值的话,那么它的初始值就是一个空的对象Object(默认添加的

  • 简单来说:原型是函数的一个特有属性

function fn1(a , b){

return a*b;

}

console.log(fn1.prototype); // 函数默认添加的原型

console.log(fn1.constructor); // 构造器指向

在这里插入图片描述

  • 从上面我们可以看到:函数fn1的原型是Object(默认添加的,所以为空)

  • 函数的构造器是 Function

  • 当然,我们也可以手动给它添加原型属性和方法:

function fn1(a , b){

return a*b;

}

// 手动添加原型属性和方法

// 通过 new 关键字可以继承

fn1.prototype.name = “小明”;

fn1.prototype.age = 18;

fn1.prototype.fn = function(){

console.log(“年纪是:”+this.age);

}

1.2 原型链( __ proto __ )

  • 定义:有限的实例对象和原型之间组成有限链,就是用来实现共享属性和继承的

  • 从1.1中,我们知道了:所有的函数都是 Function 的实例。在构造函数上都有一个原型属性 prototype,该属性也是一个对象;那么在原型对象上有一个 constructor 属性,该属性指向的就是构造函数;

  • 而实例对象上有一个 _ proto _ 属性,该属性也指向原型对象,并且该属性不是标准属性,不可以用在编程中,该属性用于浏览器内部使用(只用于看,不能操作

在这里插入图片描述

你需要理解这几句话:

  • 在函数里有一个属性prototype

  • 由该函数创建的对象默认会连接到该属性上

  • _proto_是站在对象角度来说的

  • prototype 是站在构造函数角度来说的

  • 如下图:

在这里插入图片描述

看图看不懂?代码来说话:

function Person() {

}

Person.prototype.name = “养猪的王某人”;

Person.prototype.age = 18;

Person.prototype.getAge = function () {

console.log(this.age);

}

let person1 = new Person();

console.log(person1);

console.log(person1.name); // 继承父级的属性

console.log(person1.constructor);

  • 打印结果:

在这里插入图片描述

图解:

在这里插入图片描述

  • person1 通过 new关键字继承 Person(),可以得到原型链上的属性和方法

  • 说的通俗一点,小明上学,自己挣不到钱,可以用住他爸妈的房子,花他们的钱,这就属于继承(血脉继承)

  • 函数内的构造器(constructor)指向构造他的函数

原型链的查找规则:

  • 由下往上找,一层一层找,直到找到 null,如果找到 null还没找到,就报错。
  1. 寻找自身属性,如果找到了,就返回该值

  2. 如果没找到,继续往上找(逐级)

  3. 直到找到 null为止

  4. 如果还没找到,抛出错误

看了这么久,休息一会儿吧

在这里插入图片描述

3. this 指向问题


  • this 的指向在函数创建的时候是确定不了的,只有函数执行的时候才能确定this到底指向谁。

  • 一般来说,谁调用,指向谁(并不是所有情况)

  • 最外层的 this (指向window)

  • 方法内的 this(依然指向window)

function a(){

let userName = “张三”;

console.log(this) // window

}

a(); // 相当于window.a()

  • 对象内的 this(看调用情况)

let o = {

userName: ‘张三’,

fn:function(){

console.log(this.userName);

}

}

o.fn(); // 打印结果:张三 o调用 this 指向o

最后

小编综合了阿里的面试题做了一份前端面试题PDF文档,里面有面试题的详细解析

开源分享:【大厂前端面试题解析+核心总结学习笔记+真实项目实战+最新讲解视频】

虽只说了一个公司的面试,但我们可以知道大厂关注的东西并举一反三,通过一个知识点延伸到另一个知识点,这是我们要掌握的学习方法,小伙伴们在这篇有学到的请评论点赞转发告诉小编哦,谢谢大家的支持!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值