JS面试题|[2024-12-26]

news/2024/12/27 19:01:56/

1.事件委托是什么

又叫事件代理,原理就是直接利用了事件冒泡的机制来实现,也就是说把子元素的事件绑定到了父元素的身上,如果子元素阻止了事件冒泡,那么委托也就不成立了。

阻止事件冒泡:event.stopPropagation()

addEventListener('click',函数名,true/false) 默认是false(事件冒泡),true(事件捕获)

事件冒泡的好处:提高性能,减少事件的绑定,也就是减少了内存的占用。

2.基本数据类型和引用数据类型的区别

基本数据类型:String、Number、Boolean、undefined、null

        基本数据类型保存在栈内存中,保存的就是一个具体的值

引用数据类型:Object、Function、Array

        保存在堆内存当中,声明一个引用类型的变量,它保存的是引用数据的地址

        假如声明两个引用类型同时指向了一个地址的时候,修改其中一个那么另外一个也会改变

javascript">var obj = {name:'张三',age:18
}
var obj1 = obj;
obj1.name = '李四';
console.log(obj);
console.log(obj1);------------------
{name:'李四',age:18}
{name:'李四',age:18}

3.说一下原型链

原型就是一个普通对象,它是为构造函数的实例共享属性和方法;所有实例中引用的原型都是同一个对象

使用prototype可以把方法挂在原型上,内存只保存一份

javascript">function Person(){this.say = function(){console.log('唱歌');}
}
Person.prototype.look = function(){console.log('红楼梦');
}
var p1 = new Person();
var p2 = new Person();
p1.say();
p2.say();// 调用几次,内存中就保存几次
p1.look();
p2.look();// 内存中只保存一次

__proto__可以理解为指针,实例对象中的属性,指向了构造函数的原型(prototype)

        p1.__proto__ === Person.prototype  ----  true

一个实例对象在调用属性和方法的时候,会依次从实例本身、构造函数原型、原型的原型上去查找

4.new操作符具体做了什么

1.先创建一个空对象

2.把空对象和构造函数通过原型链进行链接

3.把构造函数的this绑定到新的空对象身上

4.根据构造函数返回的类型判断,如果是值类型,则返回对象,如果是引用类型,就要返回这个引用类型

javascript">function newFun(Fun,...args){// 1.先创建一个空对象let newObj = {};// 2.把空对象和构造函数通过原型链链接newObj.__proto__ = Fun.prototype;// 3.把构造函数的this绑定到新的空对象身上const result = Fun.apply(newObj,args);// 4.根据构造函数返回的类型判断,如果是值类型,则返回对象,如果是引用类型,就要返回这个引用类型return result instanceof Object ? result : newObj;
}function Person(name){this.name = name;
}
Person.prototype.say = function(){consoel.log('123456');
}
const p1 = newFun(Person,'张三');
p1.say(); // 123456
console.log(p1); // Person {name:'张三'}

 5.JS是如何实现继承的?

1.原型链继承

        让一个构造函数的原型是另一个类型的实例,那么这个构造函数new出来的实例就具有该实例的属性。

javascript">function Parent(){this.isShow = true;this.info = {name:'abc',age:18};
}
Parent.prototype.getInfo = function(){console.log(this.info);console.log(this.isShow);
}
function Child(){}
Child.prototype = new Parent();let child1 = new Child();
child1.info.gender = '男';
child1.getInfo(); //{name:'abc',age:18,gender:'男'} truelet child2 = new Child();
child2.isShow = false;
conosle.log(child2.info.gender); // 男
child2.getInfo(); //{name:'abc',age:18,gender:'男'} false

        优点:写法方便简单,容易理解

        缺点:对象实例共享所有继承的属性和方法。无法向父类构造函数传参

2.借用构造函数继承

        在子类型构造函数的内部调用父类型构造函数;使用apply() 或 call() 方法将父对象的构造函数绑定在子对象上。

javascript">function Parent(gender){this.info = {name:'yyy',age:18,gender:gender}
}function Child(gender){Parent.call(this,gender);
}let child1 = new Child('男');
child1.info.nickname = 'zzzz';
console.log(child1.info); // {name:'yyy',age:18,gender:'男',nickname:'zzzz'}let child2 = new Child('女');
console.log(child2.info); // {name:'yyy',age:18,gender:'女'}

        优点:解决了原型链实现继承的不能传参的问题和父类的原型共享的问题

        缺点:方法都在构造函数中定义,因此无法实现函数复用

                   在父类的原型中定义的方法,对于子类型而言是不可见的,结果所有类型都是

                   只能使用构造函数模式     

