JavaScript常见面试题汇总--kalrry

JavaScript常见面试题汇总

    • 1、基本类型和引用类型的区别?
    • 2、null和undefined的区别
    • 3、js中的==和+++区别是什么?
    • 4、var、let、const三者的区别?
    • 5、for循环里let换成var会发生什么?(待测试ing)
    • 6、this的指向,箭头函数的this指向?
    • 7、call、apply、bind的区别(基本原理是什么)---待完善?
    • 8、普通函数与箭头函数的区别(待完善)?
    • 9、原型,原型链与原型继承(重点)?
    • 10、作用域和作用域链?
    • 11、Ajax的步骤与封装,Ajax中200和4分别是什么意思?
    • 12、深浅拷贝的区别?如何进行深拷贝并举例----待修改
    • 13、promise是什么?作用是什么?都有哪几种状态?
    • 14、数组去重的方法
    • 15、js如何创建数组,js数组都有哪些方法?
    • 16、同一个数组,同样的限制条件,map和filter find返回值有什么区别
    • 17、延时器(什么是宏任务,微任务?)
    • 18、什么是闭包?什么情况下会使用闭包?
    • 19、什么是解构赋值?是深拷贝还是浅拷贝?
    • 20、cookie是什么?与localStorage、sessionStorage三者的区别
    • 21、如何判断一个数据是否是NaN?

1、基本类型和引用类型的区别?

  1. 基本数据类型、引用数据类型有哪些:
    1)基本类型:
    number、string、boolean、undefinded、null、symbol
    2)引用类型:
    统称为object对象
    例如:Array、obj、function…
  2. 他们之间的区别:
    1)从内存角度看:
    基本类型在内存中只占据一块空间,空间里面存储的就是数据本身,获取数据的方式是直接获取;
    引用类型在内存中占据两块空间,第一块存储的是地址,第二块存储的是数据,获取数据只能间接获取。
    2)从赋值角度看:
    基本类型赋的就是值;
    引用类型赋的是地址。
    3)从函数传参角度看:
    基本类型传的就是值;
    引用类型传的是地址。

2、null和undefined的区别

概念

  1. null:当对象没有指向地址时,就是null。也就是说,引用类型的变量在没有引用时就是null;
  2. undefined:当变量定义(声明)后,没有赋值,那么变量的值就是undefined。

区别:

  1. 相同点:
    在if判断语句中两者都会被转换为false
  2. 不同点:
    1)Number转换的值不同,Number(null)转换后输出为0;Number(undefined)转换后输出为NaN;
    2)null表示一个值被定义了,但这个值是空值;
    3)undefined表示此处应该有值,但没有被定义;

总结:undefined 和 null 从本质上是不同的。undefined定义而未赋值,但null主要是指空对象指针

二、  面试题:
a)  null:

var person = null;//定义了一个引用类型,没有指向。
alert(person); //输出null。
alert(typeof person);//输出object,person的数据类型是Object,值是null

b) undefined:

var a;   //JavaScript中定义一个变量,没有赋值时,默认为undefined
alert(typeof a); // undefined
alert(b); // 报错,因为b没有定义。所有,在浏览器的控制台中会报 b is not defined 

3、js中的==和+++区别是什么?

  1. ==可以理解为等同,会尝试进行类型转换
    1、如果两个值类型相同,进行 === 比较。
    2、如果两个值类型不同,他们可能相等。根据下面规则进行类型转换再比较:
    1)如果一个是null、一个是undefined,那么[相等]。
    2)如果一个是字符串,一个是数值,把字符串转换成数值再进行比较。
    3)如果任一值是 true,把它转换成 1 再比较;如果任一值是 false,把它转换成 0 再比较。
    4)任何其他组合,都[不相等]。

  2. ===可以理解为绝对等或恒等,是数据和类型都相等
    1、如果类型不同,就[不相等]
    2、如果两个都是数值,并且是同一个值,那么[相等]。
    3、如果两个都是字符串,每个位置的字符都一样,那么[相等];否则[不相等]
    4、如果两个值都是true,或者都是false,那么[相等]。
    5、如果两个值都引用同一个对象或函数,那么[相等];否则[不相等]。
    6、如果两个值都是null,或者都是undefined,那么[相等]。

switch结构中,是==还是===。
答:  ===

