
作用域规定了变量能够被访问的范围,离开这个范围变量就不能被访问
作用域分为:
局部作用域分为函数作用域和块作用域。
函数作用域:
在函数内部声明的变量只能在函数内部被访问,外部无法访问
总结:
块作用域:
在JavaScript中使用
{}包裹的代码块内部声明的变量外部将有可能无法被访问
for(let i=0;i<10;i++){
    // i 只能的该代码块中被访问
    console.log(i)
}
// 超出了t的作用域 ,报错
  console.log(i)总结:
let 声明的变量,const 声明的常量,都会产生块级作用域var 声明的变量不会产生块级作用域let 和 const在
<script>标签 和.js文件的最外层就是全局作用域,在此声明的变量在函数内部也可以访问,全局作用域下声明的变量,任何其他作用域都可以被访问
//全局作用域,下声明变量num
const num=10
function fn(){
    //函数内部可以使用
    console.log(num)
}注意:
作用域链本质是底层的变量查找机制
//全局作用域
let a = 1
let b = 2
//局部作用域
function f() {
    let a = 1
    function g() {
        a = 2
        console.log(a)  // 2
    }
    g()
}
f()总结:
垃圾回收机制 (Garbage Collection) 简称 GC JS 中的内存的分配和回收都是自动完成的,,内存在不使用的时候会被垃圾回收器自动回收。 但如果不了解JS的内存管理机制,我们同样非常容易成内存泄漏(内存无法被回收)的情况 不再用到的内存,没有及时释放,就叫做内存泄漏
内存的生命周期 :
垃圾回收算法说明
所谓垃圾回收, 核心思想就是如何判断内存是否已经不再会被使用了, 如果是, 就视为垃圾, 释放掉 下面介绍两种常见的浏览器垃圾回收算法: 引用计数法 和 标记清除法
引用计数 IE采用的引用计数算法, 定义“内存不再使用”的标准很简单,就是看一个对象是否有指向它的引用。 算法:
引用计数算法是个简单有效的算法。 但它却存在一个致命的问题:嵌套引用。 如果两个对象相互引用,尽管他们已不再使用,垃圾回收器不会进行回收,导致内存泄露。
标记清除法 现代的浏览器已经不再使用引用计数算法了。 现代浏览器通用的大多是基于标记清除算法的某些改进算法,总体思想都是一致的。 核心:

概念:一个函数对周围状态的引用捆绑在一起,内层函数中访问到其外层函数的作用域 简单理解:闭包 = 内层函数 + 外层函数的变量
function outer() {
    const a = 1
    function f(){
        console.log(a)
    }
    f()
}
outer
//	内层函数调用外层函数的变量,就是闭包作用: 封闭数据,提供操作,外部也可以访问函数内部的变量
基本格式:

闭包应用:实现数据的私有 比如,我们要做个统计函数调用次数,函数调用一次,就++
普通写法
let count = 1
function fn() {
    count++
     console.log(count)
}
fn() //2
fn() //3这个count 是个全局变量,很容易被修改
闭包写法:
function fn() {
    let count = 1
  return function fun() {
        count++
       console.log(count)
    }
}
const result =fn()
result() //2
result() //3实现了数据私有,无法直接修改count
闭包可能引起的问题:内存泄漏
变量提升是 JavaScript 中比较“奇怪”的现象,它允许在变量声明之前即被访问(仅存在于var声明变量)
console.log(str) //不报错 控制台显示undefined
var str = 'hello'注意:
函数提升与变量提升比较类似,是指函数在声明之前即可被调用。
动态参数
arguments 是函数内部内置的伪数组变量,它包含了调用函数时传入的所有实参
//求和函数 不管用户传入几个实参,都要把和求出来
function sum() {
    let s = 0
    for(let i = 0;i < arguments.length;i++){
        s += arguments[i]
    }
    return s
}
sum(5,10) //15
sum(1,2,3) //6剩余参数
剩余参数允许我们将一个不定数量的参数表示为一个数组
... 是语法符号,置于最末函数形参之前,用于获取多余的实参... 获取的剩余实参,是个真数组function sum(...other) {
    let s = 0
    for(let i = 0;i < other.length;i++){
        s += other[i]
    }
    return s
}
sum(5,10) //15
sum(1,2,3) //6区别:
展开运算符:...
展开运算符 (…), 将一个数组进行展开,不会修改原数组
const arr=[1,2,3,4,5]
console.log(...arr) //1 2 3 4 5典型运用场景: 求数组最大值(最小值)、合并数组等
const arr=[1,2,3,6,4,5]
const arr2=[7,8,9]
//最大值
const max=Math.max(...arr)
//合拼
const arr3=[...arr,...arr2]展开运算符 or 剩余参数 剩余参数:函数参数使用,得到真数组 展开运算符:数组中使用,数组展开
语法:
//普通函数
const fn = function (){
    ...
}
fn()
//1.箭头 无参数
const fn = () =>{
    ...
}
//2.只有一个参数
const fn = x=> {
    return x
}
//3.函数体只有一行代码,可以写一行上,无需写 return 直接返回值
const fn = (x,y) => x + y  //返回 x + y 的值
//加括号的函数体返回对象字面量表达式
const fn1 = uname =>({uname : uname}) 
console.log(fn1('叶湘伦')) //控制台:{uname:"叶湘伦"}箭头函数参数:
arguments 动态参数arguments 动态参数,但是有 剩余参数 ..args箭头函数 this: 在箭头函数出现之前,每一个新函数根据它是被如何调用的来定义这个函数的 this 值 箭头函数不会创建自己的 this ,它只会从自己的作用域链的上一层沿用 this 。


在开发中【使用箭头函数前需要考虑函数中 this 的值】,事件回调函数使用箭头函数时,this 为全局的 window,因此,DOM事件回调函数为了简便,还是不太推荐使用箭头函数
数组解构是将数组的单元值快速批量赋值给一系列变量的简洁语法。
// 普通的数组
  let arr = [1, 2, 3];
  // 批量声明变量 a b c 
  // 同时将数组单元值 1 2 3 依次赋值给变量 a b c
  let [a, b, c] = arr;
  console.log(a); // 1
  console.log(b); // 2
  console.log(c); // 3基本语法:
= 左侧的 [] 用于批量声明变量,右侧数组的单元值将被赋值给左侧的变量undefined... 获取剩余单元值,但只能置于最末位undefined 时默认值才会生效对象解构
// 普通对象
 const user = {
   name: '小明',
   age: 18
 };
 // 批量声明变量 name age
 // 同时将数组单元值 小明  18 依次赋值给变量 name  age
 const {name, age} = user
 console.log(name) // 小明
 console.log(age) // 18总结:
= 左侧的 {} 用于批量声明变量,右侧对象的属性值将被赋值给左侧的变量undefinedundefined 时默认值才会生效forEach() 方法用于调用数组的每个元素,并将元素传递给回调函数
遍历数组.forEach(function (当前数组元素,索引号){
    //函数体
}) 注意:

filter() 方法创建一个新的数组,新数组中的元素是通过检查指定数组中符合条件的所有元素
主要使用场景: 筛选数组符合条件的元素,并返回筛选之后元素的新数组
遍历数组.filter(function (当前数组元素,索引号){
    return 筛选条件
}) 
//筛选数组大于30的元素
const arr=[10,26,62,61,56,12,36]
const re = arr.filter(function(item){
    return item > 30
})
console.log(re) //[62,61,56,36]返回值:返回数组,包含了符合条件的所有元素。如果没有符合条件的元素则返回空数组 参数:currentValue 必须写, index 可选 因为返回新数组,所以不会影响原数组
利用字面量创建
const obj = {
    name:'叶湘伦',
    age:18
}利用 new Object 创建对象
const obj = new Object({
    name:'叶湘伦',
    age:18
})利用构造函数创建
// 构造函数
function Obj(name,age){
    this.name = name
    this.age = age
}
//创建一个对象
const Stu = new Obj('叶湘伦',18)注意:
说明:
实列化执行过程:
通过构造函数创建的对象称为实例对象,实例对象中的属性和方法称为实例成员
// 构造函数
function Obj(name,age){
    //构造函数内部的 this 就是实例对象
    //实例对象中动态添加属性
    this.name = name
    this.age = age
      //实例对象中动态添加方法
    this.sayHi = function () {
        console.log('hi')
    }
}
//实例化 ,Stu 是实列对象
// Stu 实际就是构造函数内部的 this
const Stu = new Obj('叶湘伦',18)
//访问实例属性
console.log(Stu.name)
//调用实列方法
Stu.sayHi()说明:
静态成员:
在 JavaScript 中底层函数本质上也是对象类型,因此允许直接为函数动态添加属性或方法,构造函数的属性和方法被称为静态成员。
// 构造函数
function Obj(name,age){
   //实例成员
}
//静态属性
Obj.eyes = 2 
Obj.arms = 2
//静态方法
Obj.walk = funtion () {
    console.log('走路中')
    //this 指向 person
    console.log(this.eyes) 
}总结:
this 指向构造函数本身在 JavaScript 中最主要的数据类型有 6 种,分别是字符串、数值、布尔、undefined、null 和 对象,常见的对象类型数据包括数组和普通对象。其中字符串、数值、布尔、undefined、null 也被称为简单类型或基础类型,对象也被称为引用类型。
在 JavaScript 内置了一些构造函数,绝大部的数据处理都是基于这些构造函数实现的,JavaScript 基础阶段学习的 Date 就是内置的构造函数。
引用类型:
Object :
三个常用静态方法(静态方法就是只有构造函数Object可以调用的)
Object.keys 静态方法获取对象中所有属性(键)
Object.values 静态方法获取对象中所有属性值
Object.assign 静态方法常用于对象拷贝
//Object.keys
const obj = {name:'叶湘伦',age:18}
const arr = Object.key(obj)
console.log(arr)  // ['name','age']  返回是一个数组
//Object.values
const arr2 =Object.values(obj)
console.log(arr2)  // ['叶湘伦',18]  返回是一个数组
//Object.assign
const obj2 = {}
Object.assign(obj2,obj)
console.log(obj2)  // {name:'叶湘伦',age:18}
//使用:经常使用的场景给对象添加属性
Object.assign(obj,{sex:'男'})
console.log(arr)  // {name:'叶湘伦',age:18,sex:'男'}Array :
数组常见实例方法-核心方法

| 方法 | 作用 | 说明 | 
|---|---|---|
| forEach | 遍历数组 | 不返回值,用于不改变值,经常用于查找打印输出值 | 
| filter | 过滤数组 | 筛选数组元素,并生成新数组 | 
| map | 迭代数组 | 返回新数组,新数组里面的元素是处理之后的值,经常用于处理数据 | 
| reduce | 累积器 | 返回函数累计处理的结果,经常用于求和等 | 
总结:

Array 构造函数forEach 用于遍历数组,替代 for 循环 (重点)filter 过滤数组单元值,生成新数组(重点)map 迭代原数组,生成新数组(重点)join 数组元素拼接为字符串,返回字符串(重点)find 查找元素, 返回符合测试条件的第一个数组元素值,如果没有符合条件的则返回 undefined(重点)every 检测数组所有元素是否都符合指定条件,如果所有元素都通过检测返回 true,否则返回 false(重点)some 检测数组中的元素是否满足指定条件 如果数组中有元素满足条件返回 true,否则返回 falseconcat 合并两个数组,返回生成新数组sort 对原数组单元值排序splice 删除或替换原数组单元reverse 反转数组findIndex 查找元素的索引值String:
总结:
length 用来获取字符串的度长(重点)split('分隔符') 用来将字符串拆分成数组(重点)substring(需要截取的第一个字符的索引[,结束的索引号]) 用于字符串截取(重点)startsWith(检测字符串[, 检测位置索引号]) 检测是否以某字符开头(重点)includes(搜索的字符串[, 检测位置索引号]) 判断一个字符串是否包含在另一个字符串中,根据情况返回 true 或 false(重点)toUpperCase 用于将字母转换成大写toLowerCase 用于将就转换成小写indexOf 检测是否包含某字符endsWith 检测是否以某字符结尾replace 用于替换字符串,支持正则匹配match 用于查找字符串,支持正则匹配注:String 也可以当做普通函数使用,这时它的作用是强制转换成字符串数据类型。
JavaScript 规定,每一个构造函数都有一个 prototype 属性,指向另一个对象,所以我们也称为原型对象
作用:
constructor 属性: 指向该原型对象的构造函数
对象原型:
对象都会有一个属性 __proto__ 指向构造函数的 prototype 原型对象,之所以我们对象可以使用构造函数 prototype 原型对象的属性和方法,就是因为对象有 __proto__ 原型的存在

