编程语言
首页 > 编程语言> > 【JavaScript】Interview必背(详细版)

【JavaScript】Interview必背(详细版)

作者:互联网

文章目录

1.介绍一下js的数据类型有哪些,值是如何存储的

2. && 、 || 和 !! 运算符分别能做什么

3.数据类型转换

只有三种情况,分别是

null和underfined没有.toString方法
在这里插入图片描述

4.数据类型判断 typeof,instanceof,constructor,Object.prototype.toString.call()

  1. typeof

typeof 对于原始类型来说,除了 null 都可以显示正确的类型
被解释为object类型的还有数组和null

console.log(typeof 2);               // number
console.log(typeof true);            // boolean
console.log(typeof 'str');           // string
console.log(typeof []);              // object     []数组的数据类型在 typeof 中被解释为 object
console.log(typeof function(){});    // function
console.log(typeof {});              // object
console.log(typeof undefined);       // undefined
console.log(typeof null);            // object     null 的数据类型被 typeof 解释为 object

typeof 对于对象来说,除了函数都会显示 object,所以说 typeof 并不能准确判断变量到底是什么类型,所以想判断一个对象的正确类型,这时候可以考虑使用 instanceof

  1. instanceof

instanceof可以正确判断对象的类型,因为内部机制是通过判断对象的原型链中是不是能找到类型的prototype

console.log(2 instanceof Number);                    // false
console.log(true instanceof Boolean);                // false 
console.log('str' instanceof String);                // false  
console.log([] instanceof Array);                    // true
console.log(function(){} instanceof Function);       // true
console.log({} instanceof Object);                   // true    
// console.log(undefined instanceof Undefined);
// console.log(null instanceof Null);

可以看出instanceof可以精确判断出一个引用数据类型的类型,但是不能精确判断出基本数据类型

因为instanceof是用来测试一个对象在该原型链中是否存在构造函数的prototype属性,也就是判断该对象是否是某一数据类型的实例。
而数字类型,字符串类型,布尔类型不是实例,所以为false。

  1. constructor
console.log((2).constructor === Number); // true
console.log((true).constructor === Boolean); // true
console.log(('str').constructor === String); // true
console.log(([]).constructor === Array); // true
console.log((function() {}).constructor === Function); // true
console.log(({}).constructor === Object); // true

这也是通过判断构造函数中的prototype来进行的
但是修改prototype过后就会使constructor返回值修改,即使他的原型是本来的,但是原型的prototype改了。

function Fn(){};
 
Fn.prototype=new Array();
 
var f=new Fn();
 
console.log(f.constructor===Fn);    // false
console.log(f.constructor===Array); // true 
  1. Object.prototype.toString.call()
var a = Object.prototype.toString;
 
console.log(a.call(2));
console.log(a.call(true));
console.log(a.call('str'));
console.log(a.call([]));
console.log(a.call(function(){}));
console.log(a.call({}));
console.log(a.call(undefined));
console.log(a.call(null));

用call()对传进去的值进行该值的原型链prototype的构造函数type转换为字符串过后的回调

5. 介绍 js 有哪些内置对象?

可以理解成有哪些内核定义的对象

js 中的内置对象主要指的是在程序执行前存在全局作用域里的由 js定义的一些全局值属性、函数和用来实例化其他对象的构造函数对象。一般我们经常用到的如全局变量值 NaN、undefined,全局函数如 parseInt()、parseFloat() 用来实例化对象的构造函数如 Date、Object 等,还有提供数学计算的单体内置对象如 Math 对象。

全局的对象( global objects )或称标准内置对象,不要和 “全局对象(global object)” 混淆。这里说的全局的对象是说在
全局作用域里的对象。全局作用域中的其他对象可以由用户的脚本创建或由宿主程序提供。

