写点什么

工作中遇到的 50 个 JavaScript 的基础知识点

作者:Sunshine_Lin
  • 2022 年 1 月 06 日
  • 本文字数:7688 字

    阅读完需:约 25 分钟

工作中遇到的50个JavaScript的基础知识点

前言

大家好,我是林三心,基础是进阶的前提,今天给大家分享一下,我这一年来工作中遇到的 50 个「基础知识点」,我这一年来就有记录知识点的习惯哈哈。满分的可以找我拿礼品哦!

50 个基础知识点

1、JavaScript 有几种数据类型?

  • number:数字类型

  • string:字符串类型

  • boolean:布尔值类型

  • undefined:未定义类型

  • null:空值类型

  • object:对象类型

  • symbol:symbol 类型

  • bigint:大数字类型

2、JavaScript 最大安全数字与最小安全数字?

console.log(Number.MAX_SAFE_INTEGER)// 9007199254740991
console.log(Number.MIN_SAFE_INTEGER)// -9007199254740991
复制代码

3、深拷贝与浅拷贝的区别?

  • 深拷贝层层拷贝,浅拷贝只拷贝第一层,深层只是引用

  • 在深拷贝中,新对象中的更改不会影响原始对象,而在浅拷贝中,新对象中的更改,原始对象中也会跟着改。

  • 在深拷贝中,原始对象不与新对象共享相同的属性,而在浅拷贝中,它们具有相同的属性。

4、闭包是什么?

闭包是一个能读取其他函数内部变量的函数


  • 优点:使外部能访问到局部的东西

  • 缺点:使用不当容易造成内存泄漏的问题例子:


function a () {  let num = 0    // 这是个闭包  return function () {     return ++num  }}const b = a()console.log(b()) // 1console.log(b()) // 2
复制代码

5、原型链是什么呀?详细点!

看看我这篇文章:掘金讲「原型链」,讲的最好最通俗易懂的

6、什么是变量提升?函数提升?

变量提升


console.log(name) // undefinedvar name = 'Sunshine_Lin'
if (false) { var age = 23}console.log(age) // undefined 不会报错
复制代码


函数提升


console.log(fun) // function fun() {}function fun() {}
if (false) { function fun2(){}}console.log(fun2) // undefined 不会报错
复制代码


函数提升优先级 > 变量提升优先级


console.log(fun) // function fun() {}var fun = 'Sunshie_Lin'function fun() {}console.log(fun) // 'Sunshie_Lin'
复制代码

7、isNaN 与 Number.isNaN 的区别?

  • isNaN:除了判断 NaN 为 true,还会把不能转成数字的判断为 true,例如'xxx'

  • Number.isNaN:只有判断 NaN 时为 true,其余情况都为 false

8、解决遍历对象时,把原型上的属性遍历出来了咋办?

使用hasOwnProperty判断


function Person(name) {  this.name = name}Person.prototype.age = 23const person = new Person('Sunshine_lin')for (const key in person) { console.log(key) } // name age// 使用 hasOwnPropertyfor (const key in person) {  person.hasOwnProperty(key) && console.log(key)} // name
复制代码

9、valueOf 与 toString

  • 1、valueOf偏向于运算,toString偏向于显示

  • 2、对象转换时,优先调用toString

  • 3、强转字符串优先调用toString,强转数字优先调用valueOf

  • 4、正常情况下,优先调用toString

  • 5、运算操作符情况下优先调用valueOf

调用 valueOf

调用 toString

10、JavaScript 变量在内存中具体存储形式?

  • 基本数据类型:存在栈内存

  • 引用数据类型:指针存栈内存,指向堆内存中一块地址,内容存在堆内存中

  • 也有说法说其实 JavaScript 所有数据都存堆内存中,我也比较赞同这种说法

11、讲一讲 JavaScript 的装箱和拆箱?

装箱:把基本数据类型转化为对应的引用数据类型的操作

看以下代码,s1 只是一个基本数据类型,他是怎么能调用indexOf的呢?


const s1 = 'Sunshine_Lin'const index = s1.indexOf('_')console.log(index) // 8
复制代码


原来是 JavaScript 内部进行了装箱操作


  • 1、创建 String 类型的一个实例;

  • 2、在实例上调用指定的方法;

  • 3、销毁这个实例;


var temp = new String('Sunshine_Lin')const index = temp.indexOf('_')temp = nullconsole.log(index) // 8
复制代码

拆箱:将引用数据类型转化为对应的基本数据类型的操作

通过valueOf或者toString方法实现拆箱操作


var objNum = new Number(123);  var objStr =new String("123");   console.log( typeof objNum ); //objectconsole.log( typeof objStr ); //object console.log( typeof objNum.valueOf() ); //numberconsole.log( typeof objStr.valueOf() ); //string
console.log( typeof objNum.toString() ); // string console.log( typeof objStr.toString() ); // string
复制代码

12、null 和 undefined 的异同点有哪些?

相同点


  • 都是空变量

  • 都是假值,转布尔值都是 false

  • null == undefined 为 true 不同点

  • typeof 判断 null 为 object,判断 undefined 为 undefined

  • null 转数字为 0,undefined 转数字为 NaN

  • null 是一个对象未初始化,undefined 是初始化了,但未定义赋值

  • null === undefined 为 false

13、如何判断数据类型?

  • typeof xxx:能判断出 number,string,undefined,boolean,object,function(null 是 object)

  • Object.prototype.toString.call(xxx):能判断出大部分类型

  • Array.isArray(xxx):判断是否为数组

14、为什么 typeof null 是 object?

不同的数据类型在底层都是通过二进制表示的,二进制前三位为000则会被判断为object类型,而 null 底层的二进制全都是 0,那前三位肯定也是000,所以被判断为object

15、== 与 === 的区别?

  • ==:在比较过程中会存在隐式转换

  • ===:需要类型相同,值相同,才能为 true

16、JavaScript 的隐式转换规则?

  • 1、转成 string 类型: +(字符串连接符)

  • 2、转成 number 类型:++/--(自增自减运算符) + - * / %(算术运算符) > < >= <= == != === !=== (关系运算符)

  • 3、转成 boolean 类型:!(逻辑非运算符)

17、双等号左右两边的转换规则?

  • 1、null == undefined 为 true

  • 1、如果有一个操作数是布尔值,则在比较相等性之前先将其转换为数值——false 转换为 0,而 true 转换为 1;

  • 2、如果一个操作数是字符串,另一个操作数是数值,在比较相等性之前先将字符串转换为数值

  • 3、如果一个操作数是对象,另一个操作数不是,则调用对象的 toString()方法,用得到的基本类型值按照前面的规则进行比较

18、undefined >= undefined 为什么是 false ?

按照隐式转换规则,可转换成NaN >= NaN,NaN 不等于 NaN,也不大于,所以是false

19、null >= null 为什么是 true?

按照隐式转换规则,可转换成0 >= 0,0 等于 0,所以是true

20、[] == ![] 为什么是 true ?

按照双等号左右两边的转换规则


  • 1、! 优先级高于 ==[]不是假值,所以先转换成 [] == false

  • 2、右边为布尔值,false先转数字0,所以可转换为[] == 0

  • 3、左边为对象,[]调用toString转为 '',转换为'' == 0

  • 4、左边为字符串,''转换为0,最终为 0 == 0

21、0.1 + 0.2 === 0.3,对吗?

不对,JavaScript 的计算存在精度丢失问题


console.log(0.1 + 0.2 === 0.3) // false
复制代码


  • 原因:JavaScript 中小数是浮点数,需转二进制进行运算,有些小数无法用二进制表示,所以只能取近似值,所以造成误差

  • 解决方法:

  • 先变成整数运算,然后再变回小数

  • toFixed() 性能不好,不推荐

22、什么是匿名函数?

匿名函数:就是没有函数名的函数,如:


(function(x, y){    alert(x + y);  })(2, 3);
复制代码


这里创建了一个匿名函数(在第一个括号内),第二个括号用于调用该匿名函数,并传入参数。

23、绑定点击事件有几种方式?

三种


  • xxx.onclick = function (){}

  • <xxx onclick=""></xxx>

  • xxx.addEventListence('click', function(){}, false)

24、addEventListence 的第三个参数是干嘛的?

第三个变量传一个布尔值,需不需要阻止冒泡,默认是 false,不阻止冒泡

25、函数声明和函数表达式的区别?

  • 函数声明:享受函数提升

  • 函数表达式:归类于变量声明,享受变量提升

  • 函数提升优先级 > 变量提升优先级


console.log(fun) // fun () {}// 函数表达式var fun = function(name) {}// 函数声明function fun () {}console.log(fun) // fun (name) {}
复制代码

26、JavaScript 的事件流模型有哪些?

  • 事件冒泡:由最具体的元素接收,并往上传播

  • 事件捕获:由最不具体的元素接收,并往下传播

  • DOM 事件流:事件捕获 -> 目标阶段 -> 事件冒泡

27、Ajax、Axios、Fetch 有啥区别?

  • Ajax:是对 XMLHttpRequest 对象(XHR)的封装

  • Axios:是基于 Promise 对 XHR 对象的封装

  • Fetch:是 window 的一个方法,也是基于 Promise,但是与 XHR 无关,不支持 IE

28、load、$(document).ready、DOMContentLoaded 的区别?

DOM 文档加载的步骤为:


  • 1、解析 HTML 结构。

  • 2、加载外部脚本和样式表文件。

  • 3、解析并执行脚本代码。

  • 4、DOM 树构建完成。// DOMContentLoaded触发、$(document).ready触发

  • 5、加载图片等外部文件。

  • 6、页面加载完毕。// load触发

29、如何阻止事件冒泡?

function stopBubble(e) {  if (e.stopPropagation) {    e.stopPropagation()  } else {    window.event.cancelBubble = true;  }}
复制代码

30、如何阻止事件默认行为?

function stopDefault(e) {  if (e.preventDefault) {    e.preventDefault();  } else {    window.event.returnValue = false;  }}
复制代码

31、什么是事件委托?

当所有子元素都需要绑定相同的事件的时候,可以把事件绑定在父元素上,这就是事件委托,优点有:


  • 绑定在父元素上只需要绑定一次,节省性能

  • 子元素不需要每个都去绑定同一事件

  • 如果后续又有新的子元素添加,会由于事件委托的原因,自动接收到父元素的事件监听

32、如何实现数组去重?

// 使用 Map 去重function quchong1(arr) {  const newArr = []  arr.reduce((pre, next) => {    if (!pre.get(next)) {      pre.set(next, 1)      newArr.push(next)    }    return pre  }, new Map())  return newArr}
// 使用 Set 去重function quchong (arr) { return [...new Set(arr)]}
复制代码

33、Set 与 Array 的区别是什么?

建议看阮一峰老师的文章:Set 和 Map 数据结构

34、Map 与 Object 的区别是什么?

建议看阮一峰老师的文章:Set 和 Map 数据结构

35、NaN 是什么?有什么特点?

  • NaN 不等于自身,也就是 NaN === NaNfalse

  • NaN 为假值,转布尔值为false

  • NaN 本质是一个 number,typeof NaN === number

36、处理异步的方法有哪些?

  • 回调函数

  • promise

  • 事件监听

  • 发布订阅

  • async await

37、JavaScript 继承方式有几种?

前置工作


// 定义一个动物类function Animal (name) {  // 属性  this.name = name || 'Animal';  // 实例方法  this.sleep = function(){    console.log(this.name + '正在睡觉!');  }}// 原型方法Animal.prototype.eat = function(food) {  console.log(this.name + '正在吃:' + food);};
复制代码

1、原型链继承

核心:将父类的实例作为子类的原型


function Cat(){ }Cat.prototype = new Animal();Cat.prototype.name = 'cat';
var cat = new Cat();console.log(cat.name); // catcat.eat('fish') // cat正在吃:fishcat.sleep() // cat正在睡觉!console.log(cat instanceof Animal); //true console.log(cat instanceof Cat); //true
复制代码


优点:


  • 1、非常纯粹的继承关系,实例是子类的实例,也是父类的实例

  • 2、父类新增原型方法/属性,子类都能访问到

  • 3、简单,易于实现缺点:

  • 1、要想为子类新增属性和方法,必须要在new Animal()这样的语句之后执行,不能放构造器中

  • 2、来自原型对象的所有属性被所有实例共享

  • 3、创建子实例时,无法向父类构造函数传参

  • 4、不支持多继承

2、构造继承

核心:使用父类的构造器来增强子类实例,等于是复制父类的实例属性给子类(没用到原型)


function Cat(name) {  Animal.call(this);  this.name = name || 'Tom';}
var cat = new Cat();console.log(cat.name); // Tomcat.sleep() // Tom正在睡觉!console.log(cat instanceof Animal); // falseconsole.log(cat instanceof Cat); // true
复制代码


优点:


  • 1、解决了原型链继承中,子类实例共享父类引用属性的问题

  • 2、创建子类实例时,可以向父类传递参数

  • 3、可以实现多继承(call 多个父类对象)缺点:

  • 1、实例并不是父类的实例,知识子类的实例

  • 2、是能继承父类的实例属性和方法,不能继承原型属性/方法

  • 3、无法实现函数复用,每个子类都有父类实例函数的副本,影响性能

3、实例继承

核心:为父类实例添加新特性,作为子类实例返回


function Cat(name){  var instance = new Animal();  instance.name = name || 'Tom';  return instance;}
var cat = new Cat();console.log(cat.name) // Tomcat.sleep() // Tom正在睡觉!console.log(cat instanceof Animal); // trueconsole.log(cat instanceof Cat); // false
复制代码


优点:


  • 1、不限制调用方式,不管是new 子类()还是子类(),返回的对象具有相同效果缺点:

  • 1、实例是父类的实例,不是子类的实例

  • 2、不支持多继承

4、拷贝继承

核心:就一个一个拷贝


function Cat(name){  var animal = new Animal();  for(var p in animal){    Cat.prototype[p] = animal[p];  }  this.name = name || 'Tom';}
var cat = new Cat();console.log(cat.name); // Tomcat.sleep() // Tom正在睡觉!console.log(cat instanceof Animal); // falseconsole.log(cat instanceof Cat); // true
复制代码


优点:


  • 1、支持多继承缺点:

  • 1、效率低,内存占用高(因为要拷贝父类的属性)

  • 2、无法获取父类不可枚举方法(不可枚举方法,不能使用 for in 访问到)

5、组合继承

核心:通过父类构造,继承父类的属性并保留传参的有点,然后通过将父类实例作为子类原型,实现函数复用


function Cat(name){  Animal.call(this);  this.name = name || 'Tom';}Cat.prototype = new Animal();
Cat.prototype.constructor = Cat;
var cat = new Cat();console.log(cat.name); // Tomcat.sleep() // Tom正在睡觉!console.log(cat instanceof Animal); // trueconsole.log(cat instanceof Cat); // true
复制代码


优点:


  • 1、弥补了构造继承的缺陷,可以继承实例属性/方法,也可继承原型属性/方法

  • 2、既是子类的实例,也是父类的实例

  • 3、不存在引用属性共享问题

  • 4、可传参

  • 5、函数可复用缺点:

  • 1、调用了两次父类构造函数,生成了两份实例(子类实例将子类原型上的那份屏蔽了)

6、寄生组合继承

核心:通过寄生方式,砍掉父类的实例属性,这样,在调用两次父类的构造时,就不会初始化两次实例方法/属性,避免继承组合的缺点


function Cat(name) {  Animal.call(this);  this.name = name || 'Tom';}// 创建一个没有实例方法的类var Super = function () { };Super.prototype = Animal.prototype;//将实例作为子类的原型Cat.prototype = new Super();
// Test Codevar cat = new Cat();console.log(cat.name); // Tomcat.sleep() // Tom正在睡觉!console.log(cat instanceof Animal); // trueconsole.log(cat instanceof Cat); //true
复制代码


优点:


  • 1、堪称完美缺点:

  • 1、实现复杂

38、创建一个对象的方式有哪几种?

new Object 创建

const obj = new Object()obj.name = 'Sunshine_Lin'
复制代码

字面量创建

const obj = { name: 'Sunshin_Lin' }
复制代码

工厂模式创建

function createObj(name) {  const obj = new Object()  obj.name = name  return obj}const obj = createObj('Sunshine_Lin')
复制代码

构造函数创建

function Person(name) {  this.name = name}const person = new Person('Sunshine_Lin')
复制代码

39、this 指向的四种情况?

  • 1、new 操作符创建实例


function Person(name) {  this.name = name  console.log(this)}// this指向当前person实例对象const person = new Person('Sunshine_Lin')
复制代码


  • 2、指向 window


function fn() {  console.log(this)}fn() // 浏览器window,node里global
复制代码


  • 3、对象调用方法


const target = {  fn: function () { console.log(this) }}target.fn() // target
// 这种就是改变了this了const fn = target.fnfn() // 浏览器window,node里global
复制代码


  • 4、call、apply、bind 改变 this


const obj1 = {  name: '林三心',  sayName: function() {    console.log(this.name)  }}const obj2 = {  name: 'Sunshin_Lin'}// 改变sayName的this指向obj2obj1.sayName.call(obj2) // Sunshin_Lin// 改变sayName的this指向obj2obj1.sayName.apply(obj2) // Sunshin_Lin// 改变sayName的this指向obj2const fn = obj1.sayName.bind(obj2)fn() // Sunshin_Lin
复制代码

40、数组的常用方法有哪些?

41、Math 的常用方法有哪些?

42、哪些因素导致内存泄漏?如何解决?

请看我这篇文章哪是大神?只是用他人七夕约会时间,整理「JS避免内存泄漏」罢了

43、讲讲 JavaScript 的垃圾回收机制

看我这篇文章:赠你13张图,助你20分钟打败了「V8垃圾回收机制」

44、JS 中有哪些不同类型的弹出框?

在 JS 中有三种类型的弹出框可用,分别是:


  • Alert

  • Confirm

  • Prompt

45. 如何将 JS 日期转换为 ISO 标准

toISOString() 方法用于将 js 日期转换为 ISO 标准。 它使用 ISO 标准将 js Date 对象转换为字符串。如:


var date = new Date();var n = date.toISOString();console.log(n);// YYYY-MM-DDTHH:mm:ss.sssZ
复制代码

46、如何在 JS 中编码和解码 URL

encodeURI() 函数用于在 JS 中对 URL 进行编码。它将 url 字符串作为参数并返回编码的字符串。


注意: encodeURI()不会编码类似这样字符: / ? : @ & = + $ #,如果需要编码这些字符,请使用 encodeURIComponent()。 用法:


var uri = "my profile.php?name=sammer&occupation=pāntiNG";var encoded_uri = encodeURI(uri);
复制代码


decodeURI() 函数用于解码 js 中的 URL。它将编码的 url 字符串作为参数并返回已解码的字符串,用法:


var uri = "my profile.php?name=sammer&occupation=pāntiNG";var encoded_uri = encodeURI(uri);decodeURI(encoded_uri);
复制代码

47、什么是 BOM?有哪些 api?

BOM 就是browser object model浏览器对象模型


48、BOM 和 DOM 的关系

BOM 全称 Browser Object Model,即浏览器对象模型,主要处理浏览器窗口和框架。


DOM 全称 Document Object Model,即文档对象模型,是 HTML 和 XML 的应用程序接口(API),遵循 W3C 的标准,所有浏览器公共遵守的标准。


JS 是通过访问 BOM(Browser Object Model)对象来访问、控制、修改客户端(浏览器),由于 BOM 的 window 包含了 document,window 对象的属性和方法是直接可以使用而且被感知的,因此可以直接使用 window 对象的 document 属性,通过 document 属性就可以访问、检索、修改 XHTML 文档内容与结构。因为 document 对象又是 DOM 的根节点。


可以说,BOM 包含了 DOM(对象),浏览器提供出来给予访问的是 BOM 对象,从 BOM 对象再访问到 DOM 对象,从而 js 可以操作浏览器以及浏览器读取到的文档。

49、JS 中的 substr()和 substring()函数有什么区别

substr() 函数的形式为 substr(startIndex,length)。 它从 startIndex 返回子字符串并返回'length'个字符数。


var s = "hello";( s.substr(1,4) == "ello" ) // true
复制代码


substring() 函数的形式为 substring(startIndex,endIndex)。 它返回从 startIndex 到 endIndex - 1 的子字符串。


var s = "hello";( s.substring(1,4) == "ell" ) // true
复制代码

50、解释一下 "use strict" ?

“use strict”是 Es5 中引入的 js 指令。 使用“use strict”指令的目的是强制执行严格模式下的代码。 在严格模式下,咱们不能在不声明变量的情况下使用变量。 早期版本的 js 忽略了“use strict”。

结语

如果你觉得此文对你有一丁点帮助,点个赞,鼓励一下林三心哈哈。或者可以加入我的摸鱼群,我们一起好好学习啊啊啊啊啊啊啊,我会定时模拟面试,简历指导,答疑解惑,咱们互相学习共同进步!!


发布于: 刚刚
用户头像

Sunshine_Lin

关注

公众号:前端之神 2021.12.02 加入

全网粉丝2w,阅读播放超过100w,原创文章100+

评论

发布
暂无评论
工作中遇到的50个JavaScript的基础知识点