黑马程序员和尚硅谷前端Javascript学习笔记

根据2024尚硅谷的最新Web前端学习路线2024年黑马程序员前端学习路线进行的学习笔记整理之javascript篇
(持续更新中)


本人先是看的尚硅谷的前端js课程,把基础看完之后发现尚硅谷的js基础比较侧重于不同浏览器版本之间的兼容,用的很多方法都是比较老的,后面就转跟黑马程序员的前端系列课程。
后黑马程序员课程相关的源码在Gitee博主@ClearStari99 这里可以查看:https://gitee.com/ClearStari99/front-end-BV1Y84y1L7Nn
其他前端相关学习笔记可以在Gitee博主@努力学习的汪 这里查看: https://gitee.com/hongjilin/hongs-study-notes

文章目录


前端开发环境搭建

为了方便在本地搭建前端项目,笔者通过VSCode进行前端代 码的编写,参考教程如下:VScode前端环境搭建:https://blog.csdn.net/m0_75262940/article/details/141105423

浏览器中的 JavaScript 的组成部分

在这里插入图片描述

js常见指令

数学内置函数

名称描述
Math.ceil()向上取整
Math.floor()向下取整,与parseInt()相似,但后者是可以进行字符串转整数的。
Math.round()四舍五入
Math.random()生成 [0,1) 之间的随机数
Math.pow()幂运算

数组arr元素的增删及其他基本操作

名称描述
arr.push(新增数据)将一个或多个元素添加到数组的末尾,并返回该数组的新长度(⭐⭐⭐)
arr.unshift(新增数据)将一个或多个元素添加到数组的开头,并返回该数组的新长度
arr.pop()将数组的最后一个元素弹出(也就是删除),并返回该元素的值
arr.shift()将数组的第一个元素删除,并返回该元素的值
arr.splice(操作的下标(起始位置), 删除的个数)适合用于删除数组中间的元素

js数据类型

undefined, null, boolean, string, symbol, number and object

  • 基本(值)类型:
    • string:任意字符串
    • number:任意数字
    • boolean: true/false
    • undefined: underfined
    • null: null
  • 对象(引用)类型:
    • Object:任意对象
    • Function:一种特别的对象(可以执行)
    • Array:一种特别的对象(数值下标,内部数据是有序的)

需要注意的是:

  • js中的变量都是保存在栈内存中的,基本数据类型的数值直接在栈内存中存储,值之间是独立存在的;
  • 对象是保存到堆内存中的,每创建一个新的对象,就会在堆内存中开辟出一个新的空间,而变量保存的是对象的内存地址(对象的引用),如果两个变量保存的是同一个对象的引用(即同一个地址)时当一个通过一个变量修改属性时,另一个也会受到影响。
  • 什么是对象字面量?
    在这里插入图片描述

类型判断方法

  • 基本类型:
    • typeof:直接判断并的得出类型
      • 能判断:undefined / number / string / boolean / function
      • 不能判断:null / object (都是同一类型) object / array
    • instanceof:判断对象的具体类型
      • a instanceof object:a(实例对象)是不是object这个构造函数的实例
      • a instanceof array:a(实例对象)是不是array这个数组对象的实例
    • ===:强制等于,可以判断undefined和null(只有一个值)
  • 对象类型:用instanceof来判断

js声明变量的3种方式

var, let, const

  • var:可以在整个程序中使用;若在函数中变量没有用var来声明的话,该变量将自动变为全局变量=>因此,一般函数内都要先声明变量,使其为具有局部作用域的变量。(因为比较老现在开发中尽量避免用var)
  • let:只会在声明的范围内使用,并不会将当前值绑定到全局对象中(如:let a = 100; console.log(window.a)就不一定是100)
  • const:是个永远不会改变的变量
var myNumber = 5
let ourNumber = "123"
const pi = 3.14

(1)以后声明变量我们优先使用哪个?

  • const
  • 有了变量先给const,如果发现它后面是要被修改的,再改用let

(2)为什么const声明的对象可以修改里面的属性?

  • 因为对象是引用类型,里面存储的是地址,只要地址不变,就不会报错
  • 建议数组和对象使用const来声明

(3)什么时候使用let声明变量?

  • 基本数据类型的值或引用数据类型的地址发生变化时
  • 比如 一个变量进行加减运算,eg. for循环中的i++

适用赋值运算符存储数值:
声明变量和分配变量是有区别的

js对变量大小写是敏感的

js中加分号";"可以更好区分是否换行,但不加也没关系

转义字符 \

CODEOUTPUT
单引号
‘’双引号
\反斜杠
\n换行符
\r回车
\t制表符
\b退格
\f换页

函数

函数的属性和方法

函数是一段可重复使用的代码块,用于执行特定的任务。它可以接受输入参数(也可以没有参数),并返回一个值(也可以不返回值)。
函数就像是一个工具,通过调用它来执行特定的逻辑操作,这有助于提高代码的复用性和可维护性。

