javascript技巧

关注公众号 jb51net

关闭
首页 > 网络编程 > JavaScript > javascript技巧 > JS常问面试题

JavaScript常问面试题及答案总结大全

作者:巛、

最近在准备面试,JS的基础问题是每一家公司必问的方面,这篇文章主要介绍了JavaScript常问面试题的相关资料,文中通过代码介绍的非常详细,需要的朋友可以参考下

面试题:延迟加载JS有哪些方式?

https://www.growingwiththeweb.com/2014/02/async-vs-defer-attributes.html

延迟加载:async、defer
    例如: <script defer type="text/javascript" src='script.js'></script>

defer:等html全部解析完成,才会执行js代码,顺次执行js脚本。
async:async是和html解析同步的(一起的),不是顺次执行js脚本(谁先加载完谁先执行)。

面试题:JS数据类型有哪些?

基本类型: string、number、boolean、undefined、null、symbol,bigint
引用类型:object

NaN是一个数值类型,但是不是一个具体的数字。

面试题:null和undefined的区别

1. 作者在设计js的都是先设计的nul1(为什么设计了null:最初设计js的时候借鉴了java的语言)
2. null会被隐式转换成0,很不容易发现错误。
3. 先有null后有undefined,出来undefined是为了填补之前的坑。

具体区别:JavaScript的最初版本是这样区分的:null是一个表示"无"的对象(空对象指针),转为数值时为0;undefined是一个表示”无”的原始值,转为数值时为NaN。

面试题:JS数据类型考题

<script type="text/javascript">
    console.log( true + 1 );   // 2
    console.log( 'name'+true );  //nametrue
    console.log( undefined + 1 );  //NaN
    console.log( typeof(undefined + 1 ));  //number
    console.log( typeof null );  //Object
    //字符串和其他类型相加,变成连接的形式
    
    alert(typeof(NaN));   // number
    alert(typeof(undefined))  // undefined
    alert(typeot(null))  // Object
</script>

面试题:==和===有什么不同

== :比较的是值
    string == number || booleanll number ....都会隐式转换
    通过valueOf转换(valueOf()方法通常由JavaScript在后台自动调用,并不显示地出现在代码中。)
=== :除了比较值,还比较类型

console.log( 1 =='1' );     // true
console.log( true == 1 );     // true
console.log( null == undefined );     // true
console.log( [1,2] == '1,2' )   // true

面试题:JS微任务和宏任务

1.js是单线程的语言。
2.js代码执行流程: 同步执行完 ==》 事件循环
    同步的任务都执行完了,才会执行事件循环的内容
    进入事件循环:请求、定时器、事件 ···
3. 事件循环中包含: 【微任务、宏任务】
    微任务:promise.then
    宏任务:setTimeout...

要执行宏任务的前提是清空了所有的微任务
流程:同步 ==》 事件循环【微任务和宏任务】 ==》 微任务 ==》 宏任务 ==》 微任务...

面试题:JS作用域考题

1. 除了函数外,js是没有块级作用域。
2. 作用域链:内部可以访问外部的变量,但是外部不能访问内部的变量。
    注意:如果内部有,优先查找到内部,如果内部没有就查找外部的。
3. 注意声明变量是用var还是没有写(window.)
4. 注意:js有变量提升的机制【变量悬挂声明】
5. 优先级:声明变量>声明普通函数>参数>变量提升

面试的时候怎么看:
    1.本层作用域有没有此变量【注意变量提升】
    2.注意:js除了函数外没有块级作用域
    3.普通声明函数是不看写函数的时候顺序 

// 考题一:
function c(){
    var b = 1;
    function a(){
        console.log( b  );  // undefined
        var b = 2;
        console.log( b );  //2
    }
    a();
    console.log( b );  // 1
}
c();
// 考题二:
var name = 'World!';
(function(){
	if (typeof name ==='undefined'){
		var name ='Jack':
		console.log('Goodbye'+ name):  // Goodbye Jack
	}else{
		console.log('Hello'+name):
	 }
})()
// 考题三
var bar = 1;
function test(){
	console.log( bar );  //  undefine
	var bar = 2;
	console.log( bar );  // 2
}
test();

function fun( a ){
	var a = 10;
	functibn a(){}
	console.log( a );  // 10
}
fun( 100 );
// 考题四:
function fun(){
    var a = 2;
	function a(){}
		console.log( a );  // 2
}
fun();


function fun(){
	console.log( a );  // f a(){}
	var a = 10;
	function a(){}
}
fun();