标准内置对象的分类
(1)值属性,这些全局属性返回一个简单值,这些值没有自己的属性和方法。
例如 Infinity、NaN、undefined、null 字面量
(2)函数属性,全局函数可以直接调用,不需要在调用时指定所属对象,执行结束后会将结果直接返回给调用者。
例如 eval()、parseFloat()、parseInt() 等
(3)基本对象,基本对象是定义或使用其他对象的基础。基本对象包括一般对象、函数对象和错误对象。
例如 Object、Function、Boolean、Symbol、Error 等
(4)数字和日期对象,用来表示数字、日期和执行数学计算的对象。
例如 Number、Math、Date
(5)字符串,用来表示和操作字符串的对象。
例如 String、RegExp
(6)可索引的集合对象,这些对象表示按照索引值来排序的数据集合,包括数组和类型数组,以及类数组结构的对象。例如 Array
(7)使用键的集合对象,这些集合对象在存储数据时会使用到键,支持按照插入顺序来迭代元素。
例如 Map、Set、WeakMap、WeakSet
(8)矢量集合,SIMD 矢量集合中的数据会被组织为一个数据序列。
例如 SIMD 等
(9)结构化数据,这些对象用来表示和操作结构化的缓冲区数据,或使用 JSON 编码的数据。
例如 JSON 等
(10)控制抽象对象
例如 Promise、Generator 等
(11)反射
例如 Reflect、Proxy
(12)国际化,为了支持多语言处理而加入 ECMAScript 的对象。
例如 Intl、Intl.Collator 等
(13)WebAssembly
(14)其他
例如 arguments

6.undefined与undeclared的区别

7.null和undefined的区别

8.{}和[]的valueOf和toString的结果是什么

9.JS的作用域和作用域链

参考链接

作用域链本质是指向变量对象的指针列表。
作用域链的前端始终都是当前执行上下文的变量对象,全局对象始终都是作用域链的最后一个对象

查找变量的时候,如果当前没找到,可以沿着作用域链往后查找
创建过程与执行上下文的建立有关

10.JS创建对象的几种方式

  1. Object构造函数创建
var Person = new Object();
Person.name = 'Nike';
Person.age = 29;

Person指向用new创建Object引用类型的一个新实例,然后进行值的添加

  1. 使用对象字面量表示
var Person = {};//相当于var Person = new Object();
Person = {
	name:'Nike';
	age:29;
}
  1. 工厂模式:

用函数封装对象细节,通过调用函数进行复用。创建出来的对象无法和某个类型联系起来,没有建立对象和类型间的关系

function createPerson(name,age,job){
 var o = new Object();
 o.name = name;
 o.age = age;
 o.job = job;
 o.sayName = function(){
  alert(this.name); 
 };
 return o; 
}
var person1 = createPerson('Nike',29,'teacher');
var person2 = createPerson('Arvin',20,'student');
  1. 构造函数模式:

只要一个函数通过new调用,就可以称为构造函数。
首先会创建一个对象,然后将对象的原型指向构造函数的prototype,将执行上下文的this值向这个对象,然后用this给对象赋值。

function Person(name,age,job){
 this.name = name;
 this.age = age;
 this.job = job;
 this.sayName = function(){
 alert(this.name);
 }; 
}
var person1 = new Person('Nike',29,'teacher');
var person2 = new Person('Arvin',20,'student');

优点是:
1.创建的对象和构造函数建立了关系,就是prototype,因此可以通过原型来识别对象的类型;也就是说可以通过该对象的原型的prototype判断类型:
2.无显示创建对象
3.直接将属性和方法赋值给了this对象
4.无return

alert(person1 instanceof Object);//ture
alert(person1 instanceof Person);//ture
//instanceof还可以换成
//1.person1.constructor === Object;
//var a = Object.prototype.toString; a.call(person1) === Person

缺点是:每个方法都要在每个实例上重新创建一遍,方法指的就是我们在对象里面定义的函数。如果方法的数量很多,就会占用很多不必要的内存。

  1. 原型创建对象模式:
function Person(){}
	Person.prototype.name = 'Nike';
	Person.prototype.age = 20;
	Person.prototype.jbo = 'teacher';
	Person.prototype.sayName = function(){
	 alert(this.name);
};
var person1 = new Person();
var person2 = new Person();
person1.name ='Greg';
alert(person1.name); //'Greg' --来自实例
alert(person2.name); //'Nike' --来自原型
  1. 组合使用构造函数模式和原型模式
function Person(name,age,job){
 this.name =name;
 this.age = age;
 this.job = job;
}
Person.prototype = {
 constructor:Person,
 sayName: function(){
 	alert(this.name);
 };
}
var person1 = new Person('Nike',20,'teacher');

构造函数模式用于定义实例属性,而原型模式用于定义方法和共享的属性

11.JS继承的几种实现方式

由于JS并不是真正面向对象的语言,是基于对象的,没有类的概念,所以继承就要用JS对象的原型prototype机制或者用apply和call方法实现。
可以把prototype看作一个模板,新创建的对象都是这个模板的拷贝(新实例化的对象内部有个_Proto_指针,指向原型对象)

  1. 继承的第一种方式:对象冒充

通过this.某某函数()将parent函数引入,然后对其进行传参操作,此时该子对象this已经有parent的值了,也就是说一个传参后的副本,销毁最开始的parent引入,就只剩this自己的继承属性了

function Parent(username){
    this.username = username;
    this.hello = function(){
      console.log('hello ' + this.username);
    }
  }
Parent.prototype.sayMorning = function(){
	console.log('good morning ' + this.username);
}
  function Child(username,password){
    //通过以下3行实现将Parent的属性和方法追加到Child中,从而实现继承
    //第一步:this.method是作为一个临时的属性,并且指向Parent所指向的对象,
    //第二步:执行this.method方法,即执行Parent所指向的对象函数
    //第三步:销毁this.method属性,即此时Child就已经拥有了Parent的所有属性和方法
    this.method = Parent;
    this.method(username);//最关键的一行
    delete this.method;

     this.password = password;
    this.world = function(){
      console.log(this.password);
    }
  }

  var parent = new Parent("zhangsan");
  var child = new Child("lisi","123456");
  parent.hello();
  parent.sayMorning();
  child.hello();
  child.world();
  1. 继承的第二种方式:call()方法方式

因为call函数能够回调全局对象的函数/全局函数将该函数赋值给传进去的this上,所以call返回的this对象就是进行父函数回调处理过后的对象,就能够实现继承。

但是this的原型还是child的原型!!!因为传进去的this本身就是child

function Parent(username){
    this.username = username;
    this.hello = function(){
      console.log(this.username);
    }
  }

Parent.prototype.sayMorning = function(){
		console.log('good morning ' + this.username);
	}

  function Child(username,password){
    Parent.call(this,username);

    this.password = password;
    this.world = function(){
      console.log(this.password);
    }
  }


  var parent = new Parent("zhangsan");
  var child = new Child("lisi","123456");
  parent.hello();
  parent.sayMorning();
  child.hello();
  child.world();
// child.sayMorning();  通过prototype 添加的方法和属性,不能用来继承
  1. 继承的第三种方式:apply()方法方式

原理跟call一样,只是传进去的值第一个是this,第二个必须是有内存分配(不是野指针)的数组;例如new Array()或者 var []

function Parent(username){
    this.username = username;
    this.hello = function(){
      console.log(this.username);
    }
  }

	Parent.prototype.sayMorning = function(){
		console.log('good morning ' + this.username);
	}

  function Child(username,password){
    Parent.apply(this,new Array(username));

    this.password = password;
    this.world = function(){
      console.log(this.password);
    }
  }
var parent = new Parent("zhangsan");
  var child = new Child("lisi","123456");
  parent.hello();
  parent.sayMorning();
  child.hello();
  child.world();
// child.sayMorning(); 通过prototype 添加的方法和属性,不能用来继承
  1. 继承的第四种方式:原型链方式

原型链方式,即子类通过prototype将所有在父类中通过prototype追加的属性和方法都追加到child里面,从而实现继承。