函数有命名函数(Named Functions)、匿名函数(Anonymous Functions)、箭头函数(Arrow Functions)、立即执行函数表达式(IIFE - Immediately - Invoked Function Expressions)、构造函数(Constructor Functions)和事件驱动中的回调函数(Callback Function)等。

其中匿名函数通常作为其他函数的参数(如回调函数)或者立即执行函数表达式(IIFE)。例如,作为回调函数用于数组的forEach方法

立即执行函数(只会执行一次)

在这里插入图片描述
在这里插入图片描述

面试常考题:用工厂方法创建对象(批量创建对象)

在这里插入图片描述
局限性:使用工厂方法创建的对象,使用的构造函数都是Object,所以创建的对象都是Object这个类型,会导致我们无法区分出多种不同类型的对象。

构造函数(封装 多态)

比如:var per = new Person();
在这里插入图片描述
在这里插入图片描述
此时,this指的就是新建的对象per,最终会作为返回值赋值给per
改进之后,可调用创建更多不同属性的对象:
在这里插入图片描述
跟工厂方法类似,但使用同一个构造函数创建的对象,成为一类对象,比如Person类和Dog类
在这里插入图片描述
其中,对象 instanceof 构造函数可以用于检查一个对象是否是一个类的实例(eg. per instanceof Person也就是判断人属不属于人的类型)。
使用同一个构造函数创建的对象,我们称为一类对象,也将一个构造函数称为一个类。我们将通过一个构造函数创建的对象,称为是该类的实例

箭头函数

ES6中提供的一种更简洁的函数定义方式,并且它的this绑定与普通函数不同,是由其定义时所在的上下文决定的,而不是像普通函数那样在调用时确定。

这使得它在处理事件处理函数和回调函数等场景中,能够避免this指向混乱的问题。

例如传统的函数定义:

function add(x, y) {
  return x + y;
}

用箭头函数可以写成:

function add = (x, y) => x + y;

回调函数

在这里插入图片描述

面试常考题:call()、apply() 和 bind()

函数对象的方法call()、apply() 和 bind()是每个 JavaScript 函数都具有的 3 个基本方法

(1) call() 函数:能改变函数内部this指向问题的函数

  • 基本用法
    var person = {
    	fullName: function(){
    		return this.firstName + " " + this.lastName;
    	}
    }
    var person1 = {
    	firstName:"Bill",
    	lastName:"Gates",
    }
    var person2 = {
    	firstName:"Steve",
    	lastName:"Jobs",
    }
    person.fullName.call(person1);  // 将返回"Bill Gates" ,直接传递函数的实参来改变this指针原本指向的值
    
  • 实现原理: 面试手撕代码题
    实现call函数需要将其绑定到function的原型上的,结合上面代码实现call函数功能,如mycall函数所示。
    Function.prototype.mycall = function(person_n){
    	person_n.fullName = this;
    	person_n.fullName();
    }
    
    console.log(person.fullName.call(person2))  // 将输出"Steve Jobs"
    

上面只是一个简单的实现方法,但不能够返回null的数据,想进一步了解可以参照这个大佬的视频:面试题 - 手撕JavaScript call apply bind 函数

(2)apply()函数:

  • call和apply这两个方法都是函数对象的方法需要通过函数对象来调用
  • 通过两个方法可以直接调用函数,并且可以通过第一个实参来指定函数中this
  • 不同的是call是直接传递函数的实参而apply需要将实参封装到一个数组中传递

(3)bind()

  • bind方法和call很相似,第一参数也是this的指向,后面传入的也是一个参数列表(但是这个参数列表可以分多次传入)
  • 改变this指向后不会立即执行,而是返回一个永久改变this指向的函数

具体解释和实现bind函数参照:面试官:bind、call、apply 区别?如何实现一个bind?

面试常考题:this和arguments是什么?有什么区别?

调用函数时隐含的属性有两个:this 和arguments
在这里插入图片描述

  • this(调用函数的那个环境对象)
    this是函数的上下文对象,根据函数的调用方式不同会执向不同的对象(文章后面Dom环境对象中也有提到)。

    • 以函数的形式调用时,this是window
    • 以方法的形式调用时,this是调用方法的对象
    • 以构造函数的形式调用时,this是新建的那个对象
    • 使用call和apply调用时,this是指定的那个对象
    • 在全局作用域中this代表window
  • arguments(封装实参的对象)

    • arguments和this类似,都是函数中的隐含的参数
    • arguments是一个类数组元素,它用来封装函数执行过程中的实参
    • 所以即使不定义形参,也可以通过arguments来使用实参
    • arguments中有一个属性callee表示当前执行的函数对象

Web APIs

在这里插入图片描述
Web APIs包括:

  • DOM(Document Object Model)文档对象模型

  • BOM(Browser Object Model)浏览器对象模型

Dom

Dom是什么?有什么作用?

  • Dom是文档对象模型
  • 可以操作网页内容,可以开发网页内容特效和实现用户交互
获取Dom元素的方法

