深夜爆肝JS好文!2024字节跳动春招面试题深度讲解,开发web应用

文章讲述了JavaScript中的JSON深拷贝限制,介绍了一种原生JS实现深拷贝的方法,同时解析了原型和原型链的概念,讨论了this关键字的动态指向以及new关键字的作用。最后介绍了事件委托的原理和在实际开发中的应用。
摘要由CSDN通过智能技术生成

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

  • 箭头函数本身没有作用域,所以 this 指向它的上级作用域

var id = 66;

function fn5(){

setTimeout(()=>{

console.log(this.id + ‘====id’)

},500)

}

fn5({id:21});

  • 箭头函数,this 指向定义时候的对象,fn5在window作用域下,所以this指向window;

  • 箭头函数的外层,fn5函数的this就是window

  • 箭头函数的this与它的执行没有关系,在定义的时候就决定了

在这里插入图片描述

4. new 关键字做了什么?


function Person(){

this.name = ‘朱小明’;

this.fn = function(){

console.log(‘名字是:’ + this.name)

}

}

let person1 = new Person();

  1. 创建一个空的对象

  2. 链接到原型

  3. 绑定this指向,执行构造函数

  4. 确保返回的是对象

  5. 代码来解释一下:

let obj = new Object();

obj.proto= Person.prototype; // 设置原型链

let result = Person.call(obj); // 让Person的this指向obj,并执行Person函数体

// 判断Person的返回值类型:

// 如果是值类型,返回obj。如果是引用类型,就返回这个引用类型的对象

if (typeof(result) == “object”){

person1 = result;

}

else{

person1 = obj;;

}

  • 默认情况下函数返回值为 undefined,即没有显示定义返回值的话

  • 构造函数例外,new 构造函数在没有 return 的情况下默认返回新创建的对象

5. 原生JS如何实现事件委托?


  • 事件委托就是利用事件冒泡,只指定一个事件处理程序,就可以管理某一类型的所有事件

  • 举个栗子:

  • 有三个同事预计会在周一收到快递。为签收快递,

  • 有两种办法:一是三个人在公司门口等快递;二是委托给前台MM代为签收。

  • 前台MM收到快递后,她会判断收件人是谁,然后按照收件人的要求签收,

  • 甚至代为付款。这种方案还有一个优势,那就是即使公司里来了新员工(不管多少),前台MM也会在收到寄给新员工的快递后核实并代为签收。

具体实现:

事件委托
    • 0
    • 1
    • 2
    • 3
    • 4
    • 5
    • 点我添加一个li

    评论
    添加红包

    请填写红包祝福语或标题

    红包个数最小为10个

    红包金额最低5元

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

    抵扣说明:

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

    余额充值