function Person(){

}
Person.prototype.hello = "hello";
Person.prototype.sayHello = function(){
  console.log(this.hello);
}

function Child(){

}
Child.prototype = new Person();//这行的作用是:将Parent中将所有通过prototype追加的属性和方法都追加到Child,从而实现了继承
console.log("判断Child的原型链是不是Person原型的一个实例化对象 " + (Child.prototype.__proto__ === Person.prototype))
//判断Child的原型链是不是Person原型的一个实例化对象 true
Child.prototype.world = "world";
Child.prototype.sayWorld = function(){
  console.log(this.world);
}

var c = new Child();
c.sayHello();
c.sayWorld();//undefined

缺点1:通过prototype 添加的方法和属性,不能用来继承!!!!为什么呢??下面有解释

  • 这里分开分析:
    创建一个Person原型对象实例
    var obj = new Person();
    Child对象的原型 指向 这个Person原型对象的实例
    Child.prototype = obj;
  • 也就是说
    Child对象的原型其实是Person原型的实例化对象
    Child.prototype.__proto__ === Person.prototype;
    在这里插入图片描述

因为子对象的原型是父对象的原型的实例化对象,所以不能继承父对象的方法和属性。

  1. 继承的第五种方式:混合方式, 混合了call或者apply方式、原型链方式
function Parent(hello){
    this.hello = hello;
  }
Parent.prototype.sayHello = function(){
  console.log(this.hello);
}

function Child(hello,world){
  Parent.call(this,hello);//将父类的属性继承过来
  this.world = world;//新增一些属性
}

Child.prototype = new Parent();//将父类的方法继承过来

Child.prototype.sayWorld = function(){//新增一些方法
  console.log(this.world);
}

var c = new Child("zhangsan","lisi");
c.sayHello();
c.sayWorld();

可以继承通过prototype 添加的方法和属性

为什么呢

因为在子对象的初始化时,加了一个父类型的原型属性回调Parent.call(this,hello);//将父类的属性继承过来
这样就强行把父类型的原型属性拉了过来

12.call和apply的用法(详细介绍)

js中call和apply都可以实现继承,唯一的一点参数不同,func.call(func1,var1,var2,var3)对应的apply写法为:func.apply(func1,[var1,var2,var3])

调用一个对象的一个方法,以另一个对象替换当前对象。
call([thisObj[,arg1[, arg2[, [,.argN]]]]])
参数:thisObj 可选项 默认就是this 被称作当前对象的对象
args 可选项 将被传递方法参数序列
call方法可以用来代替另一个对象调用一个方法,将一个函数的对象上下文,从初始的上下文改变为thisObj指定的新对象。也就是说这个第三方函数对象的上下文this指向的是第一方函数作用链外的那个对象的this。

说简单点,这两个函数的作用其实就是更改调用的函数对象的内部指针,即改变对象的this指向的内容,使调用的第三方函数对象的this指向作用域链外的那个对象的this。

 function Person(name,age){   //定义一个类  
	 this.name=name;     //名字  
	 this.age=age;       //年龄  
	 this.sayhello=function(){alert(this.name)}; 
} 
function Print(){            //显示类的属性  
    this.funcName="Print"; 
    this.show=function(){ 
        var msg=[]; 
        for(var key in this){ 
            if(typeof(this[key])!="function"){ 
                msg.push([key,":",this[key]].join("")); 
            } 
        } 
        alert(msg.join(" ")); 
    }; 
} 
function Student(name,age,grade,school){    //学生类  
    Person.apply(this,arguments);//比call优越的地方  
    Print.apply(this,arguments); 
    this.grade=grade;                //年级  
    this.school=school;                 //学校  
} 
var p1=new Person("卜开化",80); 
p1.sayhello(); 
var s1=new Student("白云飞",40,9,"岳麓书院"); 
s1.show(); 
s1.sayhello(); 
alert(s1.funcName);