window 对象的属性是代表的全局顶级对象,而D0M Manipulation按操作分为以下几种方式(使用不同的方法我们在dom树中选择一个元素):

  • GetElementById()
  • GetElementByClassName()
  • getElementsByTagName()

按类名标签名分为:因为强大的CSS选择器,此两个更容易用到

  • querySelector(‘css选择器’) :参数包含一个或多个有效的css选择器字符串,比如document.querySelector('div')可以用来抓取div标签或者获取该类名称。会选择第一个与选择器匹配的项,并返回该HTMLElement对象。如果没有匹配到,则返回null。
  • querySelectorAll(‘css选择器’):参数包含一个或多个有效的css选择器字符串,比如document.querySelectorAll('ul li')。会选择所有匹配项,并返回一个NodeList对象集合。
伪数组

通过以上querySelectorAll方法获取到的就是伪数组,只有一个元素也是伪数组。
伪数组
形如下:
伪数组

操作元素内容
  • 对象.innerText 属性:
    • 将文本内容添加/更新到任意标签位置
    • 显示纯文本,不解析html标签
  • 对象.innerHTML 属性:
    • 将文本内容添加/更新到任意标签位置
    • 显示纯文本,解析html标签
操作元素样式属性
  1. 通过style属性操作CSS:对象.style.样式属性 = '值'
    赋值时,如果需要,不要忘记加css单位(如 ‘500px’)
    需要注意:此方法生成的是行内样式表,优先级比较高。在这里插入图片描述

  2. 通过类名(className)操作CSS:元素.className= 'active'当修改的样式较多时可以用这个方法。因为class是关键字,所以这里用className代替。
    在这里插入图片描述
    此方法会覆盖前面的类名。如果想要两种样式都有,可以把两个类名都加上,像这样:

    <div class = “nav”>
    	<script>
    		const div = document.querySelector('div')
            div.className = 'nav box'
    	</script>
    </div>
    
  3. 通过classList操作类控制CSS:为解决className操作会覆盖前面类名的问题,可以通过classList追加和删除类名,这也是最常用的方法:
    元素.classList.add('类名') // 追加一个类
    元素.classList.remove('类名') // 删除一个类
    元素.classList.toggle('类名') // 切换一个类,此方法常用

    <!DOCTYPE html>
    <html>
        <head>
            <meta charset="UTF-8">
            <title>Document</title>
            <style type="text/css">
                div{
                    width: 200px;
                    height: 200px;
                    background-color: pink;
                }
                .box{
                    width: 300px;
                    height: 300px;
                    background-color: skyblue;
                    margin: 100px auto;
                    padding: 10px;
                    border: 1px solid #000;
                }
                .active{
                    color: red;
                    background-color: pink;
                }
            </style>
        </head>
        <body>
            <div class="box">文字</div>
            <script>
                // 通过classList修改样式
                // 获取元素
                const box = document.querySelector('.box')
                // 追加类 add() 类名不加点,而且是字符串
                box.classList.add('active')
                // // 删除类 remove()
                box.classList.remove('box')
                // 切换类 toggle() 有就加上,没有就删除
                box.classList.toggle('active')
            </script>
        </body>
    </html>
    

操作样式属性小结:
在这里插入图片描述

操作元素表单属性
  1. 获取:DOM对象.属性名

  2. 设置:DOM对象.属性名 = 新值
    表单.value = '用户名'
    表单.type = 'password'

  3. 自定义属性:
    以"data-"开头的都是自定义属性
    在这里插入图片描述
    自定义属性案例:

  • 定时器-间歇函数:
    • 定时器有什么用?
      可以根据时间自动重复执行某些代码

    • 开启定时器:setInterval(函数名, 间隔时间) ,每间隔一段时间调用这个函数,间隔时间单位是毫秒。同时,其返回的是一个id数字。

      setInterval(function(){
      	console.log('一秒钟执行一次')
      }, 1000)
      

      或者

      function fn(){
      	console.log('一秒钟执行一次')
      }
      setInterval(fn, 1000) // setInterval(函数名, 间隔时间),函数名后面不跟括号,让定时器函数自己调用该函数。
      
    • 关闭定时器:clearInterval(变量名),其中变量名为定时器的id号。

事件介绍
事件监听(绑定)

在这里插入图片描述

  • 语法:元素对象.addEventListener('事件类型',要执行的函数)
  • 事件监听三要素:
    1. 事件源:那个dom元素被事件触发了,要获取dom元素
    2. 事件类型:用什么方式出发,比如鼠标单击clik、鼠标经过mouseover、文本框输入内容等
    3. 事件调用的函数(事件处理程序):要做什么事

比如点击按钮触发弹窗事件:

const btn = document.querySelector('button')
btn.addEventListner('click', function(){
	alert('你好呀!')
})
  • 事件监听的版本扩展:
    事件监听发展史:
    在这里插入图片描述

    • DOM L0
      事件源.on事件 = function(){}
     <button id="btn">按钮</button>  
     <script>  
           var btn = document.getElementById("btn");  
           btn.onclick = function(){
       	
       		};  
     </script>  
    
    • DOM L1
      事件源.addEventListener(事件, 事件处理函数)

    区别:on方式会被覆盖,addEventListener方式可以绑定多次,拥有更多特性,推荐使用。