4、var、let、const三者的区别?

  1. 相同点:
    都是用来定义变量的。
  2. 不同点:
    1)、var有声明提升,let和const没有声明提升;
    2)、var是全局作用域和函数作用域,let和const是块级作用域;
    3)、var定义的全局变量是挂载在window上,let和const定义的全局变量不会;
    4)、var可以声明多个同名变量,let和const不可以重复声明;
    5)、var没有暂时性死区,let和const有暂时性死区(就是在声明之前使用变量,会报错);
    6)、let在循环里可以暂存循环变量;
    7)、const定义的变量是常量,必须赋初始值且不可以更改(const修饰的变量是只读,不能修改的,即是常量);
    8)、let和const都可以声明变量,但let的变量可以修改,const声明的变量不可修改;
  3. const在定义一个数组时,改变下标0的值会报错吗?
    不会报错,const修饰的是数组,而不是数组的元素;
    ps:const修饰引用类型时,都修饰的是地址,而不是数据;
    ps:const修饰的变量是只读,不能修改,即是产量,修饰的是直接指向修饰的内存地址

5、for循环里let换成var会发生什么?(待测试ing)

  1. 如果换成var,for循环定义的迭代变量会渗透到循环体外部;
  2. let在循环体里会暂存变量,如果在循环的时候向外输出定义的变量,得到的是当前迭代变量,换成var向外输出的都是已经循环结束的结果

6、this的指向,箭头函数的this指向?

  1. this是什么?
    this是函数的内置对象,this是代词,顾名思义this代表哪个对象,要看函数属于哪种情况。

  2. this指向有四种情况:
    1)、当this所在函数是事件处理函数时,this代表触发该事件的元素;
    2)、当this所在函数是构造函数时,this代表new出来的对象;
    3)、当this所在函数是类的方法时,this代表调用该方法的对象;
    4)、当this所在函数没有明确的所属对象或指向时,this代表window对象。

  3. 箭头函数根本没有自己的this,他内部的this就是外层代码块的this
    ps:注意,this具体表示什么意思,更多要看调用,要看运行,因外在调用时,有可能this的指向会被改变。
    ps:this指向需要注意:es5,是谁调用this,this指向谁;es6中,不管谁调用this,this指向定义他的对象。

7、call、apply、bind的区别(基本原理是什么)—待完善?

  1. 相同点
    三个函数都会改变this的指向;
  2. 不同点
    1)、bind会产生新的函数,(把对象和函数绑定死后,产生新的函数)
    2)、call和apply不会产生新的函数,只是在调用时,绑定一下而已。
    3)、call和apply的区别,第一个参数都是要绑定的this,apply第二个参数是数组(是函数的所有参数),call把apply的第二个参数单列出来。

call和apply的区别待完善?

8、普通函数与箭头函数的区别(待完善)?

  1. 区别
    1)写法格式上不同;
    2)箭头函数不能作为构造函数使用;
    3)箭头函数中没有this和arguments;arguments详解
    4)箭头函数不具有prototype原型对象
    5)箭头函数不具有super;super是什么?

  2. 箭头函数解决了哪些问题?
    1)箭头函数使函数表达更加简洁
    2)解决了this指向的问题
    ps:使用场景:
    1.简单的函数表达式,内部没有this引用,没有递归,事件绑定,解绑定
    2.内层函数表达式,需要调用this,且this应与外层函数一致时(保证指向vue实例)

9、原型,原型链与原型继承(重点)?

不要问什么是重点,重点就是全部

  1. 什么是原型?
    每个构造函数都有一个prototype属性,这个属性就是(该构造函数的)原型(属性),js在实现面向对象时,会经常使用原型,每个对象又都有一个(_proto)属性指向构造函数的prototype属性的内存区域,prototype属性里保存着所有对象共享的属性和方法;
  2. 什么是原型链?
    当访问对象的某个属性时,会先在该对象本身属性上查找,如果没有找到,则会去它的(proto)隐式原型上查找,也就是它的构造函数prototype原型属性上查找,如果还是没有,就会在prototype的(proto)中查找,这样一层层向上查找就会形成一个链式结构,我们称之为原型链;
  3. 什么是原型继承?
    继承就是在子类构造函数中继承父类构造函数的私有属性和方法,我们在子类构造函数中使用call或apply方法调用父类构造函数并改变其this指向为子类构造函数的this,此时子类的构造函数就继承了父类构造函数的私有属性和方法,将父类的实例化对象赋值给了子类的原型对象,此时子类就继承了父类的原型对象与方法;