//alert 
卜开化 
name:白云飞 age:40 funcName:Print grade:9 school:岳麓书院
白云飞
Print

另外,Function.apply()在提升程序性能方面有突出作用:
我们先从Math.max()函数说起,Math.max后面可以接任意个参数,最后返回所有参数中的最大值。

alert(Math.max(5,8));   //8  
    alert(Math.max(5,7,9,3,1,6));   //9  

    //但是在很多情况下,我们需要找出数组中最大的元素。  

    var arr=[5,7,9,1]; 
    //alert(Math.max(arr));    // 这样却是不行的。NaN  

    //要这样写  
    function getMax(arr){ 
        var arrLen=arr.length; 
        for(var i=0,ret=arr[0];i<arrLen;i++){ 
            ret=Math.max(ret,arr[i]); 
        } 
        return ret; 
    } 

    alert(getMax(arr)); //9  

    //换用apply,可以这样写  
    function getMax2(arr){ 
        return Math.max.apply(null,arr); 
    } 

    alert(getMax2(arr)); //9  

    //两段代码达到了同样的目的,但是getMax2却优雅,高效,简洁得多。  

    //再比如数组的push方法。  
    var arr1=[1,3,4]; 
    var arr2=[3,4,5]; 
    //如果我们要把 arr2展开,然后一个一个追加到arr1中去,最后让arr1=[1,3,4,3,4,5]  
    //arr1.push(arr2)显然是不行的。 因为这样做会得到[1,3,4,[3,4,5]]  

    //我们只能用一个循环去一个一个的push(当然也可以用arr1.concat(arr2),但是concat方法并不改变arr1本身)  

    var arrLen=arr2.length; 
    for(var i=0;i<arrLen;i++){ 
        arr1.push(arr2[i]); 
    } 

    //自从有了Apply,事情就变得如此简单  

    Array.prototype.push.apply(arr1,arr2); //现在arr1就是想要的结果
//alert 8 9 9 9

13.原型与原型链

这篇文章
在这里插入图片描述

js 获取原型的方法?

14.什么是闭包,为什么要用它?

闭包就是有权访问另一个函数作用域内变量的函数,创建闭包的最常见的方式就是在一个函数内创建另一个函数,创建的函数可以访问到当前函数的局部变量

闭包的两个常见用途

  1. 在函数外部能够访问到函数内部的变量,可以创建私有变量
  2. 使已经执行结束的函数上下文中的变量对象继续留在内存中,因为闭包保留了这个变量对象的引用,所以这个变量对象不会被回收。
function a(){
    var n = 0;
    function add(){
       n++;
       console.log(n);
    }
    return add;
}
var a1 = a(); //注意,函数名只是一个标识(指向函数的指针),而()才是执行函数;
a1();    //1
a1();    //2  第二次调用n变量还在内存中

15.了解DOM和BOM吗?

16.三种事件模型是什么?

事件是用户和网页的交互

17.事件委托是什么?

本质上是利用了浏览器冒泡的机制,因为事件在冒泡过程中会上传到父节点,并且父节点可以通过事件对象获取到目标节点,因为可以把子节点的监听函数定义在父节点上,有父节点的监听函数统一处理各个子元素的事件
也就是父元素对于子元素的事件代理

不必每个元素都绑定监听事件,这样减少了内存的消耗和内存泄漏。
使用事件代理可以实现事件的动态绑定,比如新增节点就不需要为他再添加一个监听事件,发生的事件会交给父元素的监听函数来处理

18.事件传播是什么?

当事件发生再DOM元素上时,该事件并不完全发生再那个元素上
事件传播有三个阶段,

19.事件捕获是什么?

当事件发生再DOM元素上时,该事件并不完全发生再那个与那个元素上。在捕获阶段,事件从window开始,一直到触发事件的元素,window–document–html–body–目标元素

例如有下面的HTML结构
有三层继承关系

<div class="grandparent">
  <div class="parent">
    <div class="child">1</div>
  </div>
</div>