事件类型

在这里插入图片描述

此处案例参考黑马程序员js课程>>>Apis-day2-95-99轮播图完整版鼠标定时器切换、小米搜索框焦点事件、发布评论键盘事件等。

事件对象event
  • 语法:如何获取
    • 在事件绑定的回调函数的第一个参数就是事件对象

    • 一般命名为event、ev、e,比如元素.addEventListener('click', function(e){})

    • 常见事件对象属性:

      名称描述
      type获取当前的事件类型
      clientX/clientY获取光标相对于浏览器可见窗口左上角的位置
      offsetX/offsetY获取光标相对于当前DOM元素左上角的位置
      key用户按下的键盘值,现在不提倡用keyCode(keyCode已废弃)

此处案例参考黑马程序员js课程>>>Apis-day2-100-101事件对象event、按下回车发布评论。

环境对象
  • 什么是this?
    • 它代表当前函数运行时所处的环境,this就是这个对象,这个对象受当前环境影响。每个函数中都有this(环境对象),而this指向这个函数的调用者。谁调用,this就指向谁
  • 非严格条件下:
    • 普通函数this指向的是window;
    • 事件监听函数this指向的是调用者;
    • 箭头函数没有this。
    • 通过call、apply和bind方法this也可以改变指向。
回调函数

(上面函数部分已有提及)

事件流
  • 事件流与两个阶段说明

    • 事件流:事件完整执行过程中的流动路径
    • 两个阶段:捕获阶段–>冒泡阶段

    简单来说:捕获阶段是从父到子,冒泡阶段是从子到父
    实际工作都是使用事件冒泡为主

  • 事件捕获
    在这里插入图片描述

  • 事件冒泡
    在这里插入图片描述

  • 阻止冒泡

    阻止冒泡流动传播一定是事件对象e.stopPropagation()

    • 扩展了解:阻止默认行为(不是阻止冒泡)
      • 我们在某些情况下需要阻止默认行为的发生,比如阻止链接的跳转,表单域跳转
      • 语法:e.preventDefault()
      • 小结:
  • 解绑事件

    • on事件方式

    • addEventListener方式

事件委托
  • 学习目标:能够说出事件委托的好处
  • 定义:事件委托是利用事件流的特征解决一些开发需求的一种知识技巧,一件需要做很多次的事情,可以委托给别人来一次性完成。
  • 优点:减少注册次数,提高程序性能。
  • 原理:事件委托其实是利用事件冒泡的特点。
    • 给父元素注册事件,当我们触发子元素的时候,会冒泡到父元素身上,从而触发父元素的事件
其他事件
页面加载事件
  • load事件
    监听整个页面资源给window
  • DOMContentLoaded事件
    针对页面初始框架的加载,无需等待样式表、图像等完全加载:
    无需等待样式表和图像完全加载,更快,给document
元素滚动事件

获取滚动位置:

页面尺寸事件

获取元素宽高:

  • 元素的尺寸与位置
    在这里插入图片描述
  1. 获取宽高:offsetWidth和offsetHeight
  • 得到元素宽高 = 内容 + padding + border
  1. 获取位置:
  • offsetLeft和offsetTop 注意是只读属性
    • 得到位置以 带有定位的父级 为准
      • 对于html元素默认有定位,但修改样式定位 position: relative可以给该元素加相对定位,此时该元素就不带定位了。
    • 若没有父级,则以 文档左上角 为准
  • element.getBoundingClientRect()
    • 相对与网页可视区域而言的,不是整个网页。
      在这里插入图片描述
      小结:
      在这里插入图片描述
日期对象
  • 实例化 new
    • 获取当前时间:const date = bew Date()
    • 获取指定时间:const date = bew Date('2024-12-4 08:30:00')
  • 日期对象方法
    方法–>是在对象里面,eg. 日期对象.getFullYear()
    // 获取日期对象(实例化对象)
    const date = new Date()
    // 使用里面的方法
    console.log(date.getFullYear())
    console.log(date.getMonth() + 1)  // 获取月份(0~11)需要+1
    

在这里插入图片描述

  • 时间戳(毫秒数,唯一)

    • 什么是时间戳:从1970年到当前时刻的毫秒数
      在这里插入图片描述

    • 获取时间戳的方法:

      • date.getTime()
      • 简写+new Date() (记这个)
      • 使用Date.now():只能得到当前时间戳,而前面两种都可以返回指定时间的时间戳 eg. console.log(+new Date(‘2024-12-5 18:30:00’))
DOM节点操作
查找DOM节点
  • 父节点 子元素名称.parentNode属性(不加括号)
  • 子节点父元素名称.children属性
  • 兄弟节点
    • 上一个兄弟:newxtElementSibling属性
    • 下一个兄弟:previousElementSibling属性
