JavaScript面试问题(1)
目录
1.JavaScript中的垃圾回收机制
-
标记清除(最常见)
说白了就是对所有的变量加标记,用的时候删掉标记,不用了再加上,最后离开环境的时候把所有有标记的变量清除
当变量进入执行环境的时候,比如在函数中声明 个变量,垃圾回收器将其标记为“进入环 当变 量离 开环境的时候(函数执行结束),将其标记为“离开环境”。 垃圾回收器会在运行的时候给存储在内存中的所有变量加上标记,然后去掉环境中的变量,以及被环境中变量所引用的变 (闭包)的标记 在完成这些之后仍然存在的标记就是要删除的变量
- 引用计数
在低版本的IE中经常会发生内存泄漏,很多时候就是因为它采用引用计数的方式进行垃圾回收。==引用计数的策略是跟踪记录每个值被使用的次数。==当声明了一个变量并将一个引用类型赋值给该变量的时候,这个值的引用次数就加1。如果该变量的值变成了另外一个,则这个值的引用次数减1。当这个值的引用次数变为0的时候,说明没有变量在使用,这个值没法被访问。因此,可以将它占用的空间回收,这样垃圾回收器会在运行的时候清理引用次数为0的值占用的空间。
在IE中虽然JavaScript对象通过标记清除的方式进行垃圾回收,但是BOM 与 DOM对象是用引用计数的方式回收垃圾的。也就是说,只要涉及BOM和DOM,就会出现循环引用问题。
2.DOM节点的类型
四种,文档,元素,属性,文本
- 整个文档是一个文档(Document )节点。
- 每个 HTML标签是一个元素( Element)节点。
- 每一个HTML属性是一个属性( Attribute)节点。
- 包含在HTML元素中的文本是文本( Text)节点。
3.script标签中defer和async属性的区别
这俩都是js中延迟加载的方式
defer:立即下载,延迟执行。
async:立即下载,异步执行,异步加载页面其他内容
4.对闭包的理解
JavaScript 中,函数即闭包,只有函数才会产生作用域(但这不意味着js只有函数作用域)
- 优点是可以避免全局变量的污染;
- 缺点是闭包会常驻内存, 加内存使用 ,使用不当很容易造成内存泄漏
闭包的三个特性:
- 函数嵌套函数
- 在函数内部可以引用外部的参数和变量
- 参数和变量不会以垃圾回收机制回收
5.:为什么不建议在 JavaScript 中使用 innerHTML?
通过innerHTML修改内容,每次都会刷新,因此很慢。在innerHTML中没有验证的机会,因此更容易在文档中插入错误代码,使网页不稳定。
6.null undefined 的区别
null的要点在于不存在
undefined的要点在于没有找到应当存在的值,即一个没有值的变量
null用来表示尚未存在的对象,常用来表示函数企图返回一个不存在的对象。
undefined表示“缺少值”,即此处应该有一个值,但是还没有定义,典型用法是如下。
- 如果变量声明了,但没有赋值,它就等于undefined。
- 当调用函数时,如果没有提供应该提供的参数,该参数就等于undefined。
- 如果对象没有赋值,该属性的值为undefined。
- 当函数没有返回值时,默认返回undefined。
null表示“没有对象”,即此处不应该有值,典型用法是如下。
- 作为函数的参数,表示该函数的参数不是对象。
- 作为对象原型链的终点。
7.new操作符
- 创建一个空对象。
- 由 this变量引用该对象。
- 该对象继承该函数的原型(更改原型链的指向)。
- 把属性和方法加入到this引用的对象中。
- 新创建的对象由this引用,最后隐式地返回this。
8.哪些操作会造成内存泄漏?
内存泄漏抬不再拥有或需要任何对 数据 )之后 ,它们仍然存在于内存中
-
如果 setTimeout 的第一个参数使用字符串而非函数,会引发内存泄漏。
-
闭包、控制台日志、循环(在两个对象彼此引用且彼此保留时,就会产生一个循环)
等会造内存泄漏。
9.JavaScript 对象的几种创建方式
-
Object 构造函数式 特点: new Object(value) 缺点:使用同一个接口创建很多对象,会产生大量重复代码。
var person = new Object(); person.name = 'kk'; person.age = 12, person.job = 'IT', person.say = function() { console.log('hello' + this.name); } console.log(person);
-
对象字面量式 特点: 键值对 缺点:使用同一个接口创建很多对象,会产生大量重复代码。
var person = { name: 'kk', age: 12, job: 'IT', say: function () { console.log('hello' + this.name); } } console.log(person);
-
工厂模式 特点: 一次性创建多个对象
function createPerson(name, age, job) { var obj = new Object(); obj.name = name; obj.age = age; obj.job = job; obj.say = function () { console.log('hello' + this.name); } return obj; } var person = createPerson('kk', 12, 'IT'); console.log(person);
-
安全工厂模式
-
构造函数模式 特点:使用了函数封装,比较显眼的就是function
function Person(name, age, job) { this.name = name; this.age = age; this.job = job; this.say = function () { console.log('hello' + this.name); } } var person = new Person('kk', 12, 'IT'); console.log(person);
-
原型模式 特点:构造函数创建对象,通过原型添加对象属性和方法,比较显眼的就是prototype属性,所有的属性方法都依赖prototype来添加
function Person() { } Person.prototype.name = "kk"; Person.prototype.age = 12; Person.prototype.job = "IT"; Person.prototype.sayName = function () { console.log(this.name); }; var person = new Person(); console.log(person);
-
混合构造函数和原型模式 特点; 构造函数模式用于定义实例属性,而原型模式用于定义方法和共享属性。
function Person(name, age, job) {
this.name = name;
this.age = age;
this.job = job;
}
Person.prototype.sayName = function () {
console.log(this.name);
}
var person = new Person('kk', 12, 'IT');
console.log(person);
大概就是属性放在function里,方法通过prototype来添加
-
动态原型模式 特点:动态原型模式把所有信息都封装在了构造函数中,而通过在构造函数中初始化原型(仅在必要的情况下),又保持了同时使用构造函数和原型的优点。
function Person(name,age,job){ //属性 this.name = name; this.age = age; this.job = job; //方法 if(typeof this.sayName != "function"){ Person.prototype.sayName = function(){ console.log(this.name); } } } var person = new Person("kk" , 12, "IT"); console.log(person);
emmm怎么说 ,就是function(){e.prototype.type} 这样的感觉
-
寄生构造函数 这种模式的基本思想是创建一个函数,该函数的作用仅仅是封装创建对象的代码,然后再返回新创建的对象;但从表面上看,这个函数又很像是典型的构造函数。
function Person(name,age,job){
var o = new Object();
o.name = name;
o.age = age;
o.job = job;
o.sayName = function(){
console.log(this.name);
};
return o;
}
var person = new Person('kk',12,'IT');
console.log(person);
emmm,像工厂模式一样可以一次性创建多个对象的样子,特点是在function创建函数后还使用了new去创建了对象,还要使用return来返回new创建的对象
- 稳妥构造函数模式 所谓稳妥对象,指的是没有公共属性,而且其方法也不可引用this的对象。稳妥对象最适合在一些安全的环境中(这些环境中会禁止使用this和new),或者在防止数据被其他应用程序(如Mashup程序)改动时使用。 稳妥构造函数遵循与寄生构造函数类似的模式,但有两点不同:一是新创新对象的实例方法不引用this;二是不使用new操作符调用构造函数。
function Person(name,age,job){
//创建要返回的对象
var o = new Object();
o.sayName = function(){
return name;
};
//返回对象
return o;
}
var person = new Person('kk',12,'IT');
console.log(person);
简单来想,就是四类基础的对象创建方式:
- Object 构造函数式
- 对象字面量式
- 构造函数式
- 原型模式
其他的便是对以上四种的拓展与合并
10.js实现异步编程
方法 1,通过回调函数优点是简单、容易理解和部署 缺点是不利 于代码的阅和维护,各个部分之间高度耦合( Coupling ),流程混乱,而且每个任务只能指定一个回调函数。
方法2 ,通过事件监听 可以绑定多个事件,每个事件可以指定多个回调函数,而且可以“去耦合”( Decoupling ),有利于实现模块化;缺点是整个程序都要变成事件驱动型,运行流程会变得很不清晰
方法3 ,采用发布订阅方式 与“事件监听”类似, 但是明显优于后者
方法 4,通过 Promise 对象实现 Promise 对象是 CommonJS 工作组提出的 种规范,旨在为异步编程提供统一接口 它的思想是,每一个异步任务返回一个 Promise 对象,该对象有 then 方法,九许指定回调函数
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通