我们来写一个模拟事件捕获的js代码

fnunction addEvent(element,event,callback,isCapture = false){
	//判断输入是否错误
	if(!el || !event ||!callback || typeof callback !== 'function') return;
	if(typeof element === 'string'){
		element = document.querySelector(element);
	};
	element.addEventListener(event ,callback ,isCapture);
}

addEvent(document,'DOMContentLoaded',()=>{
	const child = document.querySelector('.child');
	const parent = document.querySelector('.parent');
	const grandparent = document.querySelector('.grandparent');
addEvent(child,'click',function(e){
		console.log('child');
	}
);
addEvent(parent,'click',function(e){
		console.log('parent');
	}
);
addEvent(grandparent,'click',function(e){
		console.log('grandparent');
	}
);
addEvent(document,'click',function(e){
		console.log('document');
	}
);
 addEvent('html', 'click', function (e) {
    console.log('html');
  })

  addEvent(window, 'click', function (e) {
    console.log('window');
  })
});

addEventlistener方法具有第三个可选参数useCapture,默认值为false,事件将在冒泡阶段中发生,如果为true 则事件将在捕获阶段中发生,如果单击child元素,它将分别在控制台上打印window document html grandparent parent
也就是模拟出了一个事件捕获

20.事件冒泡是什么?

事件冒泡刚好与事件捕获相反,当前元素–body–html–document–window

21.DOM操作 添加移除移动复制创建和查找结点

  1. 创建新节点
createDocumentFragment() //创建一个DOM片段
createElement() //创建一个具体的元素
createTextNode() //创建一个文本节点
  1. 添加删除替换插入
appendChild(node)
removeChild(node)
replaceChild(new,old)
insertBefore(new,old)
  1. 查找
getElementById();
getElementByName();
getElementByTagName();
getElementByClassName();
querySelector();
querySelectorAll();

4.属性操作

getAttribute(key);
getAttribute(key,value);
hasAttribute(key);
document.getElementsByTagName("BUTTON")[0].hasAttribute("onclick");
removeAttribute(key)

22.js数组和字符串原生方法

数组方法

对象方法

23.常用正则表达式

//(1)匹配 16 进制颜色值
var color = /#([0-9a-fA-F]{6}|[0-9a-fA-F]{3})/g;

//(2)匹配日期,如 yyyy-mm-dd 格式
var date = /^[0-9]{4}-(0[1-9]|1[0-2])-(0[1-9]|[12][0-9]|3[01])$/;

//(3)匹配 qq 号
var qq = /^[1-9][0-9]{4,10}$/g;

//(4)手机号码正则
var phone = /^1[34578]\d{9}$/g;

//(5)用户名正则
var username = /^[a-zA-Z\$][a-zA-Z0-9_\$]{4,16}$/;

//(6)Email正则
var email = /^([A-Za-z0-9_\-\.])+\@([A-Za-z0-9_\-\.])+\.([A-Za-z]{2,4})$/;

//(7)身份证号(18位)正则
var cP = /^[1-9]\d{5}(18|19|([23]\d))\d{2}((0[1-9])|(10|11|12))(([0-2][1-9])|10|20|30|31)\d{3}[0-9Xx]$/;

//(8)URL正则
var urlP= /^((https?|ftp|file):\/\/)?([\da-z\.-]+)\.([a-z\.]{2,6})([\/\w \.-]*)*\/?$/;

// (9)ipv4地址正则
var ipP = /^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/;

// (10)//车牌号正则
var cPattern = /^[京津沪渝冀豫云辽黑湘皖鲁新苏浙赣鄂桂甘晋蒙陕吉闽贵粤青藏川宁琼使领A-Z]{1}[A-Z]{1}[A-Z0-9]{4}[A-Z0-9挂学警港澳]{1}$/;

// (11)强密码(必须包含大小写字母和数字的组合,不能使用特殊字符,长度在8-10之间):var pwd = /^(?=.\d)(?=.[a-z])(?=.[A-Z]).{8,10}$/

