JavaScript

一、JS的数据类型以及它们的区别

JS的数据类型分为:基础数据类型和引用数据类型。

  • 基础数据类型:Number、Boolean、String、Undefined、Null,以及ES6新增的Symbol、BigInt。
  • 引用数据类型:Object

其中,SymbolBigInt是ES6新增的数据类型:

  • Symbol:代表创建后独一无二且不可改变的数据类型,它主要是为了解决可能出现的全局变量冲突的问题。
  • BigInt:一种数字类型的数据。它可以表示任何精度格式的整数,使用BigInt可以安全存储和操作大整数,即使这个数已经超出了Number能够表示的安全整数范围。使用BigInt可以避免精度丢失。

二、数据类型检测的方式有哪些

  1. typeof
js 复制代码
console.log(typeof 1) // number
console.log(typeof 'a') // string
console.log(typeof true) // boolean
console.log(typeof undefiend) // undefiend

console.log(typeof null) // object
console.log(typeof {}) // object
console.log(typeof []) // object

其中,null、对象、数组的数据类型判断为object,其他判断正确。

typeof null === 'object'原因:

  • JavaScript早期设计失误,null底层二进制存储为000,与object相似,导致typeof null === 'object'
  1. instanceof

instanceof可以正确判断对象数据类型,其内部运行机制是判断在其原型链中能否找到该类型的原型。

js 复制代码
console.log(1 instanceof Number) // false
console.log('a' instanceof String) // false
console.log(true instanceof Boolean) // false

console.log({} instanceof Object) // true
console.log([] instanceof Array) // true
console.log(function() {} instanceof Function) // true

instanceof只能判断引用数据类型,不能判断基本数据类型。

  1. constructor
js 复制代码
console.log((1).constructor === Number) // true
console.log(('a').constructor === String) // true
console.log((true).constructor === Boolean) // true

console.log(({}).constructor === Object) // true
console.log(([]).constructor === Array) // true
console.log((function(){}).constructor === Function) // true

constructor有两个作用,一是判断数据的类型,二是对象实例通过constructor对象访问对象的构造函数。需要注意,如果创建一个对象来改变它的原型,constructor就不能用来判断数据类型了

  1. Object.prototype.toString.call()
js 复制代码
const a = Object.prototype.toString

console.log(a.call(1))
console.log(a.call(true))
console.log(a.call('a'))
console.log(a.call([]))
console.log(a.call(function(){}))
console.log(a.call({}))
console.log(a.call(undefined))
console.log(a.call(null))

Object.prototype.toString.call()可以检测所有数据类型。

同样是检测对象obj调用toString方法,obj.toString()的结果和Object.prototype.toString.call(obj)的结果不一样,这是为什么?

因为toString是Object原型上的方法,向Array、Function(){}等类型作为Object上的实例,都重写了toString方法。不同的对象调用toString方法,调用的都是重写的toString方法,不会去调用Object原型上的方法。

三、判断数组的方法有哪些

  1. 通过instanceof判断 [] instanceof Array
  2. Object.prototype.toString.call([])
  3. 通过ES6的Array.isArray([])判断
  4. 通过原型链判断 [].__proto__ === Array.prototype
  5. 通过Array.prototype.isPrototypeOf([])判断

四、请简述js中的this

this是JavaScript中的上下文对象,它指向最后一次调用这个方法的对象。

常见的this使用情况

  1. 在普通函数中,this指向全局对象(在浏览器中指向window,在nodejs中指向global)
  2. 在函数作为对象的方法使用时,this指向该对象
  3. 箭头函数中的this,箭头函数没有自己的this,它的this永远指向它的作用域父级,且this指向不可变
  4. 构造函数中的this,指向实例对象
  5. callapplybind 方法,可以改变this指向

五、箭头函数与普通函数的区别

  1. 箭头函数更加简洁
js 复制代码
const fn = () => {} //箭头函数
function fn() {} //普通函数
  1. 箭头函数没有自己的this,它的this继承于它的上级作用域
  2. 箭头函数继承来的this指向永远不会被改变
  3. call、apply、bind不会改变箭头函数的this指向
  4. 箭头函数不能作为构造函数使用
  5. 箭头函数没有自己的arguments
  6. 箭头函数没有prototype
  7. 箭头函数不能作为Generator生成器函数,不能使用yeild关键字

六、js的模块化

js的模块化概念 :JS 模块化是为了解决作用域污染依赖混乱可维护性差的问题。随着项目变大,把代码拆成模块能让我们更好地管理依赖关系减少全局变量冲突,也方便团队协作。
模块化也为构建工具提供了基础,比如 tree-shaking按需加载等优化手段。

js的模块化分为:AMD、CommonJS、ES Module

