JavaScript面试问题(1)

目录


1.JavaScript中的垃圾回收机制


  1. 标记清除(最常见)

    说白了就是对所有的变量加标记,用的时候删掉标记,不用了再加上,最后离开环境的时候把所有有标记的变量清除

  当变量进入执行环境的时候,比如在函数中声明 个变量,垃圾回收器将其标记为“进入环 当变 量离 开环境的时候(函数执行结束),将其标记为“离开环境”。
  	
  垃圾回收器会在运行的时候给存储在内存中的所有变量加上标记,然后去掉环境中的变量,以及被环境中变量所引用的变 (闭包)的标记 在完成这些之后仍然存在的标记就是要删除的变量
  1. 引用计数
  在低版本的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只有函数作用域)

  • 优点是可以避免全局变量的污染;
  • 缺点是闭包会常驻内存, 加内存使用 ,使用不当很容易造成内存泄漏

闭包的三个特性:

  1. 函数嵌套函数
  2. 在函数内部可以引用外部的参数和变量
  3. 参数和变量不会以垃圾回收机制回收

5.:为什么不建议在 JavaScript 中使用 innerHTML?


通过innerHTML修改内容,每次都会刷新,因此很慢。在innerHTML中没有验证的机会,因此更容易在文档中插入错误代码,使网页不稳定。

6.null undefined 的区别


null的要点在于不存在

undefined的要点在于没有找到应当存在的值,即一个没有值的变量

null用来表示尚未存在的对象,常用来表示函数企图返回一个不存在的对象。
undefined表示“缺少值”,即此处应该有一个值,但是还没有定义,典型用法是如下。

  1. 如果变量声明了,但没有赋值,它就等于undefined。
  2. 当调用函数时,如果没有提供应该提供的参数,该参数就等于undefined。
  3. 如果对象没有赋值,该属性的值为undefined。
  4. 当函数没有返回值时,默认返回undefined。

null表示“没有对象”,即此处不应该有值,典型用法是如下。

  1. 作为函数的参数,表示该函数的参数不是对象。
  2. 作为对象原型链的终点。

7.new操作符


  1. 创建一个空对象。
  2. 由 this变量引用该对象。
  3. 该对象继承该函数的原型(更改原型链的指向)。
  4. 把属性和方法加入到this引用的对象中。
  5. 新创建的对象由this引用,最后隐式地返回this。

8.哪些操作会造成内存泄漏?


内存泄漏抬不再拥有或需要任何对 数据 )之后 ,它们仍然存在于内存中

  1. 如果 setTimeout 的第一个参数使用字符串而非函数,会引发内存泄漏。

  2. 闭包、控制台日志、循环(在两个对象彼此引用且彼此保留时,就会产生一个循环)

    等会造内存泄漏。

9.JavaScript 对象的几种创建方式


  1. 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);
    
  2. 对象字面量式 特点: 键值对 缺点:使用同一个接口创建很多对象,会产生大量重复代码。

    var person = {
        name: 'kk',
        age: 12,
        job: 'IT',
        say: function () {
            console.log('hello' + this.name);
        }
    }
    console.log(person);
    
  3. 工厂模式 特点: 一次性创建多个对象

    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);
    
  4. 安全工厂模式

  5. 构造函数模式 特点:使用了函数封装,比较显眼的就是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);
    
  6. 原型模式 特点:构造函数创建对象,通过原型添加对象属性和方法,比较显眼的就是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);
    
  7. 混合构造函数和原型模式 特点; 构造函数模式用于定义实例属性,而原型模式用于定义方法和共享属性。

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来添加

  1. 动态原型模式 特点:动态原型模式把所有信息都封装在了构造函数中,而通过在构造函数中初始化原型(仅在必要的情况下),又保持了同时使用构造函数和原型的优点。

    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} 这样的感觉

  2. 寄生构造函数 这种模式的基本思想是创建一个函数,该函数的作用仅仅是封装创建对象的代码,然后再返回新创建的对象;但从表面上看,这个函数又很像是典型的构造函数。

	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创建的对象

  1. 稳妥构造函数模式 所谓稳妥对象,指的是没有公共属性,而且其方法也不可引用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);

简单来想,就是四类基础的对象创建方式:

  1. Object 构造函数式
  2. 对象字面量式
  3. 构造函数式
  4. 原型模式

其他的便是对以上四种的拓展与合并

10.js实现异步编程


方法 1,通过回调函数优点是简单、容易理解和部署 缺点是不利 于代码的阅和维护,各个部分之间高度耦合( Coupling ),流程混乱,而且每个任务只能指定一个回调函数。

方法2 ,通过事件监听 可以绑定多个事件,每个事件可以指定多个回调函数,而且可以“去耦合”( Decoupling ),有利于实现模块化;缺点是整个程序都要变成事件驱动型,运行流程会变得很不清晰

方法3 ,采用发布订阅方式 与“事件监听”类似, 但是明显优于后者

方法 4,通过 Promise 对象实现 Promise 对象是 CommonJS 工作组提出的 种规范,旨在为异步编程提供统一接口 它的思想是,每一个异步任务返回一个 Promise 对象,该对象有 then 方法,九许指定回调函数

posted @   szfzb  阅读(24)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通
点击右上角即可分享
微信分享提示