24.Ajax 是什么? 如何创建一个 Ajax?

一种异步通信的方法,通过直接由 js 脚本向服务器发起 http 通信,然后根据服务器返回的数据,更新网页的相应部分,而不用刷新整个页面的一种方法。

//1:创建Ajax对象
var xhr = window.XMLHttpRequest?new XMLHttpRequest():new ActiveXObject('Microsoft.XMLHTTP');// 兼容IE6及以下版本
//2:配置 Ajax请求地址
xhr.open('get','index.xml',true);
//3:发送请求
xhr.send(null); // 严谨写法
//4:监听请求,接受响应
xhr.onreadysatechange=function(){
     if(xhr.readySate==4&&xhr.status==200 || xhr.status==304 )
          console.log(xhr.responsetXML)
}
$.ajax({
  type:'post',
  url:'',
  async:ture,//async 异步  sync  同步
  data:data,//针对post请求
  dataType:'jsonp',
  success:function (msg) {

  },
  error:function (error) {

  }
})
// promise 封装实现:

function getJSON(url) {
  // 创建一个 promise 对象
  let promise = new Promise(function(resolve, reject) {
    let xhr = new XMLHttpRequest();

    // 新建一个 http 请求
    xhr.open("GET", url, true);

    // 设置状态的监听函数
    xhr.onreadystatechange = function() {
      if (this.readyState !== 4) return;

      // 当请求成功或失败时,改变 promise 的状态
      if (this.status === 200) {
        resolve(this.response);
      } else {
        reject(new Error(this.statusText));
      }
    };

    // 设置错误监听函数
    xhr.onerror = function() {
      reject(new Error(this.statusText));
    };

    // 设置响应的数据类型
    xhr.responseType = "json";

    // 设置请求头信息
    xhr.setRequestHeader("Accept", "application/json");

    // 发送 http 请求
    xhr.send(null);
  });

  return promise;
}

25. js 延迟加载的方式有哪些?

js 的加载、解析和执行会阻塞页面的渲染过程,因此我们希望 js 脚本能够尽可能的延迟加载,提高页面的渲染速度。

26.谈谈你对模块化开发的理解?

27.js 的几种模块规范?模块加载方案?

28.AMD 和 CMD 规范的区别?

// CMD
define(function(require, exports, module) {
  var a = require("./a");
  a.doSomething();
  // 此处略去 100 行
  var b = require("./b"); // 依赖可以就近书写
  b.doSomething();
  // ...
});

// AMD 默认推荐
define(["./a", "./b"], function(a, b) {
  // 依赖必须一开始就写好
  a.doSomething();
  // 此处略去 100 行
  b.doSomething();
  // ...
})

29.ES6 模块与 CommonJS 模块、AMD、CMD 的差异。

CommonJS 模块输出的是一个值的拷贝,ES6 模块输出的是值的引用。CommonJS 模块输出的是值的,也就是说,一旦输出一个值,模块内部的变化就影响不到这个值。ES6 模块的运行机制与 CommonJS 不一样。JS 引擎对脚本静态分析的时候,遇到模块加载命令 import,就会生成一个只读引用。等到脚本真正执行时,再根据这个只读引用,到被加载的那个模块里面去取值
CommonJS 模块是运行时加载,ES6 模块是编译时输出接口。CommonJS 模块就是对象,即在输入时是先加载整个模块,生成一个对象,然后再从这个对象上面读取方法,这种加载称为“运行时加载”。而 ES6 模块不是对象,它的对外接口只是一种静态定义,在代码静态解析阶段就会生成。

30. requireJS的核心原理是什么?

require.js 的核心原理是通过动态创建 script 脚本来异步引入模块,然后对每个脚本的 load 事件进行监听,如果每个脚本都加载完成了,再调用回调函数。

标签:function,必背,console,log,对象,JavaScript,var,Interview,prototype
来源: https://blog.csdn.net/weixin_43698328/article/details/110632904