10、作用域和作用域链?

  1. 作用域是什么?
    作用域就是变量起作用的地方或者范围,(js代码执行的时候会先查找并确定变量作用的范围);
  2. 作用域链是什么?
    作用域链是指:当js编译器在寻找变量时,先在最近的作用域里查找,如果找不到,则继续向上一级作用域里查找,依次类推,直到找到或者找不到为止,这就是作用域链。

11、Ajax的步骤与封装,Ajax中200和4分别是什么意思?

  1. 原生ajax的步骤
//1)、创建一个XMLHttpRequest对象;

let xhr = new XMLHttpRequest();

//2)、规划一个请求;

//get方式
xhr.open("get", "url?username=kalrry&userpass=123", true);

//post方式
xhr.open("post", "url", true);
xhr.setRequestHeader("Content-type","application/x-www-form-urlencoded")

//3)、发送请求

//get方式
xhr.send();

//post方式
xhr.send("name=kalrry&age=18");

//4)、接收来自服务端的响应;

xhr.onreadystatechange = function () {
	if (xhr.readystate == 4 && xhr.status == 200){
		xhr.responseText//后端响应的内容
	}
}

老版本浏览器(IE5IE6)的兼容写法:
//1、创建ActiveXObject()对象
//var xml = new ActiveXObject("Microsoft.XMLHTTP");
val xml;
if (window.XMLHttpRequest){
	xml = new XMLHttpRequest();
	}else{
	xml = new ActiveXObject("Microsoft.XMLHTTP");
	}

onreadystatechange事件
//当向服务器发送数据请求过程中,readyState的值发生改变时触发onreadystatechange事件
//readyState存有XMLHttpRequest的状态,从0~4发生变化
//0:代表请求未初始化
//1:代表已经与服务器建立连接
//2:服务器收到请求
//3:请求正在处理
//4:请求已完成,且响应已就绪
status的常见两种状态
//200:代表ok,数据响应完成并成功返回
//404:代表前端地址错误

  1. 封装ajax代码:
function ajax2110UseObj(obj){let defaultObj = {
        method:"get",
        url:"#",
        params:"",
        callback:null,
        isAsync:true
    }for(let key in defaultObj){
        // 把obj里没有传入的属性使用defaultObj的对应属性。
        if(obj[key]==undefined){
            obj[key]=defaultObj[key];
        }
    }// 1、创建XMLHttpRequest对象
    let xhr = new XMLHttpRequest();// 2、设置请求相关信息
    let urlAndParams = obj.url;
    if(obj.method.toLowerCase()=="get"){
        urlAndParams += "?"+obj.params
    }
​
    xhr.open(obj.method,urlAndParams,obj.isAsync);// 3、设置回调函数(后端响应时,调用的函数)
    xhr.onreadystatechange = function(){
        if(xhr.readyState==4 && xhr.status==200){            
            obj.callback && obj.callback(xhr.responseText);
        }
    }if(obj.method.toLowerCase()=="get"){
        // 4、发送请求
        xhr.send();
    }else if(obj.method.toLowerCase()=="post"){
        // 如果是post方式,必须设置请求头。
        xhr.setRequestHeader("Content-type","application/x-www-form-urlencoded");
        xhr.send(obj.params);
    }
}
  1. readyState是什么?
    readyState属性:表示ajax从请求到响应过程中的状态,可以获知请求响应进行到了哪一步,readyState的取值是0-4
0:表示刚创建好XMLHttpRequest对象
1:open函数调用完毕后,
2:表示后端接收到了响应
3:表示后端正在处理
4:表示后端处理完毕(即:请求响应的过程结束了)
// readyState==4:表示请求响应的过程完毕

HTTP请求响应系列02_响应报文的详解

12、深浅拷贝的区别?如何进行深拷贝并举例----待修改

深浅拷贝特指引用类型

  1. 深浅拷贝的区别:
    深拷贝: 把引用类型的地址及其它的数据都拷贝一份;
    浅拷贝: 只拷贝了引用类型的地址;

  2. 如何进行深拷贝,并举例
    如何进行深拷贝:

深拷贝的思路:

创建空对象,循环原对象的每个键,一一 赋值给空对象,并使用递归的方式,把对象属性也进行复制,以下为示例代码:

例一:

// 功能:封装一个深拷贝的函数
// 参数:被拷贝的对象
// 返回值:拷贝的对象function copyObj(obj){
    let newObj ={};
    for(let key in obj){        
        if(typeof obj[key] == "object"){ //如果说当前属性是对象的话,那么再做深拷贝
            newObj[key] = copyObj(obj[key]);
        }else{
            newObj[key] = obj[key];
        }
    }
    return newObj;
}var obj1= {
    name:"张三疯",
    sex:"男",
    address:{
        province:"陕西",
        city:"西安"
    }
}let obj2 = copyObj(obj1);