增加DOM节点
  • 创建新节点:document.createElement('标签名称')
  • 追加节点:
    • 插入到父元素的最后一个子元素:父元素.appendChild(作为子元素要插入的元素)
    • 插入到父元素重某个子元素前面:父元素.insertBefore(要插入的子元素child, 在哪个子元素前面refchild)
    • 将child元素添加到refChild的前面去
    • 如果refChild元素获取不到,会默认以appendChild为准
    • 追加的节点可以是新创建的,也可以是页面上已经存在的(eg. 移动)
克隆和删除DOM节点
  • 克隆节点: 元素.cloneNode(true)
    • 克隆之后还要追加,如:
      • 深克隆:元素.cloneNode(true)
      • 浅克隆:元素.cloneNode(false) 只克隆标签,没啥用
  • 删除节点:parent.removeChild(child)

    注意:删除和隐藏节点(display:none)是有区别的,隐藏节点是存在的,但是删除,则是从html重删除节点。
    补充:显示节点(display: block)
M端事件(了解)

只在移动端有的触摸效果
在这里插入图片描述

  • touch相关事件
    • touchstart
    • touchmove
    • touchend
swiper插件的使用

M端中常用的插件
在这里插入图片描述

BOM

window对象

(目标:学习window对象的常见属性,知道各个BOM对象的功能和含义)

BOM(Browser Object Model, 浏览器对象模型)

在这里插入图片描述

定时器-延时/延迟函数setTimeout
  • 语法:setTimeout(回调函数, 等待的毫秒数 ) 只执行一次
  • 清除延时函数:clearTimeout(timer)
  • 两种定时器的区别:
    • setTimeout(): 延时函数 执行一次
    • setInterval(): 间隔函数 每隔一段时间执行一次,除非手动清除
js执行机制

js本身是单线程的,但浏览器可以多线程。为了解决js单线程这个问题,利用多核CPU的计算能力,HTML5提出了Web Worker标准,允许JavaScript脚本创建多个线程,则js中出现了同步和异步。
同步任务是主线上的(放在执行栈上),异步任务是耗时的(放在任务队列中)。代码执行时,先在执行栈上操作,再到任务队列中。

事件循环event loop(面试高频)

由于主线程不断的重复获得任务、执行任务、再获取任务、再执行,所以这种机制被称为事件循环(event loop)
在这里插入图片描述

location对象、navigator对象和histroy对象
  • location对象:获取浏览器的信息

    • location.herf:指定具体网址,可以实现跳转页面
    • location.search:得到问号’?'后面的部分
    • location.hash:获取地址中的哈希值,符号’#'后面的部分

      此时页面内跳转不需要切换,比如顶部导航栏各个菜单栏的切换
  • navigator对象:实现首页自动跳转到移动端页面(直接找代码复制就行)

  • histroy对象:实现浏览器的后退和前进功能,但在实际开发中很少用到
    在这里插入图片描述

本地存储localStorage(重点)

放在浏览器中的小仓库,防止页面刷新不丢失数据。一旦存储就不会消失,除非手动删除。
在这里插入图片描述

  • 本地存储分类localStorage
    注意:里面所有的key都需要加引号

    • 存储数据:localStorage.setItem('key', 'value')
      只能存储字符串数据类型(后期需要注意数据类型转换),在浏览器控制台中的application可以查看
    • 读取数据:localStorage.getItem('key')
    • 删除数据:localStorage.removeItem('key')
      本地存储一直存在,需要手动删除
  • 本地存储处理复杂数据类型(存储对象)

    • 取值步骤:
      • (1) 存:将复杂数据类型转换成JSON字符串存储到本地
        • 语法:JSON.stringify(复杂数据类型)
      • (2)取:将字符串转换为对象来读取
        • 语法:JSON.parse(JSON数据类型)
      const obj = {
      	uname: 'pink老师',
      	age: 18,
      	gender: '女'
      }
      // (1)将对象obj当字符串的形式传入进去
      localStorage.setItem('obj', JSON.stringify(obj))  // 得到的是字符串无法直接使用
      // (2)将JSON字符串转换为对象 `取出`的时候使用
      const str = localStorage.getItem('obj')
      console.log(JSON.parse(str))
      
      JSON对象 属性和值都有引号,而且是双引号:
      {
      	"uname": "pink老师",
      	 "age": 18,
      	 "gender": "女"
      }
      // 取值 查看数据类型
      console.log(typeof localStorage.getItem('obj'))
      // 输出为string
      

字符串拼接:数组map和join方法

map方法

遍历数组处理数据,并返回新的数组
在这里插入图片描述

jion方法

把数组中的所有元素转换成一个字符串,并可以用一个字符隔开,比如:mytext.innerHTML = data.join('<br>') 此处将data数组中的所有元素用
换行符隔开了,并且显示在了mytext这个对象的html页面中。

数组中map+join方法渲染页面思路:

在这里插入图片描述

正则表达式

js进阶

作用域、闭包、预解析、解构、箭头函数、构造函数、原型、原型链

