WEB前端高频面试题(三)—— JS八股文

玻璃晴朗,橘子辉煌。

——北岛《过节》

原文:”一位本地英雄 ,在废弃的停车场上 ,唱歌 ,玻璃晴朗 ,桔子辉煌 。”

释义:他在一个废弃的停车场上唱着歌,如同玻璃透明而明朗,如同橘子一般青涩而辉煌。

JavaScript基础面试题

        JavaScript在Web前端开发中扮演着重要的角色,它是实现网页交互性和动态性的关键技术。掌握JavaScript对于成为一名成功的前端开发人员来说是至关重要的。

        理解JavaScript语言的核心概念、语法和特性。这样,在面试中被问到相关问题时,便能够更自信地回答。

延迟加载JS有哪些方式(async、defer)?

 延迟加载: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是一个数值类型,但是不是一个具体的数字。

JS数据类型考题

考题一:

 console.log( true + 1 );                //2
 console.log( 'name'+true );             //nametrue
 console.log( undefined + 1 );       //NaN
 console.log( typeof undefined ); //undefined

考题二:

 console.log( typeof(NaN) );       //number
 console.log( typeof(null) );      //object

null和undefined的区别

 1. 作者在设计js的都是先设计的null(为什么设计了null:最初设计js的时候借鉴了java的语言)
 2. null会被隐式转换成0,很不容易发现错误。
 3. 先有null后有undefined,出来undefined是为了填补之前的坑。
 ​
 具体区别:JavaScript的最初版本是这样区分的:null是一个表示"无"的对象(空对象指针),转为数值时为0;undefined是一个表示"无"的原始值,转为数值时为NaN。

== 和 === 有什么不同?

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

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 );
         var b = 2;
         console.log( b );
     }
     a();
     console.log( b );
 }
 c();

考题二:

 var name = 'a';
 (function(){
     if( typeof name == 'undefined' ){
         var name = 'b';
         console.log('111'+name);
     }else{
         console.log('222'+name);
     }
 })()

考题三:

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

JS对象考题

JS对象注意点:

 1. 对象是通过new操作符构建出来的,所以对象之间不想等(除了引用外);
 2. 对象注意:引用类型(共同一个地址);
 3. 对象的key都是字符串类型;
 4. 对象如何找属性|方法;
     查找规则:先在对象本身找 ===> 构造函数中找 ===> 对象原型中找 ===> 构造函数原型中找 ===> 对象上一层原型查找

考题一:

  [1,2,3] === [1,2,3]   //false

考题二:

 var obj1 = {
     a:'hellow'
 }
 var obj2 = obj1;
 obj2.a = 'world';
 console.log(obj1);  //{a:world}
 (function(){
     console.log(a);     //undefined
     var a = 1;
 })();

考题三:

 var a = {}
 var b = {
     key:'a'
 }
 var c = {
     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:{
         a:2,
         fn:function(){
             console.log( this.a ); // 2
             console.log( this );   //代表b对象
         }
     }
 }
 o.b.fn();

考题三:

 window.name = 'ByteDance';
 function A(){
     this.name = 123;
 }
 A.prototype.getA = function(){
     console.log( this );
     return this.name + 1;
 }
 let a = new A();
 let funcA = a.getA;
 funcA();  //this代表window

考题四:

 var length = 10;
 function fn(){
     return this.length + 1;
 }
 var obj = {
     length:5,
     test1:function(){
         return fn();
     }
 }
 obj.test2 = fn;
 console.log( obj.test1() );                             //1
 console.log( fn()===obj.test2() );              //false
 console.log( obj.test1() == obj.test2() ); //false

JS判断变量是不是数组,你能写出哪些方法?

方式一:isArray

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

方式二:instanceof 【可写,可不写】

 var arr = [1,2,3];
 console.log( arr instanceof Array );

方式三:原型prototype

 var arr = [1,2,3];
 console.log( Object.prototype.toString.call(arr).indexOf('Array') > -1 );

方式四:isPrototypeOf()

 var arr = [1,2,3];
 console.log(  Array.prototype.isPrototypeOf(arr) )

方式五:constructor

 var arr = [1,2,3];
 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];
 function unique(arr){
     return [...new Set(arr)]
 }
 console.log(  unique(arr1) );

方式二: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) );

方式三: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) );

找出多维数组最大值

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

给字符串新增方法实现功能

给字符串对象定义一个addPrefix函数,当传入一个字符串str时,它会返回新的带有指定前缀的字符串,例如:

console.log( 'world'.addPrefix('hello') ) 控制台会输出helloworld

 解答:
 String.prototype.addPrefix = function(str){
     return str  + this;
 }
 console.log( 'world'.addPrefix('hello') )

找出字符串出现最多次数的字符以及次数

 var str = 'aaabbbbbccddddddddddx';
 var obj = {};
 for(var i=0;i<str.length;i++){
     var char = str.charAt(i);
     if( obj[char] ){
         obj[char]++;
     }else{
         obj[char] = 1;
     }
 }
 console.log( obj );
 //统计出来最大值
 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);
         console.log('出现的次数是'+max);
     }
 }

new操作符具体做了什么

 1. 创建了一个空的对象
 2. 将空对象的原型,指向于构造函数的原型
 3. 将空对象作为构造函数的上下文(改变this指向)
 4. 对构造函数有返回值的处理判断
 function Fun( age,name ){
     this.age = age;
     this.name = name;
 }
 function create( fn , ...args ){
     //1. 创建了一个空的对象
     var obj = {}; //var obj = Object.create({})
     //2. 将空对象的原型,指向于构造函数的原型
     Object.setPrototypeOf(obj,fn.prototype);
     //3. 将空对象作为构造函数的上下文(改变this指向)
     var result = fn.apply(obj,args);
     //4. 对构造函数有返回值的处理判断
     return result instanceof Object ? result : obj;
 }
 console.log( create(Fun,18,'张三')   )

闭包

 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

 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 );

方式三:借用构造函数继承

 function Parent(){
     this.age = 22;
 }
 function Child(){
     this.name = '张三'
     Parent.call(this);
 }
 let o3 = new Child();
 console.log( o3,o3.name,o3.age );

方式四:组合式继承

 function Parent(){
     this.age = 100;
 }
 function Child(){
     Parent.call(this);
     this.name = '张三'
 }
 Child.prototype = new Parent();
 let o4 = new Child();
 console.log( o4,o4.name,o4.age );

说一下call、apply、bind区别

共同点:功能一致

 可以改变this指向
 ​
 语法: 函数.call()、函数.apply()、函数.bind()

区别:

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

场景:

 1. 用apply的情况
 var arr1 = [1,2,4,5,7,3,321];
 console.log( Math.max.apply(null,arr1) )
 ​
 2. 用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
 ​
 ***710行代码开始***

深拷贝和浅拷贝

 共同点:复制
 ​
 1. 浅拷贝:只复制引用,而未复制真正的值。
 var arr1 = ['a','b','c','d'];
 var arr2 = arr1;
 ​
 var obj1 = {a:1,b:2}
 var obj2 = Object.assign(obj1);
 ​
 2. 深拷贝:是复制真正的值 (不同引用)
 var obj3 = {
     a:1,
     b:2
 }
 var obj4 = JSON.parse(JSON.stringify( obj3 ));
 ​
 //递归的形式
 function copyObj( obj ){
     if(  Array.isArray(obj)  ){
         var newObj = [];
     }else{
         var newObj = {};
     }
     for( var key in obj ){
         if( typeof obj[key] == 'object' ){
             newObj[key] = copyObj(obj[key]);
         }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
     
     ****根据不同的浏览器存储的大小是不同的。

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值