function fun(){ // var a
	a=10;
	console.log( a );  // 10
	var a = 20;
	console.log( a );  // 20
}
fun();

面试题:JS对象考题

JS对象注意点:
1. 对象是通过new操作符构建出来的,所以对象之间不相等
2. 对象注意:引用类型
3. 对象的key都是字符串类型
4. 对象如何找属性|方法
  先在对象本身找===>构造函数中找===>对象原型中找===>构造函数原型中找        ===>对象上一层原型查找

// 面试题一:
console.log( [1,2,3] === [1,2,3] );  // true
// 面试题二:
var obj1= {
	a:'hellow‘
}
var obj2 = obj1
obj2.a = 'world'
console.log(obj1)	//{a:'world'}
(function(){	
	console.log(a)  // undefinud
	var a=1
})();
// 面试题三:
var a = {};
var b = {
	key:'a'
}
var с = {
	key:'c"
}
a[b] ='123';
a[c] ='456';
console.log( a[b] )  // '456'

面试题:JS作用域+this指向+原型考题

// 考题一:
function Foo({
	getName= function(){console.log(1)}//注意是全局的window.
	return this;
}

Foo.getName = function()(console.log(2))
Foo.prototype.getName = function()(console.log(3)}
var getName = function()(console.log(4))
function getName(){
	console.log(5)
}

Foo.getName();	 // 2
getName();	  // 4
Foo().getName(); // 1
getName();   // 1
new Foo().getName();   // 3
// 考题二:
var o ={
	a:10,
	b:{
		fn:function(){
			console.log(this.a );	// undefined
			console.log(this)	  // {fn:f}, 代表对象
		}
	}
}
o.b.fn();

面试题:JS判断变量是不是数组,你能写出哪些方法

方法一:isArray
var arr = [1,2,3];
console.log(Array isArray( arr ) );

方法二:instancerof
var arr = [1,2,3];
console.log( arr instanceof Array);

方法三:原型prototype
console.log( Object.prototype.toString.call(arr).indexOf('Array') > -1):

方法四:isPrototypeOf()
console.log( Array.prototype.isPrototypeof(arr))

方法无:constructor
console.log( arr.constructor.toString().indexof('Array') > -1)

面试题:slice是干嘛的、splice是否会改变原数组

1.slice是来截取的
参数可以写slice(3)、slice(1,3)、slice(-3)
返回的是一个新的数组
2.splice功能有:插入、删除、替换
返回:删除的元素
该方法会改变原数组

面试题:JS数组去重

方式一:new Set
var arr1 = [1,2,3,2,4,1];
console.log( Array.from( new Set(arr1)));  // [1,2,3,4]
console.log( [...new Set(arr1)] );  // [1,2,3,4]

function unique(arr){
	return [...new Set(arr)]
}
console.log(unique(arr1) );  // [1,2,3,4]
方式二:indexOf
var arr2 = [1,2,3,2,4,1];
function unique( arr ){
	var brr = [];
	for( var i=0;i<arr.length;i++){
		if( brr.indexOf(arr[i]) == -1){
			brr.push( arr[i] );
		}
	}
	return brr;
}
console.log( unique(arr2) );  // [1,2,3,4]
方式三:sort
var arr3 = [1,2,3,2,4,1];
function unique( arr ){
	arr = arr.sort();
	var brr = [];
	for(var i=0;i<arr.length;i++){
		if(arr[i] !== arr[i-1]){
		brr.push( arr[i] );
		}
	}
	return brr;
}
console.log( unique(arr3) );  // [1,2,3,4]

面试题:找出多维数组最大值

function fnArr(arr){
	var newArr = [];
    
	arr.forEach((item,index)=>{
		newArr.push(Math.max(...item))
	})
	return newArr;  // [5, 27, 39, 1001]
}
console.log(fnArr([
	[4,5,1,3],
	[13,27,18,26],
	[32,35,37,39],
	[1000,1001,857,1]
]))

面试题:给字符串新增方法实现功能

/*考题:
1.给字符串对象定义一个addPrefix函数,当传入一个字符串str时,它会返回新的带有指定前
缀的字符串,例如:
console.log("world".addPrefix("hello")
控制台会输出::“helloworld"
*/
String.prototype.addPrefix = function(str){
	return str + this;
}
console.log('world'.addPrefix('hello'))  // helloworld

面试题:找出字符串出现最多次数的字符以及次数

var str = 'helloworld'
var obj={};
for(var i=0;i<str.length;i++){
    //charAt() 方法可返回指定位置的字符。
	var char = str.charAt(i);
	if( obj[char]){
		obj[char]++;
	}else{
		obj[char] = 1;
    }
}
console.log( obj );  // {h: 1, e: 1, l: 3, o: 2, w: 1, …}

//统计出来最大值
var max = 0;
for( var key in obj ){
	if( max < obj[key] ){
		max = obj [key];
    }
}
//拿最大值去对比
for( var key in obj ){
	if(obj[key] == max ){
		console.log('最多的字符是' + key);  //最多的字符是l
		console.log('出现的次数是' + max);  // 出现的次数是3
    }
}

面试题:new操作符具体做了什么

1. 创建了一个空的对象
2. 将空对象的原型,指向于构造函数的原型
3. 将空对象作为构造函数的上下文(改变this指向)
4. 对构造函数有返回值的处理判断
5. 如果构造器中没有返回对象,则返回上面的创建出来的对象

面试题:闭包

1.闭包是什么
闭包是一个函数加上到创建函数的作用域的连接,闭包“关闭”了函数的自由变量。
2. 闭包可以解决什么问题【闭包的优点】
2.1内部函数可以访问到外部函数的局部变量
2.2闭包可以解决的问题
var lis = document.getElementsByTagName('li');
for(var i=0;i<lis.length;i++){
  (function(i){
   lis[i].onclick = function(){
    alert(i);
   }
  })(i)
}
3. 闭包的缺点
3.1 变量会驻留在内存中,造成内存损耗问题。
   解决:把闭包的函数设置为null
3.2 内存泄漏【ie】 ==> 可说可不说,如果说一定要提到ie

面试题:原型链

1. 原型可以解决什么问题
	对象共享属性和共享方法
2.    谁有原型
	函数拥有:prototype
	对象拥有:__proto__
3.对象查找属性或者方法的顺序
	先在对象本身查找 --> 构造函数中查找 --> 对象的原型 --> 构造函数的原型中 --> 当前原型的原型这找
4.原型链
	4.1 是什么?:就是把原型串联起来
	4.2  原型链的最顶端是null
	
每个对象(Object)都有一个私有属性指向另一个名为原型(prototype)的对象。原型对象也有一个自己的原型,层层向上直到一个对象的原型为 null。根据定义,null 没有原型,并作为这个原型链(prototype chain)中的最后一个环节。

隐式原型

原型链

面试题:JS继承有哪些方式

// 方法一:ES6
class Parent{
	constructor(){
		this.age = 18;
	}
}
class Child extends Parent{
	constructor({
		super();
		this.name ='张三';
	}
}
let o1 = new Child();
console.log( o1,o1.name,o1.age );
//方法二:原型链继承(实现了共享)
function Parent(){
	this.age = 20;
}
function Child(){
	this.name= '张三'
}

Child.prototype = new Parent();
let o2 = new Child();
console.log( o2,o2.name,o2.age ); // {name:'张三',age:20},'张三',20
// 方法三:借用构造函数(实现不了共享)
function Parent(){
	this.age = 20;
}
function Child(){
    Parent.call(this);
	this.name= '张三';
}

let o3 = new Child();
console.log( o3,o3.name,o3.age ); // {name:'张三',age:20} '张三' 20
// 方法四:组合式继承(既可以实现共享,也可以解决原型链问题)
function Parent(){
	this.age = 20;
}
function Child(){
    Parent.call(this);
	this.name= '张三';
}

Child.prototype = new Parent();
let o4 = new Child();
console.log( o4,o4.name,o4.age ); // {name:'张三',age:20} '张三' 20

说一下call、apply、bind区别

共同点:功能一致
可以改变this指向

语法:函数.call()、函数.apply()、函数.bind()

区别:
1. call、apply可以立即执行。bind不会立即执行,因为bind返回的是一个函数需要加入()执行
2.参数不同:apply第二个参数是数组。call和bind有多个参数需要挨个写。

var str='你好';
varobj={str:'这是obj对象内的str'}
function fun(){
	console.log( this, this.str );
}
//fun.call(obj); // call立即执行
//fun.apply(obj); // apply立即执行
fun.bind(obj)(); // 执行结果为函数
fun. bind(obj) ; // bind不会立即执行,因为bind返回的是函数

fun();
var str ='你好';
varobj={str:'这是obj对象内的str'}
function fun( name, age ){
	this.name = name;
	this.age = age;
	console.log( this,this.str );
}
fun.call(obj,‘张三',18); // {str:'这是obj对象内的str',name:'张三',age:18} '这是obj对象内的str'
fun.apply(obj,['张三',88]);// {str:'这是obj对象内的str',name:'张三',age:88} '这是obj对象内的str'
fun.bind(obj,['张三',88])();// {str:'这是obj对象内的str',name:['张三',88],age:undefined} '这是obj对象内的str'
fun.bind(obj,'张三',88)();// {str:'这是obj对象内的str',name:'张三',age:88} '这是obj对象内的str'

场景

// apply
var arr1= [1,2,4,5,7,3,321];
console.log(Math.max.apply(null,arr1))

// bind
var btn = document.getElementById('btn');
var h1s = document.getElementById('h1s');
btn.onclick = function(){
	console.log( this.id );
}.bind(h1s)

sort背后原理是什么?

V8引擎sort函数只给出了两种排序InsertionSort和QuickSort,数量小于10的数组使用InsertionSort,比10大的数组则使用QuickSort。

之前的版本是:插入排序和快排,现在是冒泡

链接:
https://github.com/v8/v8/blob/ad82a40509c5b5b4680d4299c8f08d6c6d31af3c/src/js/array.js

var arr1= [12,11,1,23,'45','34',21,'b','a','ab','bc'];
console.log( arrl.sort());  // [1,11,12,21,23,'34','45','a','ab','b','bc']

var arr2= [12,111,11,1,23,'45','34',21];
var arr3 = arr2.sort(function( a, b ){
	return b-a;
})
console.log( arr3 );  // [111,'45','34',23,21,12,11,1]
var arr4 = [
	{name:'zhangsan',age:18},
	{name:'lisi',age:2},
	{name:'wangwu',age:50},
];

function compare(age){
	return function(a,b){
		var val1 = alage];
		var val2 = b[age];
		return val1 - val2;
    }
}

var arr5 = arr4.sort(compare('age'));

console.log( arr5 );//  {name:'wangwu',age: 50}
					//	{name:'zhangsan',age: 18}
					//  {Rname:'lisi',age:2} 

深拷贝和浅拷贝

共同点:复制

1. 浅拷贝:只复制引用,而未复制真正的值。
2. 深拷贝:是复制真正的值(不同引用)

// 1、浅拷贝
var arr1= ['a','b','c','d'];
var arr2 = arr1;
arr1[0]='你好吗';
arr2[1]='还行';
console.log( arr1, arr2 ); // ['你好吗',‘还行','c','d']

var obj1 = {a:1,b:2}
var obj2 = Object.assign(obj1);
obj1.a = '100';
obj2.b = '你怎么养';
console.log( obj1,obj2); // {a:'100',b:'你怎么养'}
// 2、深拷贝
var obj3 = {
	a:1,
	b:2
}
var obj4 = JSON.parse(JSON.stringify( obj3));
obj3.a = '100′;
obj4.b = '你怎么阳' 
console.log( obj3, obj4 ); // {a: '100',b:2}{a:1,b:'你怎么阳'}
// 递归形式
var obj5 ={
	a:1,
	b:2,
	arr:['a','b','c','d']
}
function copyObj( obj ){
	if(Array.isArray(obj){
		var newObj = [];
	}else{
        var newObj = {};
    }
	for( var key in obj ){
		if( typeof obj[keyl =object' ){
			newObj[key] = copyObj(obj[keyl);
		}else{
			newObj[key] = obj[key];
        }
    }
	return newObj;
}
console.log(copyObj(obj5));

面试题:localStorage、sessionStorage、cookie的区别

公共点:在客户端存放数据
区别:
1.数据存放有效期
sessionStorage :仅在当前浏览器窗口关闭之前有效。【关闭浏览器就没了】
localStorage   :始终有效,窗口或者浏览器关闭也一直保存,所以叫持久化存储。
cookie     :只在设置的cookie过期时间之前有效,即使窗口或者浏览器关闭也有效。

2. localStorage、sessionStorage不可以设置过期时间
cookie有过期时间,可以设置过期(把时间调整到之前的时间,就过期了)

3.存储大小的限制
cookie存储量不能超过4k
localStorage、sessionStorage不能超过5M

****根据不同的浏览器存储的大小是不同的。

总结 

到此这篇关于JavaScript常问面试题及答案总结的文章就介绍到这了,更多相关JS常问面试题内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

您可能感兴趣的文章:
阅读全文