谈谈我在面试中遇到的javascript中常见的几个问题

本文详细介绍了JavaScript的基本和引用数据类型,内存存储机制,数组的多种判断方法,let、const和var的区别,以及ES6新特性如箭头函数和解构赋值。还涵盖了事件冒泡、设计模式和防抖节流的概念。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、js的数据类型有哪些
1、基本类型:

Boolean(布尔类型),String(字符串类型),Number(数字类型),Null,Undefined,Bigint还有一个es6新增的Symbol。

2、引用类型:

Object(对象),Function(函数),Array(数组)

二、js的内存存储的方式
1、栈内存:引擎执行代码时工作的内存空间,除了引擎,也用来保存基本类型数据和引用数据类型的地址

2、堆内存:用来保存一组无序且唯一的引用类型值。可以使用栈中的键名来获取

基本数据类型放在栈内存里面;

引用数据类型有一个占位在栈内存里,真实的数据在堆内存中,并且占位有一个指针指向对应的内存空间。这就是为什么const可以对原引用数据类型进行修改,而不能重新赋值一个新对象的原因。一是因为指针未发生改变,二是因为指针指向新的内存地址会报错。

如果,我们使用const声明的是一个对象的话是可以修改值的,因为这个常量不能修改指的是指向的地址不能修改,我只是修改里面的内容,堆空间地址是不变的,所以是可以修改的。

三、js中如何判断是不是一个数组
1. 通过 instanceof 判断
instanceof 运算符用于检测构造函数的 prototype 属性是否出现在原型链中的任何位置,返回一个布尔值

let a=[ ];
a instanceof Array   //true
 
 
let b={ }
b instanceof Array  //false
2. 通过 constructor 判断
实例的构造函数属性 constructor 指向构造函数,那么我们通过 constructor 属性也可以判断是否为一个数组。

let a =[1,2,3,4]
a.constructor === Array    //true
3. 通过 Array.isArray() 判断
Array.isArray()  用于确定传递的值是否是一个数组,返回一个布尔值。

let a =[1,2,3]
Array.isArray(a)  //true
4. 通过 Object.prototype.toString.call() 判断
Object.prototype.toString.call() 可以获取到对象的不同类型 

let a=[1,2,3]
 
Object.prototype.toString.call(a)=== '[object Array]' //true 
它不仅仅可以检测是否是数组,还可以检测是否是一个函数或者数字等等

let a=function (){}
 
Object.prototype.toString.call(a)=== '[object Function]' //true 
 
let b=3
 
Object.prototype.toString.call(b)=== '[object Number]' //true 
四、let、const、var的区别
1. var声明的变量会挂载在window上,而let和const声明的变量不会
var a=1;
 
console.log(window.a)  // 1
 
let b=1;
console.log(window.b)  //undefined
 
 
const c=1;
console.log(window.c)  //undefined
2. var声明变量存在变量提升,let和const不存在变量提升 
console.log(a);  //undefined
var a = 1;
 
let b = 1;
console.log(b);  //1
 
console.log(b2)  //报错
let b2 = 1;
 
console.log(c);  //报错
const c = 1;
3. let 和 const 声明形成块级作用域
if () {
    var a = 10;
    let b = 10;
}
function fn() {
   return {
      a: 100,
   };
}
fn();
console.log(a);  //100
console.log(b);  //报错:b is not defined
4. 同一作用域下 let 和 const 不能声明同名变量,而var可以
const a = 1;
const a = 4;   //报错:标识符'a'已经声明
 
var b=1;
var b=2;        //不会报错
 
let c=1;
let c=2;       //报错:标识符'c'已经声明
5. const 声明时的事项
一旦声明必须赋值.
声明后不能在修改.
如果声明的是引用类型数据,可以修改.
五、 JS常见的设计模式有那些
单例模式,工厂模式,适配模式,观察者模式等

单例模式:就是保证一个类里面只有一个实例,实现的方法一般是先判断实例存在与否。如果存在就直接返回,不存在就创建了在返回。单例作为一个命名空间的提供者,从全局命名空间提供一个唯一访问点来访问该对象

观察者模式:观察者模式的工作就是在解耦。让耦合的双方都依赖于抽象,不是依赖于具体。从而使一方的变化不会影响到另外一方.

六、es6新增语法
let/const 箭头函数 模板字符串 解构赋值 等

let/const

Const声明一个常量

let声明一个变量不会变量提升

箭头函数

箭头函数没有this 他的this指向上一层

模板字符串

let a=18
console.log(`李磊${a}岁了`)//李磊18岁了
解构赋值

数组解构,函数参数解构 对象解构

七、阻止事件冒泡的方式
冒泡事件:比如说鼠标点击了一个按钮,同样的事件将会在那个元素的所有祖先元素中被触发。这一过程被称为事件冒泡。

阻止冒泡事件有三种方法:

1.event.stopPropagation()方法
$('.btn').click(function (even) {
        even.stopPropagation();
        alert('按钮被点击了');
    })
 这是阻止事件的冒泡方法,不让事件向documen上蔓延,但是默认事件任然会执行,当你掉用这个方法的时候,如果点击一个连接,这个连接仍然会被打开。
例如:

<a href="https://www.youkuaiyun.com/" class="box">
    <button class="btn">按钮</button>