高阶技巧:深浅拷贝、异常处理、this、性能优化(防抖、节流)

作用域(scope)和作用域链

目标:了解作用域对程序执行的影响及作用域链的查找机制,使用闭包函数创建隔离作用域避免全局变量污染。
作用域就是一个范围,作用域规定了变量能够被访问的“范围”

  • 局部作用域:

    • 函数作用域:在函数内部声明的变量只能在函数内部被访问,外部无法直接访问。函数执行完毕后,内部变量实际会被清空。
    • 块作用域:被{}包裹的代码称为代码块,代码块内部的变量将有可能无法被访问。
  • 全局作用域:尽可能避免使用

作用域链

作用域链本质上是底层的变量查找机制

  • 在函数被执行时,会优先查找当前函数作用域中查找变量
  • 如果当前作用域查找不到则会依次逐级查找父级作用域直到全局作用域

JS垃圾回收机制(Garbage Collection, GC)及算法

JS垃圾回收机制(GC)

JS中内存的分配和回收都是自动完成的,内存在不使用的时候会被垃圾回收器自动回收

内存的生命周期:

  • 内存分配
  • 内存使用
  • 内存回收

一般情况下,全局变量不会回收,局部变量会自动回收。

内存泄漏:程序中分配的内存由于某种原因程序未释放无法释放叫做内存泄漏

垃圾回收机制算法

在这里插入图片描述
栈:存放基本数据类型
堆:存放复杂数据类型,垃圾回收机制主要回收复杂数据类型。

常见垃圾回收机制算法:

  • 引用计数法:

    • 定义:看对象是否有指向它的引用,没有引用了就回收对象
    • 缺点:但当嵌套引用也就是循环引用时,两个对象相互引用,尽管不再使用该引用,但垃圾回收器也不会进行回收,容易导致内存泄漏。
      在这里插入图片描述

    因此,此方法现在基本不用了。

  • 标记清除法
    在这里插入图片描述
    在这里插入图片描述
    核心思路是从根部扫描对象,能查找到的就是使用的,查找不到的就是要回收的。

JS闭包(Closure)(面试高频考点)

  • 概念:一个函数对周围状态的引用捆绑在一起,内层函数中访问到其外层函数的作用域

  • 简单理解:闭包 = 内层函数 + 外层函数的变量

  • 闭包的作用:

    • 封闭数据,提供操作,外部也可以访问函数内部的变量
    • 允许将函数与其所操作的某些数据(环境)关联起来
  • 闭包的基本格式:

    function outer(){
    	let a = 1
    	function fn(){
    		console.log(a)
    	}
    	return fn
    }
    const fun = outer()
    fun()
    // 外部fun函数使用了outer函数内部的变量`a`
    

    简约写法为:

    function outer(){
    	let a = 1
    	return function(){
    		console.log(a)
    	}
    }
    const fun = outer()
    fun()
    
  • 闭包的应用:实现数据的私有,不容易被篡改
    比如,做一个统计函数调用次数的功能
    在这里插入图片描述

但右边这种闭包形式实现数据私有的方法,会存在内存泄漏(应该被回收但没有被回收)的问题,因为作为全局变量的result始终会用到i,一直不会被释放

  • 闭包可能引起的问题:内存泄漏

变量提升(面试考点)

什么叫变量提升:在代码执行之前,会先去检测当前作用域下所有var声明的变量,并提到当前作用域的最前面只提升声明,不提升赋值
因此会造成很多意想不到的bug,因此ES6引入了块级作用域,用let或者const声明变量,让代码写法更加规范和人性化。

函数进阶

函数提升

函数参数

动态参数arguments

只存在于函数中的一个伪数组
在这里插入图片描述

  • 当不确定传递多少个实参的时候,我们怎么办?
    • 用arguments动态参数
  • arguments是什么?
    • 只存在函数中的伪数组
剩余参数 ...
  • 在实参数量不确定时使用,用于获取多余的实参
  • 借助 …获取的剩余实参,是个真数组
    在这里插入图片描述
    注意:写的时候用...other,使用时只需要写other
展开运算符(...)

与剩余参数非常相似,展开运算符是将一个数组进行展开
在这里插入图片描述
写在函数中的是剩余参数,写在外面的是展开运算符

  • 剩余参数:函数参数使用,得到真数组
  • 展开运算符:数组中使用,数组展开

箭头函数

基本语法

ES6中提供的一种更简洁的函数定义方式,并且它的this绑定与普通函数不同,是由其定义时所在的上下文决定的,而不是像普通函数那样在调用时确定。

这使得它在处理事件处理函数和回调函数等场景中,能够避免this指向混乱的问题。

例如传统的函数定义:

function add(x, y) {
  return x + y;
}

用箭头函数可以写成:

function add = (x, y) => x + y;
箭头函数参数
  1. 普通函数有arguments动态参数
  2. 箭头函数没有arguments动态参数,但有剩余参数 …args
箭头函数this

箭头函数没有自己的this,也不会创建自己的this,只会从自己的作用域链的上一层沿用this

