【面经】2021最新的javascript的面试

文章目录

      • 1:Js基本数据类型有哪些
      • 2:Ajax如何使用,常见HTTP状态码
      • 3:js中的变量提升
      • 4:判断一个数据是NaN
      • 5:null和undefined区别
      • 6:object.is()和`===`、`==` 的区别?
      • 7:闭包是什么,有什么特性,
      • 8:事件委托是什么?如何确定事件源
      • 9:本地存储与cookie的区别
      • 10:let,const,var的区别
      • 11:ES6的新特性
      • 12:数组的方法
      • 13:new一个箭头函数会怎样
      • 14:new操作符的实现步骤
      • 15:构造函数和普通函数的区别
      • 16:箭头函数
      • 17:逆运算符的使用场景
      • 18:原型,原型链,继承
      • 19:Promise的理解
      • 20:**Promise**在哪里使用过
      • 21:js中call()和apply()的区别
      • 22:跨域/同源策略
      • 23:this的指向
      • 24:什么是jsonp工作原理,他为什么不是ajax
      • 25:jsonp和json的区别
      • 26:深浅拷贝是什么如何实现?
      • 27:请输出三种减少页面加载时间的方式
      • 28:JavaScript 类数组对象的定义?
      • 29:为什么函数的 arguments 参数是类数组
      • 29:为什么函数的 arguments 参数是类数组

1:Js基本数据类型有哪些

String,number,boolean,undefined,null

“”,0, null,undefined, NaN, false 会自动转换为false

其中数据的检测类型可以划分为

  • typeof

    console.log(typeof function(){
           });    // function
    console.log(typeof []);              // object    
    
  • instanceof:检测机制是通过判断其原型对象上是否有该类的原型

    【判断对象】

    console.log(2 instanceof Number);      // false
    console.log([] instanceof Array);      // true
    console.log(function(){
           } instanceof Function);// true
    
  • 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
    

2:Ajax如何使用,常见HTTP状态码

Ajax是一种异步交互技术,可以在不重新加载整个页面的情况下,对网页进行局部的加载更新

Ajax的优点是:

  • 对用户的操作作出及时的反应,

  • 在不中断用户操作的情况下和web服务器进行交互

  • 局部更新相对于整个页面的更新可以降低网络的流量

Ajax的Get请求是:

Let xhr=new xmlhttprequest()    0
//open 可以设置请求的方式(请求方式,地址,是否异步)
	Xhr.open("get”,”ajax.php?username="+,true)    1
	Xhr.send()
	Xhr.onreadystagechange=function(){
         3
		If(xhr.status==200&&xhr.readystate==4){
     
			Console.log(xhr.responseText)
	} }

Ajax的Post请求是:

Let xhr=new xmlhttprequest()    0
//open 可以设置请求的方式(请求方式,地址,是否异步)
	Xhr.open("post”,”ajax.php")    1
	Xhr.send("username"+)
//请求头
	Xhr.setRequestHeader(“ Content-type”,”application”)
	Xhr.onreadystagechange=function(){
         3
		If(xhr.status==200&&xhr.readystate==4){
     
			Console.log(xhr.responseText)
	} }

Ajax的常用转态码:

  • 200:处理请求成功
  • 204:请求成功,但是没有返回值
  • 301:请求的页面已经被永久的移除了
  • 302:请求的页面,被临时移除了
  • 400:不理解请求的语法
  • 403:服务器拒绝请求
  • 404:服务器找不到请求的url
  • 500:服务器有错误,无法完成请求
  • 503:服务器无法使用

3:js中的变量提升

变量提升是:无论是在函数的何种位置声明变量,该变量都不会报错函数的声明会被提前到函数的顶部,在全局变量中也是一样的

为什么会出现变量提升:

主要得益于js脚本语言在浏览器中的运行机制,js的运行会分为两部分

(1):代码的解析过程:js会在代码进行解析的时候,现将即将使用到的所有的变量进行提前赋值,赋值为undefined,同时也会将即将执行的函数进行提前声明,这些都会在全局上下文中执行,在函数提前声明之前,也会创建一个函数的上下文,函数的上下文会包括(this,参数,argument)