</a>
2.event.preventDefault()方法 
$('.btn').click(function (even) {
        even.preventDefault();
        alert('按钮被点击了');
})
这是阻止默认事件的方法,调用此方法是,连接不会被打开,但是会发生冒泡,冒泡会传递到上一层的父元素; 

3.return false ;
$('.btn').click(function (even) {
        alert('按钮被点击了');
        return false;
})
 这个方法比较暴力,他会同事阻止事件冒泡也会阻止默认事件;写上此代码,连接不会被打开,事件也不会传递到上一层的父元素;可以理解为return false就等于同时调用了event.stopPropagation()和event.preventDefault()

八、==和===的区别
==是比较值相等即可

console.log(1=='1') //true
===不仅比较值是否相等还要比较数据类型是否相同

console.log(1==='1') //false
console.log(1===1)//true
九、 判断JS的数据类型
1. typeof
typeof主要用来判断基本数据类型 他返回的数据类型是字符串 (注意:typeof来判断null和引用数据类型 返回的结果都是 ‘object’)

typeof 1          //number
typeof 'a'        //string
typeof true       //boolean
typeof undefined  //undefined  
typeof null       //object
typeof {}         //object 
typeof [1,2,3]    //object
 
function Fn(){}
typeof new Fn()    //object
 
typeof new Array() //object
2.instanceof
instanceof 后面一定要是对象类型,并且大小写不能错 (专门判断引用数据类型)

console.log(a instanceof Array)   //true
console.log(b instanceof Date) 
console.log(c instanceof function)    //true
console.log(d instanceof function)     //false
十、 js常见的创建方式
//1.实例化创建  new
var obj=new Obj();
obj.name="磊磊"
obj.age=18
obj.say=function(){
   console.log(this.name)
}
 
//2.直接创建
let obj1={
name:"磊磊",
age:18
}
 
//3.自定义构造函数创建对象
 let OBJ=new obj2("磊磊",18)
    function obj2(name,age){
        this.name=name;
        this.age=age;
        console.log(this.name);
   }   

十一、 map和forEach的区别
1.map()会分配内存空间储存新的数组并且返回 foreach()不会返回新的数据

2.foreach()允许callback改变原数组的内容。map()返回新的数组。

3.map多用于复杂的逻辑运算中 在react中循环多数用map

十二、 数组去重的方法
1.双重for循环去重
//数组去重
   function disTinct(arr) {
       var ans = []
       for (var i = arr.length - 1; i >= 0; i--) {
           var nb = 0 //没重复为0.有重复不为0
           for (var j = i - 1; j >= 0; j--) {
               if (arr[i] == arr[j]) {
                   nb = 1
                   break
               }
           }
           if (nb == 0) {
               ans.unshift(arr[i])
           }
       }
       return ans
   }

2. indexof去重
//数组去重(indexOf)
function unique(arr) {
    var res = []
    for (var i = 0; i < arr.length; i++) {
        if (res.indexOf(arr[i]) == -1) {
            res.push(arr[i])
        }
    }
    return res
}
3. sort排序后循环数组去重 
function unique(arr){
  var arr2 = arr.sort();
  for(var i=1;i<arr2.length;){
    if(arr2[i] === arr2[i-1]){
      arr2.splice(i,1);       
    }else{
           i++;
        }
  }
  return arr2;
}
十三、 number和parseint的区别 
parseInt() 函数:
parseInt()函数用于解析字符串并将其转换为指定基数的整数。它需要两个参数,要解析的字符串和要使用的基数。基数是一个介于2和36之间的整数,表示数字的基数。

如果parseInt()在解析过程中遇到不符合指定基数的字符,它将忽略该字符和所有后续字符。然后它将解析到该点的值作为一个整数返回。在这种情况下,允许使用前导或尾随的空格。

如果parseInt()函数得到参数如果以数字开头,就会返回开头的合法数字部分;如果以非数字开头,则它将返回NaN。此NaN值不是任何基数的有效数字,不能用于任何数学计算。

语法:

parseInt(string, radix)
Number()函数:
Number()函数用于创建基本类型Number对象。它接受一个参数,即数字的值。此值可以使用字符串传递,Number函数将尝试将其表示为数字。如果参数无法转换为数字,则返回NaN值。此NaN值不是有效数字,不能用于任何数字计算。

语法:

Number(valueString)
parseInt()和Number()之间的区别
1、当转换的内容包含非数字的时候,Number() 会返回NaN(Not a Number);parseInt() 要看情况,如果以数字开头,就会返回开头的合法数字部分,如果以非数字开头,则返回NaN。

2、parseInt()仅返回整数值的区别,而Number()返回包括浮点的所有数字。

十四、 Eventloop机制
这个是js的一个底层运行的原理 因为js的单线程的。但是一些耗时的任务会影响到我们的执行效率。这样我们使用异步的时候 会单独开辟出来一个异步线程。将这些耗时的放在异步线程中。等主线程里面执行完毕之后,再从异步队列中取出一个到主线程中执行。执行完之后在在异步线程中取出第二个。这个过程就是eventloop循环机制

十五、防抖和节流
防抖是指我们在连续对一个事件进行操作的时候,这个事件只会按照固定每n秒执行一次的时间执行

(就是为了防止用户连续点击多长清除相同的数据 造成浏览器和服务器频繁的接收带来的压力)

节流大多用于搜索框等地方 是指我们在连续操作一个事件的时候,这个事件不会执行,只有等我们操作完成之和等n秒后自己执行

(也是减少浏览器和服务器的压力)

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值