【明年找到好工作】JavaScript 基础篇

本文介绍了JavaScript中的箭头函数特性,包括它的this绑定规则和不能作为构造函数使用。讨论了JSON.stringify的局限性,如处理正则、函数和特殊值的方式。接着,解释了for...of和for...in循环的区别,以及在遍历对象和数组时的应用。此外,还涵盖了表单的enctype属性,以及执行上下文、作用域和作用域链的概念,强调了它们在JavaScript编程中的重要性。
摘要由CSDN通过智能技术生成

箭头函数和普通函数有什么区别

  • 箭头函数没有自己的 this
  • 箭头函数的 this 是继承于自己作用域的上一层 this
  • 箭头函数不能作为构造函数使用

JSON.stringify 有什么缺点

  • 如果 obj 里有 正则表达式的缩写Error 对象,则序列化的结果将只得到空对象
  • 如果 obj 里有 函数undefined,则序列化的结果将只得到undefined
  • 如果 obj 里有 NaNInfinity-Infinity,则序列化的结果将只得到null
  • 使用 JSON.parse(JSON.stringify(obj))深拷贝后,会丢弃对象的 constructor

for…in 和 for…of 的区别

  • for...of 遍历获取的是对象的键值;for...in 遍历获取的是对象的键名
  • for...of 只遍历当前对象不会遍历原型链 ;for...in 遍历对象的整个原型链
  • for...in循环主要是为了遍历对象而生,不适用遍历数组;
// 定义一个对象
var obj = {"name": "Clark", "surname": "Kent", "age": "36"};
// 使用 for of 循环遍历对象中的所有属性
for(var value in obj) {
    document.write(value + ", ");
}
  • for....of 循环可以用来遍历数组、类数组对象、字符串、Set、Map以及Generator对象
// 定义一个数组
var arr = ['a', 'b', 'c', 'd', 'e', 'f'];
// 使用 for of 循环遍历数组中的每个元素
for (var value of arr) {
    document.write(value + ", ");
}

form 的 enctype 编码方式

  • application/x-www-form-urlencoded:表单数据编码为键值对并用 & 进行分割(默认编码
  • multipart/form-data:表单数据编码为一条信息,每个表单控件对应信息的一部分
  • text/plain:表单数据以纯文本形式进行编码

application/x-www-form-urlencoded

  • 当 action 为 GET 时,表单数据编码为(account=value1&password=value2),然后将该字符串拼接 url,用 ?进行分割(http://localhost:3000/login?account=value1&password=value2)

  • 当 action 为 POST 时,浏览器会将 form 的数据封装到 http body 中,并发送到 server

multipart/form-data

  • 在表单控件中,如果存在 type=file 时,需要设置 enctype 为 multipart/form-data浏览器会把表单以控件为单位分割

application/x-www-form-urlencodedmultipart/form-data 对比:

  • application/x-www-form-urlencoded :向服务器发送大量的文本、包含非ASCII字符的文本或二进制数据时这种编码方式效率很低
  • 在文件上载时,所使用的编码类型应当是“multipart/form-data”,它既可以发送文本数据,也支持二进制数据上传

执行上下文

什么是执行上下文

指当前执行环境中的变量、函数声明、作用域链、this

执行上下文生命周期

1、创建阶段

生成变量对象、建立作用域链、确定 this 的指向

2、执行阶段

变量赋值、函数引用、执行其他代码

执行上下文特点

1)单线程,只在主线程上运行

2)同步执行,从上向下按顺序执行

3)全局上下文只有一个,也就是 window对象

4)函数每调用一次就会产生一个新的执行上下文环境


作用域

什么是作用域

可访问变量的集合

好处

隔离变量,不同作用域下同名变量不会有冲突

类型

1、全局作用域

2、函数作用域:是指声明在函数内部的变量,函数的作用域在函数定义的时候就决定了

3、块级作用域:

  • 块作用域由{ }包括,if和for语句里面的{ }也属于块作用域

  • 在块级作用域中,可通过let和const声明变量,该变量在指定块的作用域外无法被访问


var、let、const 区别

1)var定义的变量,没有块的概念,可以跨块访问, 可以变量提升

2)let定义的变量,只能在块作用域里访问,不能跨块访问,也不能跨函数访问,无变量提升,不可以重复声明