(2):代码的执行过程:按照执行顺序进行依次执行

4:判断一个数据是NaN

  • NaN!= NaN结果返回true表明他是一个NaN
  • 采用es6中的Object.is(a, NaN) 结果返回true表明他是一个NaN
  • 通过isNaN( ), 结果返回true表明他是一个NaN

5:null和undefined区别

Undefined:常用来表示一个定义了但是没有赋值的变量,Undefined不是一个保留关键字

Null:常用来表示一个还没有存在的对象

判断:

两者在不严格等于的情况下是相等的

但是在严格等于的情况下是不相等的

采用typeof检测的时候,undefined返回undefined,null返回的是object

转换为数字的时候,undefined会返回NaN,null会返回0

Undefined的值出现有四种情况:

  1. 数据定义了但是没有赋值

  2. 数组中空出来的值

  3. 对象没有相应的方法和属性

  4. 函数没有返回值的时候

6:object.is()和===== 的区别?

双等号进行相等判断时,如果两边的类型不一致,则会进行强制类型转化后再进行比较。

三等号进行相等判断时,如果两边的类型不一致时,不会做强制类型准换,直接返回 false

使用 Object.is 来进行相等判断时,一般情况下和三等号的判断相同,它处理了一些特殊的情况,比如 -0 和 +0 不再相等,两个 NaN 认定为是相等的。

7:闭包是什么,有什么特性,

闭包就是能够读取其他函数内部变量的函数。闭包函数的使用必须使用var关键字声明变量

闭包的缺点:容易造成内存泄漏

闭包的优点:可以内部变量访问外部变量,可以永久的保存某些变量

闭包的造成是:浏览器中自带的垃圾回收机制

垃圾回收机制:在 Javascript 中,如果⼀个对象不再被引⽤,那么这个对象就会被垃圾回收机制回收。如果两个对象互相引⽤,⽽不再 被第 3 者所引⽤,那么这两个互相引⽤的对象也会被回收

垃圾回收机制的方法:1。标记清除,2。引用计数

8:事件委托是什么?如何确定事件源

事件委托就是利用事件冒泡,只制定一个事件处理程序,就可以管理某一类型的所有事件。

事件委托的好处:

将某一个事件加在父元素身上,提高程序的执行效率

要是动态创建的元素,会给新创建好的元素提前绑定触发事件

事件委托的方法:

父元素.事件=function(evt){
     
 //获取事件的真正操作源
Var  e = evt || event;
//真正的操作元素
var target = e.srcElement || e.target;
}
//确定事件源采用target.tagName

9:本地存储与cookie的区别

特性 Cookie localStorage sessionStorage
数据的生命期 一般由服务器生成,可设置失效时间 除非被清除,否则永久保存 仅在当前会话下有效
存放数据大小 4K左右 一般为5MB 一般为5MB
与服务器端通信 跟随http一起进行发送的,所以会浪费一部分带宽 仅在客户端中保存,不参与和服务器的通信 仅在客户端中保存,不参与和服务器的通信
易用性 需要程序员自己封装,源生的Cookie接口不友好 源生接口可以接受,亦可再次封装来对Object和Array有更好的支持 源生接口可以接受,亦可再次封装来对Object和Array有更好的支持

localstroage的相关API

a : localstroage.getitem(key)

b : localstroage.setitem(key,value)

c : localstroage.removeitem(key)删除key值对应的

d : localstroage.clear():删除所有的键值对

10:let,const,var的区别

  • let的基本用法:

    1:块级作用域(let,const)

    2:暂时性死区

     Let a=123;
    {
           
     	Console.log(a)
    	a=456
    }
    Console.log(a)
    

    3:不存在变量提升

    4:不允许重复声明

    5:let和const声明的变量不会成为全局对象的属性

  • const的值可以变吗

    const保证的并不是变量的值不得改动,而是变量指向的那个内存地址不能改动

    基本数据类型:值就保存在变量指向的那个内存地址,因此等同于常量

    引用数据类型:变量指向数据的内存地址,保存的只是一个指针,const只能保证这个指针是固定不变的,至于它指向的数据结构是不是可变的,就完全不能控制了

  • var声明的变量

    var声明的变量会挂载在window上,而let和const声明的变量不会:

11:ES6的新特性

  • let,const

  • 模板字符串``,使用内容+$(变量)

  • 箭头函数

  • 对象解构

    解构对象:let {name,age,sex}=[name:”li”,age:5,sex:”女”]

    解构数组:let {x,y,a }=[1,3,5]

  • 逆运算符[…obj]

  • for in(不能遍历对象)和for of

  • ES6中的类

12:数组的方法

  • push( I ),从后面添加元素,返回值为添加完后的数组的长度

  • arr.pop( ),从后面删除元素,只能是一个,返回值是删除的元素

  • arr.shift ( ),从前面删除元素,只能删除一个 返回值是删除的元素

  • arr.unshift( I ),从前面添加元素, 返回值是添加完后的数组的长度**

  • arr.splice(索引,位移,添加的元素),删除或者添加元素,删除从i(索引值)开始之后的那个元素共删除(n) 位。返回值是删除元素组成的数组

  • arr.slice(start,end), 左闭右开,切去索引值start到索引值end的数组,不包含end索引的值,返回值是切出来的数组

  • arr.concat( ) 连接两个数组 返回值为连接后的新数组

  • arr.join( ) 将数组转化为字符串

  • str.split( ) ,将字符串转化为数组

  • arr.sort( ) ,将数组进行排序,返回值是排好的数组,默认是按照最左边的数字进行排序,不是按照数字大小排序的

  • arr.reverse() ,将数组反转,返回值是反转后的数组

  • arr.indexof(元素查找数组中某一个元素的下标, 不存在返回-1.存在返回下标

数组的新增API

  • arr.forEach((v,i)=>{}) ,遍历数组,无return 即使有return,也不会返回任何值,并且会影响原来的数组

  • arr.map((v,i)=>{return }),映射数组(遍历数组),有return 返回一个新数组

  • arr.filter((v,i)=>{return}), 过滤数组,返回一个满足要求的数组

13:new一个箭头函数会怎样

箭头函数是ES6中的提出来的,它没有prototype,也没有自己的this指向,更不可以使用arguments参数,所以不能New一个箭头函数。

14:new操作符的实现步骤

  • 创建一个空的对象
  • 将构造函数的作用域赋值给新new的对象【即就是将对象的-proto-属性指向构造函数的prototypr属性】
  • 构造函数中的this指向该对象(也就是通过this为新对象添加属性何方法)
  • 返回新的对象

15:构造函数和普通函数的区别

命名规则上:构造函数一般大写,普通函数一般采用驼峰命名法

调用的时候:构造:new fun();普通:fun()

This的指向区别:构造:new出来的 ;普通:谁调用指向谁

16:箭头函数

  • 箭头函数书写更加简洁高级,多变

    //无参
    ()=>{
           console.log("haha")}
    //一个参数
    a=>{
           console.log("haha")}
    //多个参数
    a,b,c=>{
           console.log("haha")}
    
    //返回值只有一句话且没有返回值
    a,b,c=> void console.log("haha")
    
    //有返回值且只有一句话
    a,b,c=> return "haha"
    
  • 箭头函数的this问题

    箭头函数不会创建自己的this, 所以它没有自己的this

    它只会在自己作用域的上一层继承this。

    所以箭头函数中this的指向在它定义时已经确定了,之后不会改变。【箭头函数继承来的this指向永远不会改变】

    var id="123"
    var obj={
           
        id:"987"
        a:function (){
           
            console.log(this.id)
        }	
    	b:()=>{
           
           console.log(this.id) 
        }
    }
    obj.a()//987
    //方法b是使用箭头函数定义的,这个函数中的this就永远指向它定义时所处的执行环境,(即就是祖父)
    obj.b()//123
    

17:逆运算符的使用场景

  • 对象:用于取出参数对象中的所有可遍历属性

    let obj={
           a:1,b:"haha"}
    let obj2={
           ...obj}
    
    //注意:要是在逆运算符后面添加自定义属性,要是添加的属性和你元算符的属性同名,就会被覆盖
    let obj3={
           ...obj,{
           a:2,b:"gaga"}}//a:2,b:"gaga"
    
  • 数组

    const arr1 = [1, 2];
    const arr2 = [...arr1];
    

18:原型,原型链,继承

**原型:**绝大部分的函数都有⼀个 prototype 属性,这个属性是原型对象⽤来创建新对象实例,而所有被创建的对象都会共享原型对象,因此这些对象便可以访问原型对象的属性。

hasOwnProperty() ⽅法存在于Obejct原型对象中,它便可以被任何对象当做⾃⼰的⽅法使⽤. object.hasOwnProperty( propertyName )可以判断该对象是否有该原型

**原型链:**是每个对象都有 proto 属性,此属性指向该对象的构造函数的原型。对象可以通过 proto 与上游的构造函数的原型对象连接起来,⽽上游的原型对象也有⼀个 proto ,这样就形成了原型链。

**继承:**利用原型中的成员可以被和其相关的对象共享这一特性,可以实现继承,这种实现继承的方式,就叫做原型继承.

19:Promise的理解

romise 是一种解决异步编程的方案,相比回调函数和事件更合理和更强大。从语法上讲,promise是一个对象,从它可以获取异步操作的消息;

对于promise,只要resolve和reject是异步代码

  • 三种状态:

    1.pending 初始状态也叫等待状态

    2.resolve成功状态

    3.rejected失败状态;创造promise实例后,它会立即执行。

  • 两个特点:

    1.Promise对象的状态不受外界影响

    2.Promise的状态一旦改变,就不会再变,任何时候都可以得到这个结果,状态不可以逆,

  • 解决两个问题

    1.回调地狱,代码难以维护

    2.promise可以支持多并发的请求,获取并发请求中的数据

  • 【promise是解决异步的问题,不能说promise本身是异步的。Promise本身是同步的立即执行函数 】

//【先同步代码在,有微则微,无微则宏】
console.log('start')
let promise1 = new Promise(function (resolve,reject) {
     
    console.log('1')
    resolve()
    console.log('1 end')
}).then(function () {
     
    console.log('2')
})
setTimeout(function(){
     
    console.log('settimeout')
})
console.log('end')
//所以上述代码的执行顺序是:Start->1,->1 end->end->2-> settimeout

20:Promise在哪里使用过

在数据请求的解决回调地狱的时候被使用

以及axios封装时候使用

在service拦截器的时候过

21:js中call()和apply()的区别

call和apply都是调用一个对象的一个方法,用另一个对象替换当前对象。

相同点:两个方法产生的作用是完全一样的。

不同点:方法传递的参数不同,apply第二个参数是数组

22:跨域/同源策略

在前后端分离的模式下,前后端的域名是不一致的,此时就会发生跨域访问问题

跨域问题来源于浏览器的同源策略,是浏览器处于安全方面的考虑,只允许本域名下的接口交互,即只有 同协议,同域名,同端口号相同,则允许相互访问,不同源的客户端脚本,在没有明确授权的情况下,不能读写对方的资源。

也就是说JavaScript只能访问和操作自己域下的资源,不能访问和操作其他域下的资源。

23:this的指向

This和普通函数连用的时候,谁调用this,this就指向谁

This和构造函数连用的时候,this指向的是new出来的

This和事件连用的时候,this表示触发该事件的事件对象

This和类连用的时候,this表示的是祖父

24:什么是jsonp工作原理,他为什么不是ajax

  • 在调用方式上"看起来"很像,目的也一样,都是请求一个url,然后把服务器返回的数据进行处理,

  • ajax和jsonp其实本质上是不同的东西

    ajax的核心是通过XmlHttpRequest获取本页内容,

    jsonp则是动态添加

25:jsonp和json的区别

1,Jsonp 并不是⼀种数据格式,⽽ json 是⼀种数据格式,它可以被任何的编程语言读取和作为数据格式来传递。

2.jsonp 是⽤来解决跨域获取数据的⼀种解 决⽅案,

3·在开发中。前–>json转为json字符串–>后端解析后生成对应的数据结构

26:深浅拷贝是什么如何实现?

Js中数据分为两种模式

1基本数据类型:值存在堆空间内

2引用数据类型:值会保存在堆空间以及栈空间中,其中栈空间保存的是真实值的地址,该地址指向真实的数据

深拷贝是指:深拷贝的话就会拷贝多层,嵌套的对象也会被拷贝出来,相当于开辟一个新的内存地址用于存放拷贝的对象。

**浅拷贝是指:**如果拷贝基本类型,那么就等于赋值一样,会直接拷贝其本身;但如果拷贝的是引用类型,就只会拷贝一层,如果 原对象发生改变,那么拷贝对象也会发生改变。

深拷贝的实现有三种方式

  • es6中的Object.assign((),obj1)

    Let obj1={
           
    Name:”你好”
    Age:18
    }
    Var obj2=Object.assign({
           },obj1)
    Obj2.name=”李银河”
    Console.log(obj1. Name)
    Console.log(obj2. Name)
    
    
  • json.parse(json.stringfy())的方式

     var obj={
           
    	  name:"你好",
    	  age:18,
    	  sex:"女"
      }
      var obj2=JSON.parse(JSON.stringify(obj))
      obj2.name="李银河"
      console.log(obj.name)
      console.log(obj2.name)	
    
    

27:请输出三种减少页面加载时间的方式

  • 图片使用懒加载的方式
  • 路由使用懒加载的方式
  • 减少http的请求
  • 对过大的图片,进行切割,或者使用压缩后的图片
  • 对于一些比较小的图片,采用雪碧图的方式
  • 压缩js,css文件代码

28:JavaScript 类数组对象的定义?

数组对象和数组类似,但是不能调用数组的方法。拥有 length 属性和若干索引属性的对象就可以被称为类数组对象

例如:arguments 和 DOM 方法的返回结果

类数组转换为数组的方法

  • 通过 call 调用数组的 slice 方法来实现转换

    Array.prototype.slice.call(arrayLike);
    
  • 通过 call 调用数组的 splice 方法来实现转换

    Array.prototype.splice.call(arrayLike, 0);
    
  • 通过 Array.from 方法来实现转换

    Array.from(arrayLike);
    

29:为什么函数的 arguments 参数是类数组

arguments是一个对象,它的属性是从 0 开始依次递增的数字,还有calleelength等属性,但是它们却没有数组常见的方法属性

类数组的遍历

  • 将数组的方法应用到类数组上,就可以使用callapply方法,

    function foo(){
            
      Array.prototype.forEach.call(arguments, a => console.log(a))
    }
    
  • 使用Array.from方法将类数组转化成数组:‌

    function foo(){
            
      const arrArgs = Array.from(arguments) 
      arrArgs.forEach(a => console.log(a))
    }
    
  • 使用展开运算符将类数组转化成数组

    function foo(){
            
        const arrArgs = [...arguments] 
        arrArgs.forEach(a => console.log(a)) 
    }
    

方法来实现转换

Array.from(arrayLike);

29:为什么函数的 arguments 参数是类数组

arguments是一个对象,它的属性是从 0 开始依次递增的数字,还有calleelength等属性,但是它们却没有数组常见的方法属性

类数组的遍历

  • 将数组的方法应用到类数组上,就可以使用callapply方法,

    function foo(){
            
      Array.prototype.forEach.call(arguments, a => console.log(a))
    }
    
  • 使用Array.from方法将类数组转化成数组:‌

    function foo(){
            
      const arrArgs = Array.from(arguments) 
      arrArgs.forEach(a => console.log(a))
    }
    
  • 使用展开运算符将类数组转化成数组

    function foo(){
            
        const arrArgs = [...arguments] 
        arrArgs.forEach(a => console.log(a)) 
    }
    

第四大部分

你可能感兴趣的:(面经,面试,javascript)