AMD概念 :AMD(Asynchronous Module Definition)是一种浏览器端的模块化规范,由 RequireJS 推广,强调异步加载模块。

CommonJS概念 :CommonJS 是一种模块化规范,最初是为服务器端(Node.js)设计的,强调同步加载模块。

AMD和CommonJS的区别

  1. AMD是异步加载,适用于浏览器端
  2. CommonJS是同步加载,适用于nodejs

七、let、const、var区别

  1. 变量提升:var具有变量提升,let、const不存在变量提升
  2. 暂时性死区:let、const具有暂时性死区,var不存在暂时性死区
  3. 块级作用域 :块级作用域是由{}包裹,let、const具有块级作用域,var没有块级作用域。
  4. 给全局添加属性 :浏览器的全局对象是window,node的全局对象是global。var声明的变量为全局变量,并会将该变量添加到全局对象的属性上。但是let、const不会。
  5. 重复声明:var声明变量时,可以重复声明变量,后面声明的同名变量会覆盖前面的。let、const不允许重复声明。
  6. 初始值设置:const声明必须赋值,let、var可以不用设置初始值。
  7. 指针指向:var、let创建的变量可以改变指针指向(重新赋值),const声明的变量不可以改变指针指向。

八、块级作用域解决了ES5中的什么问题

  1. 解决了变量提升的问题:内层变量可以覆盖外层变量

    js 复制代码
    var x = 10
    function fn() {
        console.log(x) // undefined
        var x = 20
        console.log(x) // 20
    }
    fn()
    console.log(x) // 10 
    // fn()函数经过变量提升之后
    function fn() {
        var x
        console.log(x)
        x = 20
        console.log(x)
    }
  2. 解决了变量覆盖问题

    js 复制代码
    var x = 10
    if (true) {
    var x = 20 // 重新赋值
    }
    console.log(x) // 20
  3. for循环变量共享的问题

    • var没有块级作用域,i 变成了全局变量。
    js 复制代码
    for(var i = 0; i < 3; i++){
    setTimeOut(function() {
    console.log(i)
    }, 0)
    }
    // 预期结果: 0,1,2
    // 实际结果: 3,3,3
    • let具有块级作用域,每次循环都会创建一个新的i,setTimeout中的i互不影响。
    js 复制代码
    for(let i = 0; i < 3; i++){
    setTimeOut(function() {
    console.log(i)
    }, 0)
    }
    // 实际结果: 0,1,2
  4. 变量重复声明的问题:var创建的变量可以重复声明,容易引发问题。let、const禁止重复声明变量。

    js 复制代码
    var x = 10
    var x = 20 // 重复声明不会报错
    console.log(x) // 20

九、new操作符的实现原理

  1. 新建一个空对象
  2. 将空对象的原型挂载到构造函数的原型上
  3. 将空对象的this指向构造函数
  4. 返回这个对象
js 复制代码
// 实现
function myNew(constructor, ...args) {
    if (typeof constructor !== 'function') return
    let obj = {}
    obj.__proto__ = constructor.prototype
    const result = constructor.apply(obj, args)
    return result instanceof Object ? result : obj
}

// 使用实例 - 构造函数没有显式返回值
function Person(name, age) {
    this.name = name;
    this.age = age;
}
const person1 = new Person('lili', 24)
console.log(person1) // 打印结果 {name: 'lili', age: 24}
const person2 = myNew(Person, 'qiqi', 21)
console.log(person2) // 打印结果 {name: 'qiqi', age: 21}
console.log(person1 instanceof Person); // 打印结果 true
console.log(person2 instanceof Person); // 打印结果 true

// 使用实例 - 构造函数有显式返回值
function Fn(name, age, sex) {
    this.name = name
    this.age = age
    return { sex }
}
const fn1 = new Fn('lili', 24, '女')
console.log(fn1.name) // 打印结果 undefined
console.log(fn1) // 打印结果 {sex: '女'}
console.log(fn1.sex) // 打印结果 '女'

const fn2 = myNew(Fn, 'qiqi', 21, '男')
console.log(fn2) // 打印结果 {sex: '男'}
console.log(fn2 instanceof Fn) // 打印结果 false

十、for in和for of的区别

  • for in 循环的是键值
  • for of 循环的是键名

十一、原型和原型链

当访问对象上的一个属性时,如果在该对象身上没有找到该属性,通常会去该对象的原型上找,该原型对象又会有自己的原型,这样一层一层的向上寻找,形成了原型链。原型链的尽头一般是Object.prototype

十二、事件循环(EventLoop)