3.组合式继承

        将 原型链 和 借用构造函数 的组合到一起。使用原型链实现对原型属性和方法的继承,而通过借用构造函数来实现对实例属性的继承。这样,既通过在原型上定义方法实现了函数复用,又能够保证每一个实例都有自己的属性。

javascript">function Parent(gender){console.log('执行次数');this.info = {name:'yyy',age:18,gender:gender}
}Parent.prototype.getInfo = function(){ // 使用原型链继承原型上的属性和方法console.log(this.info.name,this.info.age);
}function Child(gender){Parent.call(this,gender); // 使用构造函数法传递参数
}Child.prototype = new Parent();let child1 = new Child('男');
child1.info.nickname = 'zzzz';
child1.getInfo(); // 'yyy' 18
console.log(child1.info); // {name:'yyy',age:18,gender:'男',nickname:'zzzz'} let child2 = new Child('女');
console.log(child2.info); // {name:'yyy',age:18,gender:'女'}

        优点:解决了原型链继承和借用构造函数继承造成的影响

        缺点:无论在什么情况下,都会调用两次父类构造函数,一次是在创建子类原型的时候,另一次是在子类构造函数内部

4.ES6的class类继承

        Class通过extends关键字实现继承,其实质就是先创造出父类的this对象,然后用子类的构造函数修改this

        子类的构造方法中必须调用super方法,且只有在调用了super()之后才能使用this,因为子类的this对象是继承父类的this对象,然后对其进行加工,而super方法表示的是父类的构造函数,用来新建父类的this对象

javascript">class Animal{constructor(kind){this.kind = kind;}getKind(){return this.kind;}
}// 继承Animal
class Cat extends Animal{constructor(name){// 子类的构造方法中必须先调用super方法super('cat');this.name = name;}getCatInfo(){console.log(this.name + ':' + super.getKind())}
}
const cat1 = new Cat('buding'); 
cats.getCatInfo(); // buding:cat

        优点:语法简单易懂,操作更方便

        缺点:并不是所有的浏览器都是支持class关键字


http://www.ppmy.cn/news/1558593.html

相关文章

一个特别的串口通讯

背景 设备是EPICS流式细胞仪,这个设备的控制系统是在DOS系统上的。数据存储在硬盘上,不带串口通讯功能。我们遇到了这个设备后,就开发了一个DOS下的执行程序通过串口,将最新的数据自动上传到服务器上。 编译工具 Turbo C 数据…

MIT实验笔记冲刺2 实验部分

目录 实现trace调用(系统调用跟踪(中等)) 攻击 xv6(中等) 下面就是实验的部分,Lab2中的实验有两个。一个是syscall implementations,另一个则是利用未抹除的内存内容来读取上一个内…

【MySQL】在MySQL中如何定位慢查询?

MySQL慢查询定位面试问答总结 一、面试官提问 在MySQL中如何定位慢查询? 二、面试者回答 (一)整体思路 定位慢查询主要有两种方式,一种是使用开源工具,另一种是利用MySQL自带的慢日志查询功能。 (二&a…

c# 线程 AutoResetEvent 的Set()函数多次调用

本文部分内容摘自ChatGPT 在 C# 中,AutoResetEvent 是一种用于线程同步的机制,它的行为类似于一个信号量,主要用于在多线程环境中发出信号并控制线程的执行。AutoResetEvent 的主要特点是每当调用 Set() 方法时,信号会被设置&…

设置postgreSQL字段自增

CREATE SEQUENCE ai_mirror_opcode_seq START WITH 1 INCREMENT BY 1 NO MINVALUE NO MAXVALUE CACHE 1; nextval(ai_mirror_opcode_seq) 手动创建序列并设置默认值: 如果你需要更细粒度的控制,可以手动创建一个序列,并将其设置为某个字段的…

STM32串口无法正常中断

1.串口无法中断是由于第一次使用 HAL_UART_Receive_IT(&huart6(uint8_t*)&My_Control.Data.SeriaReceivelData,sizeof(My_Control.Data.SeriaReceivelData));//使能串口接受中断 之后没有在回调函数里再一次使用 2.串口无法使用,观察寄存器 发现RXNE标志…

springboot495基于java的物资综合管理系统的设计与实现(论文+源码)_kaic

摘 要 如今社会上各行各业,都喜欢用自己行业的专属软件工作,互联网发展到这个时候,人们已经发现离不开了互联网。新技术的产生,往往能解决一些老技术的弊端问题。因为传统物资综合管理系统信息管理难度大,容错率低&am…

Android--java实现手机亮度控制

文章目录 1、开发需求2、运行环境3、主要文件4、布局文件信息5、手机界面控制代码6、debug 1、开发需求 需求:开发一个Android apk实现手机亮度控制 2、运行环境 Android studio最新版本 3、主要文件 app\src\main\AndroidManifest.xml app\src\main\res\layou…