【建议收藏】2024前端校招BATJ面试秘籍,为你保驾护航金三银四,直通大厂!(2)

p1 = new Person()
p1 instanceof Person // true

Object.prototype.toString.call()可以检测所有的数据类型,算是一个比较完美的方法了。

var obj={}
var arr=[]
console.log(Object.prototype.toString.call(obj)) //[object Object]
console.log(Object.prototype.toString.call(arr)) //[object Array]

深浅拷贝

浅拷贝

Object.assign() //es6的方法

Object.assign会合并对象生成一个新对象。如果对象的属性是普通类型改变之后新对象不会改变,如果是引用类型改变后新对象也会改变,所以Object.assign实际上还是浅拷贝。

var obj={aa:1,b:{item:‘45’}};
var newObj=Object.assign({},obj);
obj.aa=2;
obj.b.item=‘kk’;
console.log(newObj.aa); //1
console.log(newObj.b.item); //kk

深拷贝

JSON.parse(JSON.stringify(obj))

利用JSON.stringify(obj)将对象先转为json字符串,再JSON.parse()转回为json对象可以实现深拷贝,这也是比较常用的一种方法。

用js实现一个深拷贝

其实深拷贝可以拆分成 2 步,浅拷贝 + 递归,浅拷贝时判断属性值是否是对象,如果是对象就进行递归操作,两个一结合就实现了深拷贝。

function cloneDeep(source) {
if (!isObject(source)) return source; // 非对象返回自身
var target = Array.isArray(source) ? [] : {};
for (var key in source) {
if (source.hasOwnProperty(i)) {
if (isObject(source[key])) {
target[key] = cloneDeep(source[key]); // 注意这里
} else {
target[key] = source[key];
}
}
}
return target;
}
function isObject(obj) {
return typeof obj === ‘object’ && obj != null;
}

二、作用域

变量声明提升

  • 在 JavaScript 中,函数声明(function aa(){})与变量声明(var)经常被 JavaScript 引擎隐式地提升到当前作用域的顶部。
  • 函数声明的优先级高于变量,如果变量名跟函数名相同且未赋值,则函数声明会覆盖变量声明
  • 声明语句中的赋值部分并不会被提升,只有变量的名称被提升

作用域链

因为函数的嵌套形成作用域的层级关系。当函数执行时,从当前作用域开始搜,没有找到的变量,会向上层作用域查找,直至全局函数,这就是作用域链。

  • 在 JavaScript 中,作用域为 function(){}内的区域,称为函数作用域。
  • 全局函数无法查看局部函数的内部细节,但局部函数可以查看其上层的函数细节,直至全局细节

闭包

闭包的原理就是作用域链,比函数F内部有一个函数G,函数 G可以访问到函数F中的变量,那么函数G就是闭包。

function F() {
let a = 1
window.G = function () {
console.log(a)
}
}
F()
G() // 1

三、原型和继承

js 创建对象的几种方式

对象字面量的方

var obj={};

new一个构造函数

function Pel(){}
var p=new Pel();
p.name=“hu”;
p.age=“25”;
p.address=function(){
}

new一个内置对

var obj=new Object();

Object.create()创建对象

var test = Object.create({x:1});

给大家留一道思考题,new Object() 、 Object.create()、{},这三种方式创建对象有什么区别。

JS 如何实现一个类

构造函数法

缺点:用到了 this 和 prototype,编写复杂,可读性差

function P(name, age){
this.name = name;
this.age= age;
}
P.prototype.sal= function(){

}
var pel= new P(“jj”, 1);
pel.sell()

ES6 语法糖 class

class Point {
constructor(x, y) {
this.x = x;
this.y = y;
}
toString() {
return ‘(’ + this.x + ', ’ + this.y + ‘)’;
}
}
var point = new Point(2, 3);

原型链

一句话解析什么是原型链

遍历一个实列的属性时,先遍历实列对象上的属性,再遍历它的原型对象,一直遍历到Object

任何一个类(函数)都有原型对象,原型对象至少有两个属性(constructor,proto)。constructor指向函数本身,proto指向父类原型对象。

函数上有一个prototype属性,指向原型对象,通过它可以访问原型对象

函数的实列可以直接访问原型对象(因为实列上有proto指向构造函数的原型对象)

function Dog(){} //类
var obj=new Dog(); //实列
obj.name=‘沪江’;
Dog.prototype.name=“旺财”;
Dog.prototype.eat=function(){
console.log(this.name);
};
console.log(Dog.prototype.name); //旺财
console.log(obj.prototype); //undefined,prototype是类上才有的,实列上没有
obj.eat(); //沪江(先遍历实列对象上的属性,再遍历它的原型对象)

继承

Js如何实现继承?

构造函数绑定:使用 call 或 apply 方法,将父对象的构造函数绑定在子对象上

function Cat(name,color){
Animal.apply(this, arguments);
this.name = name;
this.color = color;
}

实例继承:将子对象的 prototype 指向父对象的一个实例

Cat.prototype = new Animal();
Cat.prototype.constructor = Cat;

拷贝继承:如果把父对象的所有属性和方法,拷贝进子对象

function extend(Child, Parent) {
var p = Parent.prototype;
var c = Child.prototype;
for (var i in p) {
c[i] = p[i];
}
c.uber = p;
}

原型继承:将子对象的 prototype 指向父对象的 prototype

function extend(Child, Parent) {
var F = function(){};
F.prototype = Parent.prototype;
Child.prototype = new F();
Child.prototype.constructor = Child;
Child.uber = Parent.prototype;
}

ES6 语法糖 extends继承

class ColorPoint extends Point {
constructor(x, y, color) {
super(x, y); // 调用父类的constructor(x, y)
this.color = color;
}
toString() {
return this.color + ’ ’ + super.toString(); // 调用父类的toString()
}
}

❤️篇幅有限,更详细的内容点击我获取完整版pdf查看❤️

四、new和this

new 操作符具体干了什么?

当我们new一个数据的时候,new操作符到底做了什么?