DOM事件回调函数不建议使用箭头函数

遍历数组 forEach 方法(重点)

加强版for循环,只遍历,不返回值
语法:

被遍历的数组.forEach(function(当前数组元素, 当前元素索引号){
	// 函数体
})
筛选数组 filter方法(重点)

筛选数组,返回符合条件的数据。
比如,返回数组中大于等于20的数据:
在这里插入图片描述
与map相似,但map不能判断,可以运算。

以上代码可以简化如下:

const newArr = arr.filter(item => item >= 20)
console.log(newArr)

构造函数

创建对象的三种方式
  1. 利用对象字面量创建对象
const o = {
	name: '佩奇'
}
  1. 利用new Object 创建对象
const o = new Object({ name: '佩奇' })
  1. 利用构造函数创建对象
什么是构造函数
  • 是一种特殊的函数,主要用于初始化对象,可以用来快速创建多个类似的对象,不需要return但会自动返回创建的新对象。
  • 约定:
    • 命名以大写字母开头
    • 使用构造函数必须加new,比如:
      // 创建构造函数
      function Pig(name, age, gender){
      	this.name = name
      	this.age = age
      	this.gender = gender
      }
      // new 关键字调用函数
      // new Pig('') 接受创建的对象
      const Peppa = new Pig('佩奇', 6, '女')
      const George = new Pig('乔治', 3, '男')
      const Mum = new Pig('猪妈妈', 30, '女')
      const Dad = new Pig('猪爸爸', 35, '男')
      
  • 缺点:在处理复杂数据类型(比如函数)时不同对象会在堆中声明不同的数据,导致浪费内存 => 可以用原型的方法来解决这个问题。
实例对象
  • 实例对象:构造函数创建的对象成为实例对象,都是相互独立的
  • 实例成员实例对象中的属性和方法称为实例成员(实例属性和实例方法)
  • 静态成员构造函数的属性和方法被称为静态成员(静态属性和静态方法)
    • 只能由构造函数来访问
    • this指向构造函数
内置构造函数
  • Object

    • Object.key(对象名称)
    • Object.value(对象名称)
    • 拷贝对象或追加对象属性值:Object.assign(新的对象名称, 被拷贝的对象名称)
  • Array

    • reduce 不用遍历进行累加求和
    • 两个参数:
      • 第一个回调函数function(){}
      • 第二个起始值
        在这里插入图片描述
        在这里插入图片描述
    • 将伪数组转为数组:Array.from
  • String
    在这里插入图片描述

    下面这两个方法在实际开发中十分常用:

    • 字符串–>数组:str.split('分隔符')
      const str = 'pink, red'
      const arr = str.aplit(', ')
      console.log(arr)
      
      数组–>字符串:join
    • 字符串截取:str.substring(indexStart[, indexEnd])
      • indexStart:开始截取的索引号
      • indexEnd:结束截取的索引号,不包含结束索引号,可省略
    • 检测字符串开头:str.startWith(检测字符串[, 检测位置索引号]),根据结果返回True或False
    • 检测字符串是否包含关键字:str.includes(searchString[, position])
    • 转换为字符串:num.toString()
  • Number

    • Number:直接使用传数字
    • toFixes():设置保留小数位数的长度
常见数组操作forEach、filter、map和reduce的区别:

在这里插入图片描述

补充:
trim()方法:用于去除字符串两端的空白字符(包括空格、换行符、制表符等),返回一个新的字符串。在判断输入框的字符串是否与对应格式的数据匹配时会用到。

原型和原型链

原型

  • 构造函数

  • 原型prototype是什么?

    • 一个对象,我们也称prototype原型对象
  • 原型的作用是什么?

    • 共享方法
    • 可以把不变的方法,直接定义在prototype对象上
  • 构造函数和原型里面的this指向谁?

    • 实例化的对象
      在这里插入图片描述
      写在原型上的方法可以共享,这样可以通过共享的方式来减少内存的浪费。
  • 公共的属性写在构造函数中

  • 公共的方法写在原型对象上

eg. 自己定义 利用数组扩展方法 来求和求最大值

// 求和
const arr = [1, 2, 3]
Array.prototype.sum = function(){
	return this.reduce((prev, item) => prev + item, 0)
}
console.log(arr.sum())

// 求最大值
const arr = [1, 2, 3]
Array.prototype.max = function(){
	return Math.max(...this)
}
console.log(arr.max())
constructor属性

constructor 构造函数

  • 概念:每个原型对象中默认都有一个constructor属性,指向该原型对象的构造函数
  • 作用:在开发中,若有多个对象的方法,可以给原型对象采取对象形式赋值,但这样就会覆盖构造函数原型对象原来的内容(原型继承),此时需要重新指回创建这个原型对象的 构造函数
function Star(){
}
Star.prototype = {
	// 需要重新指回创建这个原型对象的 构造函数
	constructor: Star,
	sing: function(){
		console.log('唱歌')
	},
	dance: function(){
		console.log('跳舞')
	}
}
对象原型