总结:
prototype是什么?哪里来的?constructor属性在哪里?作用干啥的?prototype原型和对象原型__proto__里面都有__proto__属性在哪里?指向谁?prototype原型继承
继承是面向对象编程的另一个特征,通过继承进一步提升代码封装的程度,JavaScript 中大多是借助原型对象实现继承的特性。
//人类
const People = {
    head:1,
    eyes:2,
    leys:2,
    say:function () {}
}
//男人
function Man(){
}
//公共属性和方法给原型
Man.prototype = People
//如果我们给男人添加了一个吸烟的方法,发现女人自动也添加这个方法
//男人和女人都同时使用了同一个对象,根据引用类型的特点,他们指向同一个对象,修改一个就会都影响
Man.prototype.smoking = function () {}
//女人
function Woamn() {
    //独有方法
    this.body =function () {}
}
// 继承写法完善 ,解决上面问题
//男人和女人不要使用同一个对象,但是不同对象里面包含相同的属性和方法
//答案:构造函数
//new 每次都会创建一个新的对象
function People() = {
    head:1,
    eyes:2,
    leys:2,
    say:function () {}
}
//男人
function Man(){
}
//公共属性和方法
Man.prototype =new People()原型链:
基于原型对象的继承使得不同构造函数的原型对象关联在一起,并且这种关联的关系是一种链状的结构,我们将原型对象的链状结构关系称为原型链

原型链-查找规则:
__proto__指向的 prototype 原型对象)Object 的原型对象)Object 为止(null)__proto__对象原型的意义就在于为对象成员查找机制提供一个方向,或者说一条路线拷贝的是地址 常见方法:
Object.assgin() 展开运算符 {...obj} 拷贝对象Array.prototype.concat() 或者 [...arr]总结:
拷贝的是对象,不是地址
常见方法:
总结:
throw 抛出异常信息,程序也会终止执行throw 后面跟的是错误提示信息Error 对象配合 throw 使用,能够设置更详细的错误信息总结:
try...catch 用于捕获错误信息try 代码段中try 代码段中出现错误后,会执行 catch 代码段,并截获到错误信息finally 不管是否有错误,都会执行debugger :类似浏览器调试打断点
普通函数的调用方式决定了 this 的值,即【谁调用 this 的值指向谁】
普通函数没有明确调用者时 this 值为 window,严格模式下没有调用者时 this 的值为 undefined
箭头函数中的 this 与普通函数完全不同,也不受调用方式的影响,事实上箭头函数中并不存在 this !
call() 方法调用函数,同时指定被调用函数中 this 的值
fn.call(thisArg,arg1,arg2,...)说明:
thisArg:在 fn 函数运行时指定的 this 值arg1,arg2:传递的其他参数apply() 调用函数,同时指定被调用函数中 this 的值
fn.apply(thisArg,[argArray])说明:
thisArg:在fn函数运行时指定的 this 值argsArray:传递的值,必须包含在数组里面apply 主要跟数组有关系,比如使用 Math.max() 求数组的最大值bind() 不会调用函数。但是能改变函数内部this 指向
fn.bind(thisArg,arg1,arg2,...)说明:
thisArg:在 fn 函数运行时指定的 this 值arg1,arg2:传递的其他参数总结:
call 和 apply 会调用函数, 并且改变函数内部 this 指向call 和 apply 传递的参数不一样, call 传递参数 aru1, aru2.. 形式 apply 必须数组形式[arg]bind 不会调用函数, 可以改变函数内部 this 指向节流:
就是指连续触发事件但是在 n 秒中只执行一次函数,比如可以利用节流实现 1s之内 只能触发一次鼠标移动事件
防抖:
指触发事件后在 n 秒内函数只能执行一次,如果在 n 秒内又触发了事件,则会重新计算函数执行时间
使用场景