一、JavaScript部分面试题
-
1.JavaScript 有哪些数据类型,它们的区别?
- JavaScript 共有八种数据类型,分别是Undefined、Null、Boolean、Number、String、Object、Symbol、BigInt。其中 Symbol 和 BigInt 是 ES6 中新增的数据类型:●Symbol 代表创建后独一无二且不可变的数据类型,它主要是为了解决可能出现的全局变量冲突的问题。●BigInt 是一种数字类型的数据,它可以表示任意精度格式的整数,使用 BigInt 可以安全地存储和操作大整数,即使这个数已经超出了Number 能够表示的安全整数范围。 这些数据可以分为原始数据类型和引用数据类型:●栈:原始数据类型(Undefined、Null、Boolean、Number、String)●堆:引用数据类型(对象、数组和函数)两种类型的区别在于存储位置的不同:●原始数据类型直接存储在栈(stack)中的简单数据段,占据空间小、大小固定,属于被频繁使用数据,所以放入栈中存储;●引用数据类型存储在堆(heap)中的对象,占据空间大、大小不固定。如果存储在栈中,将会影响程序运行的性能;引用数据类型在栈中存储了指针,该指针指向堆中该实体的起始地址。当解释器寻找引用值时,会首先检索其在栈中的地址,取得地址后从堆中获得实体。堆和栈的概念存在于数据结构和操作系统内存中,在数据结构中:●在数据结构中,栈中数据的存取方式为先进后出。●堆是一个优先队列,是按优先级来进行排序的,优先级可以按照大小来规定。 在操作系统中,内存被分为栈区和堆区: 2 ●栈区内存由编译器自动分配释放,存放函数的参数值,局部变量的值等。其操作方式类似于数据结构中的栈。●堆区内存一般由开发着分配释放,若开发者不释放,程序结束时可能由垃圾回收机制回收。
-
数据类型检测的方式有哪些
-
1).typeof
console.log(typeof(num)); //String console.log(num); //12 console.log(12); //12 console.log(typeof(true)); //boolean console.log(typeof("true")); //string var b; console.log(typeof(b)); //undefined console.log(typeof(11)); //Number console.log(typeof(null)); //object
其中数组、对象、null 都会被判断为 object,其他判断都正确。
-
2) instanceof
- instanceof 可以正确判断对象的类型,其内部运行机制是判断在其原型链中能否找到该类型的原型。
const instanceof=(item,val)=> { let cdn=item; while(cdn) { if(cdn===val.protype){return true} cdn=cdn.__proto__; } return false; } /*实际应用:调用函数判断*/ instanceof([],Array) //true
3) constructor
- 引用javascript 对象中的 constructor属性的作用?
-
var a,b; (function(){ function A (arg1,arg2) { this.a = 1; this.b=2; } A.prototype.log = function () { console.log(this.a); } a = new A(); b = new A(); })() a.log(); // 1 b.log(); // 1
以上代码我们可以得到两个对象,a,b,他们同为类A的实例。因为A在闭包里,所以现在我们是不能直接访问A的,那如果我想给类A增加新方法怎么办?
-
// a.constructor.prototype 在chrome,firefox中可以通过 a.__proto__ 直接访问 a.constructor.prototype.log2 = function () { console.log(this.b) } a.log2(); // 2 b.log2(); // 2
4)Object.prototype.toString.call()
- Object.prototype.toString.call() 使用Object 对象的原型方法toString 来判断数据类型:
-
5)null和undefined区别
- 首先 Undefined 和 Null 都是基本数据类型,这两个基本数据类型分别都只有一个值,就是 undefined 和null。undefined 代表的含义是未定义,null 代表的含义是空对象。一般变量声明了但还没有定义的时候会返回undefined,null 主要用于赋值给一些可能会返回对象的变量,作为初始化。undefined 在 JavaScript 中不是一个保留字,这意味着可以使用undefined 来作为一个变量名,但是这样的做法是非常危险的,它会影响对 undefined 值的判断。我们可以通过一些方法获得安全的undefined 值,比如说 void 0。 当对这两种类型使用 typeof 进行判断时,Null 类型化会返回“object”,这是一个历史遗留的问题。当使用双等号对两种类型的值进行比较时会返回 true,使用三个等号时会返回false。
- 4. intanceof 操作符的实现原理及实现
- instanceof 运算符用于判断构造函数的prototype 属性是否出现在对象的原型链中的任何位置。
- Object.is() 与比较操作符 “===”、“==”的区别?
- 使用双等号(==)进行相等判断时,如果两边的类型不一致,则会进行强制类型转化后再进行比较。 使用三等号(===)进行相等判断时,如果两边的类型不一致时,不会做强制类型准换,直接返回 false。 使用 Object.is 来进行相等判断时,一般情况下和三等号的判断相同,它处理了一些特殊的情况,比如 -0 和+0 不再相等,两个NaN是相等的。
-
3.如何判断一个对象是空对象
- 使用JSON自带的.stringfy方法来判断
-
if(Json.stringfy(obj) =='{}'){ conlole.log('空对象') } //使用ES6新增的方法Object.keys()来判断 if(Object.keys(obj).length < 0){ conlole.log('空对象') }
4.const 对象的属性可以修改吗
-
const 保证的并不是变量的值不能改动,而是变量指向的那个内存地址不能改动。对于基本类型的数据(数值、字符串、布尔值),其值就保存在变量指向的那个内存地址,因此等同于常量。但对于引用类型的数据(主要是对象和数组)来说,变量指向数据的内存地址,保存的只是一个指针,const 只能保证这个指针是固定不变的,至于它指向的数据结构是不是可变的,就完全不能控制了。
-
-
5.如果 new 一个箭头函数的会怎么样
-
箭头函数是ES6中的提出来的,它没有prototype,也没有自己的this指向,更不可以使用 arguments 参数,所以不能New 一个箭头函数。new 操作符的实现步骤如下: 1.创建一个对象 2.将构造函数的作用域赋给新对象(也就是将对象的__proto__属性指向构造函数的 prototype 属性) 8 3.指向构造函数中的代码,构造函数中的this 指向该对象(也就是为这个对象添加属性和方法) 4.返回新的对象 所以,上面的第二、三步,箭头函数都是没有办法执行的。
-
6.箭头函数的 this 指向哪⾥?
-
箭头函数不同于传统 JavaScript 中的函数,箭头函数并没有属于⾃⼰的 this,它所谓的 this 是捕获其所在上下⽂的this 值,作为⾃⼰的 this 值,并且由于没有属于⾃⼰的this,所以是不会被new调⽤的,这个所谓的 this 也不会被改变。
-
可以⽤Babel 理解⼀下箭头函数:
const obj={ getArrow(){ return () =>{ console.log(this == obj); }; } }
转化后:
-
var obj={ getArrow:function getArrow(){ var _this=this; return function(){ console(_this === obj) } } }
7.Proxy 可以实现什么功能?
-
在 Vue3.0 中通过 Proxy 来替换原本的Object.defineProperty来实现数据响应式。 Proxy 是 ES6 中新增的功能,它可以用来自定义对象中的操作。
-
let a = new Proxy(target,handler)
代表需要添加代理的对象,handler 用来自定义对象中的操作,比如可以用来自定义 set或者get函数
-
常用的正则表达式有哪些
-
//(1)匹配16今之色值 var reget=/#([0-9a-fA-f]{6}|[0-9a-fA]{3})/g //(2)匹配日期,如 yyyu-mm-dd var reget = /^[0-9]{4}-(0[1-9]|[0-2])-(0[1-9]|[12][0-9]|3[01])$/ //(3)匹配qq号 var reget =/^[1-9][0-9]{4,10}$/g //(4)手机号码正则 var regex =/^1[34578]\d{9}$/g //(5)用户名正则 var reget=/^[a-2A-Z\$][a-2A-Z0-9_\$]{4,16}$/
8.什么是 DOM 和 BOM?
-
DOM 指的是文档对象模型,它指的是把文档当做一个对象,这个对象主要定义了处理网页内容的方法和接口。BOM 指的是浏览器对象模型,它指的是把浏览器当做一个对象来对待,这个对象主要定义了与浏览器进行交互的法和接口。BOM 的核心是window,而 window 对象具有双重角色,它既是通过js 访问浏览器窗口的一个接口,又是一个 Global(全局)对象。这意味着在网页中定义的任何对象,变量和函数,都作为全局对象的一个属性或者方法存在。window 对象含有 location 对象、navigator 对象、screen 15 对象等子对象,并且 DOM 的最根本的对象document 对象也是BOM的 window 对象的子对象。
-
9.对 AJAX 的理解,实现一个 AJAX 请求
-
AJAX 是 Asynchronous JavaScript and XML 的缩写,指的是通过JavaScript 的 异步通信,从服务器获取XML 文档从中提取数据,再更新当前网页的对应部分,而不用刷新整个网页。创建 AJAX 请求的步骤: 创建一个 XMLHttpRequest 对象。 在这个对象上使用 open 方法创建一个HTTP 请求,open 方法所需要的参数是请求的方法、请求的地址、是否异步和用户的认证信息。在发起请求前,可以为这个对象添加一些信息和监听函数。比如说可以通过 setRequestHeader 方法来为请求添加头信息。还可以为这个对象添加一个状态监听函数。一个 XMLHttpRequest 对象一共有5个状态,当它的状态变化时会触发 onreadystatechange 事件,可以 16 通过设置监听函数,来处理请求成功后的结果。当对象的readyState变为 4 的时候,代表服务器返回的数据接收完成,这个时候可以通过判断请求的状态,如果状态是 2xx 或者304 的话则代表返回正常。这个时候就可以通过 response 中的数据来对页面进行更新了。当对象的属性和监听函数设置完成后,最后调用sent 方法来向服务器发起请求,可以传入参数作为发送的数据体。
-
10.ES6 模块与 CommonJS 模块有什么异同?
-
ES6 Module 和 CommonJS 模块的区别: CommonJS 是对模块的浅拷⻉,ES6 Module 是对模块的引⽤,即ES6Module 只存只读,不能改变其值,也就是指针指向不能变,类似const;import 的接⼝是 read-only(只读状态),不能修改其变量值。即不能修改其变量的指针指向,但可以改变变量内部指针指向,可以对commonJS 对重新赋值(改变指针指向),但是对ES6 Module 赋值会编译报错。 ES6 Module 和 CommonJS 模块的共同点:CommonJS 和 ES6 Module 都可以对引⼊的对象进⾏赋值,即对对象内部属性的值进⾏改变。
-
11.for...in 和 for...of 的区别
-
for…of 是 ES6 新增的遍历方式,允许遍历一个含有iterator接口的数据结构(数组、对象等)并且返回各项的值,和ES3 中的for…in 的区别如下 for…of 遍历获取的是对象的键值,for…in 获取的是对象的键名; 18 for… in 会遍历对象的整个原型链,性能非常差不推荐使用,而for … of 只遍历当前对象不会遍历原型链;对于数组的遍历,for…in 会返回数组中所有可枚举的属性(包括原型链上可枚举的属性),for…of 只返回数组的下标对应的属性值;总结:for...in 循环主要是为了遍历对象而生,不适用于遍历数组;for...of 循环可以用来遍历数组、类数组对象,字符串、Set、Map以及 Generator 对象。
-
12.对作用域、作用域链的理解
-
1)全局作用域和函数作用域 (1)全局作用域 最外层函数和最外层函数外面定义的变量拥有全局作用域所有未定义直接赋值的变量自动声明为全局作用域所有 window 对象的属性拥有全局作用域全局作用域有很大的弊端,过多的全局作用域变量会污染全局命名空间,容易引起命名冲突。 (2)函数作用域 函数作用域声明在函数内部的变零,一般只有固定的代码片段可以访问到 作用域是分层的,内层作用域可以访问外层作用域,反之不行2)块级作用域 23 使用 ES6 中新增的 let 和 const 指令可以声明块级作用域,块级作用域可以在函数中创建也可以在一个代码块中的创建(由{ }包裹的代码片段) let 和 const 声明的变量不会有变量提升,也不可以重复声明在循环中比较适合绑定块级作用域,这样就可以把声明的计数器变量限制在循环内部。 作用域链: 在当前作用域中查找所需变量,但是该作用域没有这个变量,那这个变量就是自由变量。如果在自己作用域找不到该变量就去父级作用域查找,依次向上级作用域查找,直到访问到window 对象就被终止,这一层层的关系就是作用域链。 作用域链的作用是保证对执行环境有权访问的所有变量和函数的有序访问,通过作用域链,可以访问到外层环境的变量和函数。作用域链的本质上是一个指向变量对象的指针列表。变量对象是一个包含了执行环境中所有变量和函数的对象。作用域链的前端始终都是当前执行上下文的变量对象。全局执行上下文的变量对象(也就是全局对象)始终是作用域链的最后一个对象。当查找一个变量时,如果当前执行环境中没有找到,可以沿着作用域链向后查找
-
13.call() 和 apply() 的区别?
-
它们的作用一模一样,区别仅在于传入参数的形式的不同。apply 接受两个参数,第一个参数指定了函数体内this 对象的指向,第二个参数为一个带下标的集合,这个集合可以为数组,也可以为类数组,apply 方法把这个集合中的元素作为参数传递给被调用的函数。call 传入的参数数量不固定,跟 apply 相同的是,第一个参数也是代表函数体内的 this 指向,从第二个参数开始往后,每个参数被依次传入函数。
-
14.异步编程的实现方式?
-
JavaScript 中的异步机制可以分为以下几种:回调函数 的方式,使用回调函数的方式有一个缺点是,多个回调函数嵌套的时候会造成回调函数地狱,上下两层的回调函数间的代码耦合度太高,不利于代码的可维护。 Promise 的方式,使用 Promise 的方式可以将嵌套的回调函数作为链式调用。但是使用这种方法,有时会造成多个then 的链式调用,可能会造成代码的语义不够明确。 generator 的方式,它可以在函数的执行过程中,将函数的执行权转移出去,在函数外部还可以将执行权转移回来。当遇到异步函数执行的时候,将函数执行权转移出去,当异步函数执行完毕时再将执行权给转移回来。因此在 generator 内部对于异步操作的方式,可以以同步的顺序来书写。使用这种方式需要考虑的问题是何时将函数的控制权转移回来,因此需要有一个自动执行generator 的机制,比如说 co 模块等方式来实现 generator 的自动执行。async 函数 的方式,async 函数是 generator 和promise 实现的一个自动执行的语法糖,它内部自带执行器,当函数内部执行到一个await 语句的时候,如果语句返回一个promise 对象,那么函数将会等待 promise 对象的状态变为 resolve 后再继续向下执行。因此可以将异步逻辑,转化为同步的顺序来书写,并且这个函数可以自动执行。
-
15.对 Promise 的理解
-
Promise 是异步编程的一种解决方案,它是一个对象,可以获取异步操作的消息,他的出现大大改善了异步编程的困境,避免了地狱回调,它比传统的解决方案回调函数和事件更合理和更强大。所谓 Promise,简单说就是一个容器,里面保存着某个未来才会结束的事件(通常是一个异步操作)的结果。从语法上说,Promise是一个对象,从它可以获取异步操作的消息。Promise 提供统一的API,各种异步操作都可以用同样的方法进行处理。(1)Promise 的实例有三个状态: Pending(进行中) Resolved(已完成) Rejected(已拒绝) 当把一件事情交给 promise 时,它的状态就是Pending,任务完成了状态就变成了 Resolved、没有完成失败了就变成了Rejected。(2)Promise 的实例有两个过程: pending -> fulfilled : Resolved(已完成)pending -> rejected:Rejected(已拒绝)注意:一旦从进行状态变成为其他状态就永远不能更改状态了。Promise 的特点: 对象的状态不受外界影响。promise 对象代表一个异步操作,有三种状态,pending(进行中)、fulfilled(已成功)、rejected(已失败)。只有异步操作的结果,可以决定当前是哪一种状态,任何其他操作都无法改变这个状态,这也是 promise 这个名字的由来——“承诺”; 27 一旦状态改变就不会再变,任何时候都可以得到这个结果。promise对象的状态改变,只有两种可能:从 pending 变为fulfilled,从pending 变为 rejected。这时就称为 resolved(已定型)。如果改变已经发生了,你再对 promise 对象添加回调函数,也会立即得到这个结果。这与事件(event)完全不同,事件的特点是:如果你错过了它,再去监听是得不到结果的。 Promise 的缺点: 无法取消 Promise,一旦新建它就会立即执行,无法中途取消。如果不设置回调函数,Promise 内部抛出的错误,不会反应到外部。当处于 pending 状态时,无法得知目前进展到哪一个阶段(刚刚开始还是即将完成)。 总结: Promise 对象是异步编程的一种解决方案,最早由社区提出。Promise是一个构造函数,接收一个函数作为参数,返回一个Promise实例。一个 Promise 实例有三种状态,分别是pending、resolved和rejected,分别代表了进行中、已成功和已失败。实例的状态只能由pending 转变 resolved 或者 rejected 状态,并且状态一经改变,就凝固了,无法再被改变了。 状态的改变是通过 resolve() 和 reject() 函数来实现的,可以在异步操作结束后调用这两个函数改变 Promise 实例的状态,它的原型上定义了一个 then 方法,使用这个 then 方法可以为两个状态的改变注册回调函数。这个回调函数属于微任务,会在本轮事件循环的末尾执行。 注意:在构造 Promise 的时候,构造函数内部的代码是立即执行的
-
-
-