3)const用来定义常量,使用时必须初始化(即必须赋值),只能在块作用域里访问,而且不能修改,无变量提升,不可以重复声明


作用域链

当程序在查找变量的时候,首先会先从当前上下文的变量对象(作用域)中查找,如果没有找到,就会从父级的执行上下文的变量对象中查找,如果还没找到,一直找到全局上下文的变量对象,也就是全局对象。这样由多个执行上下文的变量对象构成的链表就叫做作用域链。


this 绑定方式

1、默认绑定(非严格模式下 this 指向全局对象,严格模式下函数内的 this 指向 undefined)

2、隐式绑定(当函数引用有上下文对象时,如obj.foo()的调用方式,foo内的 this 指向 obj

3、显示绑定(通过 call 或者 apply 方式直接指定 this 的绑定对象,如 foo.call(obj)

4、new 构造函数绑定,this 指向新生成的对象

5、箭头函数, this 指向的时定义函数时,外部环境中的 this,箭头函数的 this 在定义时就决定了,不能修改。


call apply bind 区别

1、三者都可以显示般的函数的 this 指向

2、三者第一个参数都是 this 要指向的对象,若该参数为 undefined 或 null, this 则默认指向全局 window

3、传参不同:apply 是数组、call 是参数列表、而 bind 可以分多次传入,实现参数的合并

4、call apply 是立即执行,bind 是返回绑定 this 之后的函数,如果这个新的函数作为构造函数被调用,那么 this 不再指向传入给 bind 的第一个参数,而是指向新生成的对象


闭包

什么是闭包

在函数中能够引用外部其他作用域(在该函数中)的变量

常见情况

1)函数作为返回值

2)函数作为参数传递

作用

1)可以让局部变量的值始终保存在内存中

2)对内部变量进行保护,使外部访问不到

缺点

1)不合理的使用闭包,会造成内存泄露(该内存空间使用完毕之后未被回收)

2)闭包中引用的变量直到闭包被销毁时才会被垃圾回收


原型/原型链

原型作用

为其他对象提供共享属性的对象,函数的实例可以共享原型上的属性和方法

原型链作用

它的作用就是当你在访问一个对象上属性的时候,如果该对象内部不存在这个属性,那么就会去它__proto__属性所指向的对象(原型对象)上查找。如果原型对象依旧不存在这个属性,那么就会去其原型的__proto__属性所指向的原型对象上去查找。以此类推,直到找到nul,而这个查找的线路,也就构成了我们常说的原型链

原型链和作用域链的区别:原型链是查找对象上的属性,作用域链是查找当前上下文中的变量


proto、prototype、constructor 属性

1)js 中对象分为两种,普通对象和函数对象

2)protoconstructor 属性是对象独有的。

3)而 prototype属性 是函数所独有的。它作用是包含可以给特定类型的所有实例提供共享的属性和方法。

4)在js中,万事万物皆对象,所以函数也有 protoprototype 属性

5)proto属性是来连接对象直到null的一条链即为原型链

6)constructor属性含义是指向该对象的构造函数,最终的构造函数都指向Funtion

https://www.jianshu.com/p/173f651ccf45


instanceof

instanceof 的基本用法,它可以判断一个对象的原型链上是否包含该构造函数的原型,经常用来判断对象是否为该构造函数的实例

console.log(Object instanceof Object); //true
console.log(Function instanceof Function); //true
console.log(Function instanceof Object); //true
console.log(function() {} instanceof Function); //true

instanceof 与 typeof 区别

1、typeof一般被用于来判断一个变量的类型

特殊情况:typeof null === 'object'

2、instanceof判断一个对象的原型链上是否包含该构造函数的原型


new 关键字

new 对象,到底发生什么?

1)创建一个对象,该对象的原型指向该构造函数

2)构造函数的 this 会指向该对象


深拷贝

1) JSON.parse(JSON.stringify())

缺点: 无法拷贝 函数、正则、时间格式、原型上的属性和方法等

2)递归实现深拷贝

/**
 * 数据拷贝
 * @param {Array | Object} obj 待拷贝的数据 
 * @returns 
 */