例2:待修改

//json方式实现深拷贝

var obj={
	"id":"00001",
	"name":"奚大官人",
	"age":"31",
	"sex":"female",
}
var deepObj=JSON.parse(JSON.stringify(obj))//JSON.stringify,将对象转化成字符串,字符串是基本的数据类型,意味着此时在开辟空间区存这个字符串,我们在存好的这个空间中,将字符串转换为对象
deepObj.sex="male"
console.log(obj)
console.log(deepObj)

深浅拷贝详解

13、promise是什么?作用是什么?都有哪几种状态?

  1. promise是什么?
    promise是异步编程的一种解决方案,从语法上来看,promise是一个对象,可以获取异步操作的信息,将异步操作以同步方式表达出来(使用链式的写法),避免了回调函数的层层嵌套。
  2. promise的作用是什么?
    1)避免了回调地狱问题
    2)promise对象提供了简洁的API,使得控制异步操作更加容易
  3. promise有3种状态
    1)pandding:正在进行中;
    2)rejected:失败;
    3)resolved:成功;
    状态改变,只有两种可能:从 Pending 变为 Resolved 和从 Pending 变为 Rejected
    如:函数fn1和fn2,当我们需要在fn1(fn1函数里有异步操作)调用结束后调用fn2,一般的解决方案是fn1(fn2)。而promise的做法是 fn1().then(fn2);即Promise将回调模式的主从关系调换了一个位置,变成了同等的只是顺序的关系;
    fn1().then(fn2).then(fn3).then(fn4)
    4)对象方法:then、catch
    then
then方法:
功能:把then方法的参数传给resolve和reject。 promise对象.then(resolve回调函数,reject回调函数);
参数:
then方法的第一个参数是resolve
then方法的第二个参数是reject
返回值:promise对象本身,所以,then调用完毕后,还可以继续调用then(即:链式调用)

catch

catch方法:
它和then的第二个参数一样,用来指定reject的回调,

5)类方法: all、race
all方法:

功能: Promise.all可以并行执行多个异步操作,并且在一个回调中处理所有的返回数据。返回的数据与传的参数数组的顺序是一样的。当所有的异步操作都成功才表示成功 。

参数:数组。数组里是若干个返回promise对象的函数(异步操作);

返回值:promise对象。promise对象的then方法的回调函数的参数是 所有promise对象的resolve的参数(数组形式)

race方法:

功能:也是并发,但是,与all不同之处时,当一个异步操作完成(resolve或reject)时,就调用方法了。即:多个异步操作,同时执行,谁快就用谁的结果,所以,结果不再是数组。
  1. 基础用法
new Promise(function(resolve,reject){undefined
异步代码
})
  1. 上代码:
//promise(reject,resolve,pending)
	new Promise(function(resolve){
		setInterval(()=>{
			resolve(1)
		},1000)
	}).then((num)=>{
		console.log(num*3)
		// alert(1*3)
		return num*3
	}).then((num)=>{
		console.log(num*3)
		// alert(1*3)
	})

点击跳转至大佬级理解

14、数组去重的方法

  1. 利用数组index方法
function unique(arr) {
        var arr1 = [];
        for (var i = 0; i < arr.length; i++) {
            if (arr1.indexOf(arr[i]) == -1) {
                arr1.push(arr[i]);
            }
        }
        return arr1;
    }
    console.log(unique([1,1,2,2,3,3,3,4,5,6,6,6,7]));//1,2,3,4,5,6,7
  1. ES6的set
// 第一种:
function unique(arr){
    return [...new Set(arr)]
}
​
console.log(unique([1,2,1,2,2,3,2,1]));

// 第二种
let arr = [1,2,3,1,2,5,5,3,4];
let set = new Set(arr);
arr = Array.from(set);
console.log(arr);

15、js如何创建数组,js数组都有哪些方法?

  1. 有两种创建方式:
    1)字面量创建:var arr = [];
    2)构造函数创建:var arr1 = new Array();
  2. js数组的方法:
1、push 尾增
2、pop 尾删
3、unshift 头增
4、shift 头删
5、concat 数组拼接
6、join 数组转字符串
7、reverse 逆序
8、sort 按字符串UniCode码排序
9、map 对数组的每个元素做某个处理,参数是回调函数,并且有返回值
10、slice 数组截取,在vue中与计算属性搭配,返回截取的内容用来渲染页面
11、indexOf 查找数组中的元素,找到返回该元素下标, 没找到返回-1
12、splice 截取,会改变原数组
13、filter 根据回调函数过滤相应内容并返回过滤后的数组
14、every 对数组中的每一项进行判断,若都符合则返回true,否则返回false
15、some 对数组中的每一项进行判断,若都不符合则返回false,否则返回true
16、reduce:将数组所有数值进行叠加返回
18、forEach 对数组的每个元素做某个处理,参数是回调函数

16、同一个数组,同样的限制条件,map和filter find返回值有什么区别

  1. 相同点:都不会改变原数组
  2. 不同点:
    map返回值是一个新的数组,新数组中的元素为原始数组中的元素通过回调函数处理后的值。
    find返回值:方法返回数组中满足提供的测试函数的第一个元素的值,否则返回 undefined。返回值不是数组!

const array1 = [5, 12, 8, 130, 44];
const found = array1.find(element => element > 10);
console.log(found);//12
filter:主要是用来过滤数组内容,返回一个新数组 是原数组中符合回调函数条件的所有元素。

17、延时器(什么是宏任务,微任务?)

  1. 宏任务(macroatsk)
    宏任务一般包括:setTimeout, setInterval,I/O操作(包括ajax请求)。
  2. 微任务(microtask)
    微任务包括‘;promise.then()里的操作

18、什么是闭包?什么情况下会使用闭包?

  1. 什么是闭包?
    闭包: 从结构上看,闭包的实质就函数嵌套函数,也就是定义在函数内部的函数,并且这个内部函数能够访问到外层函数中定义的局部变量,内部函数也可以当作外层函数的返回值被调用,当其中一个内部函数在包含他们的外部函数之外被调用时,就形成了闭包。
    解释一下就是:外层函数被调用后,外层函数的作用域对象无法被释放,被内层函数继续引用着,就形成了闭包

  2. 何时使用闭包: 即想要重用一个变量,又想保护变量不被污染时,在此种情况下使用

  3. 如何使用,分三步走:
    1)用外层函数包裹要保护的变量和内层函数
    2)外层函数将内层函数返回到外部
    3)调用外层函数,获得内层函数的对象,保存在外部变量中–形成了闭包

  4. 闭包的作用及特点
    1)函数嵌套函数
    2)函数内部可以引用外部的参数和变量
    3)局部变量会常驻内存
    4)使用过后的参数和变量不会被垃圾回收机制回收垃圾回收机制
    5)

  5. 闭包的优点
    1)变量长期驻扎在内存中
    2)避免全局变量的污染,仅函数内可用,不会被污染
    3)私有成员的存在(待解释…)

  6. 闭包的缺点?如何解决?
    缺点:比普通函数占用更多内存空间,过多使用会影响性能,易造成内存泄漏
    解决:闭包不在使用时,要及时释放,将引用的内存函数对象的变量赋值为null。

19、什么是解构赋值?是深拷贝还是浅拷贝?

  1. 解构赋值是es6新增的一种语法。通过解构赋值, 可以将属性/值从对象/数组中取出,赋值给其他变量。
  2. 解构赋值属于浅拷贝,因为只是进行了数据第一层的拷贝,没有进行数据更深层次的拷贝,他只是将数组、对象的地址层进行了拷贝,并没有开辟堆空间,在解构后,修改解构后的内容,原被拷贝数组、对象内容也会发生改变
// 没有进行空间的开辟
var obj = {
	a: "1",
	b: "2",
	c:{
		id:"0001"
	}
}
var newobj={
	...obj
}
newobj.c.id="kalrry"
console.log(obj)
console.log(newobj)

20、cookie是什么?与localStorage、sessionStorage三者的区别

  1. cookie是网络会话跟踪技术,通常用来存储用户登陆信息、网页浏览信息的一种技术

21、如何判断一个数据是否是NaN?

NaN概念:NaN不是一个数字且数据类型为number,而且不等于自身
如何判断

  1. 采用内置isNaN方法判断
function isNaN(n){
	if(n!=n){
		return true;
	}else{
		returu false;
	}
}
  1. 利用NaN是唯一一个不等于自身的特点来判断
var a = NaN;
	console.log(a == a); 
	//false;
  1. 采用Object.is内置方法:
	console.log(Object.is("a",NaN)); 
	console.log(Object.is(1,NaN)); 
	console.log(Object.is(NaN,NaN)); 

你可能感兴趣的:(JavaScript,javascript)