  • 首先是创建实例对象{}
  • this 变量引用该对象,同时还继承了构造函数的原型
  • 其次属性和方法被加入到 this 引用的对象中
  • 并且新创建的对象由 this 所引用,最后隐式的返回 this

new的模拟实现

function objectFactory() {

var obj = new Object(),//从Object.prototype上克隆一个对象

Constructor = [].shift.call(arguments);//取得外部传入的构造器

var F=function(){};
F.prototype= Constructor.prototype;
obj=new F();//指向正确的原型

var ret = Constructor.apply(obj, arguments);//借用外部传入的构造器给obj设置属性

return typeof ret === ‘object’ ? ret : obj;//确保构造器总是返回一个对象

};

this 对象的理解

普通函数

  • this 总是指向函数的直接调用者
  • 如果有 new 关键字,this 指向 new 出来的实例对象
  • 在事件中,this 指向触发这个事件的对象
  • IE 下 attachEvent 中的 this 总是指向全局对象 Window
  • 箭头函数中,函数体内的this对象,就是定义时所在作用域的对象,而不是使用时所在的作用域的对象。

function foo() {
console.log(this.a)
}
var a = 1
foo() //1

const obj = {
a: 2,
foo: foo
}
obj.foo() //2

const c = new foo() //undefined

  • 对于直接调用 foo 来说,不管 foo 函数被放在了什么地方,this 一定是window
  • 对于 obj.foo() 来说,我们只需要记住,谁调用了函数,谁就是 this,所以在这个场景下 foo 函数中的 this 就是 obj 对象
  • 对于 new 的方式来说,this 被永远绑定在了 new出来的对象上,不会被任何方式改变 this

说完了以上几种情况,其实很多代码中的 this 应该就没什么问题了,下面让我们看看箭头函数中的 this

function a() {
return () => {
return () => {
console.log(this)
}
}
}
a()()() //Window

  • 首先箭头函数其实是没有 this 的,箭头函数中的 this 只取决包裹箭头函数的第一个普通函数的 this。在这个例子中,因为包裹箭头函数的第一个普通函数是 a,所以此时的 this 是 window。另外对箭头函数使用 bind这类函数是无效的。

五、apply、call、bind

callapplybindFunction对象自带的三个方法,都是为了改变函数体内部 this 的指向。
apply 、 call 、bind 三者第一个参数都是 this 要指向的对象,也就是想指定的上下文;
apply 、 call 、bind 三者都可以利用后续参数传参;
bind 是返回对应 函数,便于稍后调用;apply 、call 则是立即调用 。

function fruits() {}

fruits.prototype = {
color: ‘red’,
say: function() {
console.log(this.color);
}
};

var apple = new fruits();

apple.say(); // red, 此时方法里面的this 指的是fruits

banana = {color: ‘yellow’};
apple.say.call(banana); //yellow,此时的this的指向已经通过call()方法改变了,指向的是banana,this.color就是banana.color=‘yellow’;

apple.say.apply(banana);//yellow,同理,此时的this的指向已经通过apply()方法改变了,指向的是banana,this.color就是banana.color =‘yellow’;

apple.say.apply(null); //undefined, null是window下的,此时,this 就指向了window ,但是window下并没有clolr这个属性,因此this.clolr就是window.color=undefined;

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数前端工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年Web前端开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
img
img
img
img
img
img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上前端开发知识点,真正体系化!

由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且后续会持续更新

如果你觉得这些内容对你有帮助,可以添加V获取:vip1024c (备注前端)
img

其实前端开发的知识点就那么多,面试问来问去还是那么点东西。所以面试没有其他的诀窍,只看你对这些知识点准备的充分程度。so,出去面试时先看看自己复习到了哪个阶段就好。

这里再分享一个复习的路线:(以下体系的复习资料是我从各路大佬收集整理好的)

《前端开发四大模块核心知识笔记》

最后,说个题外话,我在一线互联网企业工作十余年里,指导过不少同行后辈。帮助很多人得到了学习和成长。

我意识到有很多经验和知识值得分享给大家,也可以通过我们的能力和经验解答大家在IT学习中的很多困惑,所以在工作繁忙的情况下还是坚持各种整理和分享。

一个人可以走的很快,但一群人才能走的更远。不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎扫码加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
img

习资料是我从各路大佬收集整理好的)

《前端开发四大模块核心知识笔记》

最后,说个题外话,我在一线互联网企业工作十余年里,指导过不少同行后辈。帮助很多人得到了学习和成长。

我意识到有很多经验和知识值得分享给大家,也可以通过我们的能力和经验解答大家在IT学习中的很多困惑,所以在工作繁忙的情况下还是坚持各种整理和分享。

一个人可以走的很快,但一群人才能走的更远。不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎扫码加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
[外链图片转存中…(img-nfF8WQgn-1712932032674)]

  • 17
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值