const copyData = (obj = {}) => {
    let newObj = null
    if (typeof (obj) === 'object' && obj !== null) {
        newObj = obj instanceof Array ? [] : {}
        // 进入下一层进行递归
        for (let i in obj) newObj[i] = copyData(obj[i])
    } else {
        newObj = obj
    }
    return newObj
}

事件轮询机制

JS 语言最大的特点就是 单线程,即同一个时间只能做一件事。所有任务都需要排队。前一个任务结束,才能执行后一个任务。

这由此就会导致:如果正在执行的任务出现执行时间过长,则后一个任务得一直等着,导致后续任务无法执行。

为了解决这个问题:JS 将所有任务分成两种:**** 和 微任务

  • 宏任务:在主线程上排队执行的任务

  • 微任务:不进入主线程,而是进入“微任务列表”

什么是宏任务:

  • script全部代码(注意同步代码也属于宏任务)、setTimeout、setInterval、setImmediate等

什么是微任务:

  • Promise、MutationObserver

事件轮询机制执行过程:

1)代码执行过程中,宏任务和微任务放在不同的任务队列中

2)当某个宏任务执行完后,会查看微任务队列是否有任务。如果有,执行微任务队列中的所有微任务(注意这里是执行所有的微任务)

3)微任务执行完成后,会读取宏任务队列中排在最前的第一个宏任务(注意宏任务是一个个取),执行该宏任务,如果执行过程中,遇到微任务,依次加入微任务队列

4)宏任务执行完成后,再次读取微任务队列里的任务,依次类推。

Promise.resolve()
  .then(function() {
    console.log("promise0");
  }).then(function() {
    console.log("promise5");
  });


setTimeout(() => {
  console.log("timer1");
  Promise.resolve().then(function() {
    console.log("promise2");
  });
  Promise.resolve().then(function() {
    console.log("promise4");
  });
}, 0);

setTimeout(() => {
  console.log("timer2");
  Promise.resolve().then(function() {
    console.log("promise3");
  });
}, 0);

Promise.resolve().then(function() {
  console.log("promise1");
});

console.log("start");

// start promise0 promise5 promise1 timer1 promise2 promise4 timer2 promise3

事件轮询机制 与 浏览器更新渲染时机

1) 浏览器更新渲染会在event loop中的 宏任务 和 微任务 完成后进行,即宏任务 → 微任务 → 渲染更新(先宏任务 再微任务,然后再渲染更新)

2)宏任务队列中,如果有大量任务等待执行时,将dom的变动作为微任务,能更快的将变化呈现给用户,这样就可以在这一次的事件轮询中更新dom


定时器不准的原因

setTimeout/setInterval是宏任务,根据事件轮询机制,其他任务会阻塞或延迟js任务的执行

考虑极端情况,假如定时器里面的代码需要进行大量的计算,或者是DOM操作,代码执行时间超过定时器的时间,会出现定时器不准的情况


setTimeout/setInterval 动画卡顿

不同设备的屏幕刷新频率可能不同, setTimeout/setInterval只能设置固定的时间间隔,这个时间和屏幕刷新间隔可能不同

setTimeout/setInterval通过设置一个间隔时间,来不断改变图像实现动画效果,在不同设备上可能会出现卡顿、抖动等现象


requestAnimationFrame

requestAnimationFrame 是浏览器专门为动画提供的API

requestAnimationFrame刷新频率与显示器的刷新频率保持一致,使用该api可以避免使用setTimeout/setInterval造成动画卡顿的情况

requestAnimationFrame:告诉浏览器在下次重绘之前执行传入的回调函数(通常是操纵dom,更新动画的函数)


setTimeout、setInterval、requestAnimationFrame 三者的区别

1)引擎层面

  • setTimeout,setInterval 属于 JS引擎 ,存在事件轮询
  • requestAnimationFrame 属于 GUI引擎
  • JS引擎与GUI引擎是互斥的,也就是说 GUI引擎在渲染时会阻塞JS引擎的计算

这样设计的原因,如果在GUI渲染的时候,JS同时又改变了dom,那么就会造成页面渲染不同步

2)性能层面

  • 当页面被隐藏或最小化时,setTimeout,setInterval 仍会在后台执行动画任务
  • 页面处于未激活的状态下,该页面的屏幕刷新任务会被系统暂停,requestAnimationFrame也会停止
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

海面有风

您的鼓励将是我前进的动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值