事件循环是js执行异步代码的机制,它保证了js是单线程的,也能执行异步任务不阻塞主任务。

  1. 首先会先执行同步任务,再执行异步任务,进入到事件循环过程中。
  2. 执行异步任务的时候又会区分微任务宏任务。先执行微任务
  3. 后执行宏任务,如果执行宏任务的过程中产生微任务的话,会把微任务放到微任务队列中。
  4. 执行完当前宏任务,立刻执行微任务,再执行下一轮宏任务
  • 同步任务:console.log()、变量声明、函数调用、for循环
  • 异步任务setTimeoutfetch、事件绑定(click)、Promise、DOM 渲染
  • 微任务
    1. Promise.then/catch/finallyAsync/Await
    2. MutationObserver监听 DOM 变动(浏览器原生)
    3. queueMicrotask(fn)手动添加微任务(浏览器和 Node 支持)
    4. process.nextTickNode.js 中的微任务,比 Promise 更早
  • 宏任务
    1. setTimeout(fn, 0)定时器
    2. setInterval(fn, 1000)定时重复任务
    3. setImmediate(fn)Node.js 特有,立即执行
    4. axios 网络请求

十三、闭包

  • 闭包:指在函数内部可以访问到函数外部的变量。
  • 在哪里使用过闭包:防抖、节流函数。

十四、Promise

Promise的概念:Promise是ES6新引入的异步编程解决方案。

Promise的状态

  1. pending 进行中
  2. fulfilled 已成功
  3. rejected 已失败

状态只能从 pending 变为 fulfilled或 rejected,一旦变更不可逆。

Promise的方法

  1. Promise.all: 可以放多个promise对象,会等所有promise对象都执行完成后一起返回。如果其中有一个promise对象执行失败,promise.all返回失败结果。
  2. Promise.race: race的意思是"赛跑"。它里面可以放多个promise对象,哪个promise对象先执行完成,先返回哪个promise对象。

十五、异步编程的实现方式

  1. Promise
  2. Async/Await
  3. 回调函数
  4. generator(生成器)函数

十六、内存泄露

  1. 意外的全局变量
  2. 被遗忘的计时器和回调函数
  3. 不正确的使用闭包
  4. 脱离DOM的引用

十七、ES6的新特性

1.箭头函数 2. 新的变量声明方式let、const 3. 解构赋值 const [a, b] = [1, 2] 4. promise 5. 模版字符串: 在代码层面可换行

js 复制代码
const a = 'str'
console.log(`<p>${a}</p>
<div>${a}</div>`)
  1. 扩展运算符
js 复制代码
const a = [1, 2, 3]
const b = [5, 6, 7]
const c = [...a, ...b] // [1, 2, 3, 5, 6, 7]
  1. Symbol数据类型,代表独一无二的值
  2. 模块化
  3. for...of 遍历对象的键值
  4. Map 和 Set复杂数据类型:
  5. Proxy代理
  6. 类(Class):面向对象编程的概念
  7. 默认参数(Default Parameter),在定义函数时可以给参数设置默认值

十八、数组的原生方法

七个可以改变原数组的数组方法 unshift()、shift()、push()、pop()、sort()、reverse()、splice()

数组和字符串的转换

  1. toString() 默认按逗号分隔 ["hello", "world"].toString()"hello,world"
  2. join() 将数组元素用指定分隔符连接成字符串 ["a", "b", "c"].join("-")"a-b-c"
相关推荐
哟哟耶耶14 分钟前
React-04React组件状态(state),构造器初始化state以及数据读取,添加点击事件并更改state状态值
前端·javascript·react.js
kiramario20 分钟前
用IconContext.Provider修改react-icons的icon样式
前端·javascript·react.js
destinyol22 分钟前
React首页加载速度优化
前端·javascript·react.js·webpack·前端框架
程序员小续22 分钟前
React 多个 HOC 嵌套太深,会带来哪些隐患?
java·前端·javascript·vue.js·python·react.js·webpack
慕斯策划一场流浪2 小时前
fastGPT—nextjs—mongoose—团队管理之部门相关api接口实现
前端·javascript·html·fastgpt部门创建·fastgpt团队管理·fastgpt部门成员更新·fastgpt部门成员创建
我自纵横20233 小时前
事件处理程序
开发语言·前端·javascript·css·json·ecmascript
拉不动的猪4 小时前
刷刷题50(vue3)
前端·javascript·面试
ZSK64 小时前
【HTML】分享一个自己写的3*3拼图小游戏
前端·javascript·html
Yvette-W5 小时前
【JavaScript】原型链 prototype 和 this 关键字的练习(老虎机)
开发语言·前端·javascript·ecmascript·原型模式
程序员JerrySUN5 小时前
设计模式 Day 4:观察者模式(Observer Pattern)深度解析
javascript·观察者模式·设计模式