prototype是指原型/原型对象,构造函数制动有原型
在这里插入图片描述

在这里插入图片描述

原型继承

父构造函数(父类) 子构造函数(子类)
子类.prototype = new 父类()
子类通过原型来继承父类

原型链(面试高频考点)
  • __proto__:属性链状结构
  • instanceof:用于检测构造函数的prototype属性是否出现某个实例对象的原型链上

在这里插入图片描述

基于原型对象的继承使得不同构造函数的原型对象关联在一起,并且这种关联的关系是一种链状的结构,我们将原型对象的链状结构关系称为原型链

原型链的查找规则:
在这里插入图片描述

深浅拷贝

浅拷贝

浅拷贝是创建一个新对象,这个新对象有着原始对象属性值的一份精确拷贝。如果属性是基本数据类型,拷贝的就是基本数据类型的值;如果属性是引用数据类型,拷贝的就是内存地址,所以新对象和原始对象的引用数据类型属性会指向同一块内存地址。
在这里插入图片描述
在这里插入图片描述

深拷贝

深拷贝是指完全克隆一个对象,包括对象的所有嵌套属性。新对象和原始对象是完全独立的,对新对象的任何修改都不会影响原始对象。

  • clodash_.cloneDeep(value)实现深拷贝
    在这里插入图片描述
  • JSON实现深拷贝

异常处理

throw抛异常
try/catch捕获异常
debugger

处理this

call()(🌟🌟)

可以改变调用函数,可以改变this指向,并且传递参数
在这里插入图片描述

apply()(🌟🌟🌟🌟)

可以改变调用函数,可以改变this指向,并且传递参数(参数必须是数组
返回值(本身就是在调用函数,所以返回值就是函数的返回值)

使用场景:求Math.max()数组的最大值
在这里插入图片描述

bind()(🌟🌟🌟🌟🌟)

bind不会调用函数
能改变this指向
因此,当我们只想改变this指向,不想调用这个函数时就用bind
在这里插入图片描述

使用场景:改变定时器内部的this指向

在这里插入图片描述

性能优化

防抖和底层实现(debounce)

在这里插入图片描述

lodash库中的debounce函数

实现防抖的js库
_.debounce(执行的函数, [等待时间], [选项])
在这里插入图片描述

debounce函数的底层实现

手写防抖函数

在这里插入图片描述

节流-throttle

只执行完整的一次
在这里插入图片描述

lodash库中的throttle函数

在这里插入图片描述

节流的底层实现

节流小结
在这里插入图片描述

防抖节流总结:
在这里插入图片描述


### 黑马程序员 JavaScript 学习资料汇总 以下是关于黑马程序员提供的 JavaScript 学习资源及相关知识点的详细介绍: #### 一、基础入门视频教程 可以通过 B 站上的系列课程快速掌握 JavaScript 的基础知识。推荐以下两个视频作为起点: - **【黑马程序员前端JavaScript 入门到精通 (1)** – 提供了 HTML 和 JavaScript 基础理论的学习内容[^1]。 - **【黑马程序员前端JavaScript 入门到精通 (2)** – 进一步深入讲解实际开发中的应用案例。 这些视频涵盖了从零开始学习 JavaScript 所需的核心概念,适合初学者逐步理解并实践。 #### 二、常见功能实现案例分析 在实战项目中巩固所学技能非常重要。以下是一些经典的功能模块及其对应的解决方案: - 轮播图效果:通过 Apis-day2 中提到的方法可以完成带有鼠标悬停暂停以及自动播放等功能的图片轮播组件[^2]。 - 小米官网风格搜索框交互设计:利用焦点事件监听输入状态变化来增强用户体验。 - 键盘按键触发评论提交机制:借助键盘事件捕获用户的敲击动作从而执行特定逻辑操作。 以上实例均来源于官方教学材料,并附带详尽说明便于模仿练习。 #### 三、基本语法结构与事件绑定方法 对于刚接触这门语言的人来说,了解如何正确书写代码至关重要。下面展示了一个简单的例子用于演示给 DOM 对象附加行为的过程: ```javascript // 获取页面内的某个 div 元素节点 var divElement = document.querySelector('div'); // 定义当该元素被单击时要做的事情 function handleClick() { console.log("Div was clicked!"); } // 把上面定义好的函数设置成此 div 上发生 click 类型活动后的响应措施 divElement.onclick = handleClick; ``` 上述片段展示了标准方式之一去关联起始点同其后续可能产生的状况之间的联系[^3]。 #### 四、外部脚本文件加载技巧 为了保持网页主体简洁明了,在适当时候引入独立 js 文件成为必要手段。注意路径配置无误之后按照如下形式声明即可成功调用远端存储的内容[^4]: ```html <script type="text/javascript" src="/path/to/yourfile.js"></script> ``` 确保服务器能够正常提供请求过来的数据包;另外记得调整 MIME-Type 参数匹配目标类型(application/x-javascript 或 text/javascript)。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值