作用域链执行机制

作用域

定义:指变量访问的范围,离开了这个作用域,变量不能被访问。

分类:局部作用域和全局作用域,局部作用域分为函数作用域和块作用域

函数作用域,在函数内部或者形参都是在函数作用域内,函数内定义的变量只能在函数里访问,函数执行完就被清空

块作用域,以{}包围内定义的变量就是块作用域,for,if括号内定义的变量都是在块作用域上。但是在{}上的var无法在块作用域上,可以有var在函数作用域上。

局部作用域上的变量都只能在作用域上访问。外部无法访问。定义在{}的变量不在块作用域上。

局部作用域内都能访问到全局作用域上。

全局作用域在script标签或者js文件的最外层。

作用域链

 本质

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

        作用域链执行机制_第1张图片

作用域链执行机制_第2张图片

作用域在内存当中的存在情况,在栈内有函数,函数会有函数作用域的部分,存在于变量环境内,和函数所有代码块都存在于词法环境。全局变量中也有全局变量存在于变量环境,但是变量环境可以被window访问到。词法环境内是全局下的块级作用域,let和const定义的都是块级作用域。

内存上都存在作用域链,访问的时候会往更大的作用域查找,首先查找的是自身所在作用域,如果在词法环境,第二个是变量环境,再去查找的时候,只会找变量环境。作用域链是为了变量查找,且一定是往大的范围查找。查找的时候机制就是如此,不会有机制使得往更小的作用域查找。

垃圾回收机制

简称GC,

内存生命周期:内存分配(系统分配)=>内存使用=>内存回收(由垃圾回收机制自动回收)

垃圾回收机制会自动回收局部变量的内存。

全局变量在关闭页面时被垃圾回收机制回收。

内存泄漏

严格来说:无法释放内存

广泛而言:内存生命周期长,无法被回收。

垃圾回收机制的算法

引用计数法和标记清除法

作用域链执行机制_第3张图片

垃圾回收机制会回收变量所在内存,垃圾回收机制也会回收对象,对象的回收计数,看是否还有变量指向。计数。

但是当两个对象互相指向则无法回收该内存。对象也可以通过程序员自己回收。

作用域链执行机制_第4张图片

标记清除法是看对象能否通过程序被找到,来是否回收。

垃圾回收机制会在函数不再用时,回收函数内存。变量回收也是一样。看该变量是否能被存在的变量访问到。

闭包

闭包是指有权访问另一个函数作用域中的变量的函数。

定义:函数内还有函数,且内层函数用到了外层函数定义的变量(无论是变量环境还是词法环境)

作用:使得函数外的能访问外层函数定义的变量。用闭包函数的return能返回变量的值,但是只是返回一个字面值,使得外部能得到,当无法访问内存,无法修改。

闭包内层函数还能访问外层函数的变量,此时变量的内存不会回收。

闭包能实现数据私有且能被访问,不能被修改。

变量提升

将var定义的变量提升到作用域最前面,只提升声明,不提升赋值。变量在一个作用域上,当于

let c=2

let b=1

var a=1

var a

let c=2

let b=1

a=1

函数提升

函数提升,在作用域内会将所有函数写到作用域最上层。只提升声明,不调用。函数也只能在作用域上才能访问。

参数

动态参数

每一个函数(非箭头函数)都有动态参数,可以直接在arguments变量,这个变量是参数形成的伪数组。每个函数内都有都能访问。

arguments该参数最后得到的是Objet类,是对象,不过形式和数组一样,但不是Array数组对象。无法有数组对应的方法。但是Object类内也有length属性。每个函数内的arguments都是调用后执行时,自动将所有形参生成的伪数组。

剩余参数

作用域链执行机制_第5张图片

剩余参数赋值赋得是真数组。...arr变量还是arr,但是形参写了...会知道将前面参数之后的所有实参组成数组赋给...后的变量。剩余参数后不能再写形参,剩余参数只写在形参内。

展开运算符

作用域链执行机制_第6张图片

该运算符和剩余参数写法一样,但是剩余参数是写在形参上,运算符不是,写在其他地方表示,

扩展运算符只能跟数组。作用是相当于写了一个数组元素隔逗号的一行数(去掉【】)。写了这种,可以写到实参上。

箭头函数

箭头函数无函数名,可以用来替代匿名函数。更为简单的语法

匿名函数的写法

function(){

}

箭头函数的写法

(形参)=>{

代码块

}

执行箭头函数,调用箭头函数时,也是将参数传递,然后执行代码块。

箭头函数的简化写法

1.箭头函数基本写法
()=>{
}
2.只有一个参数可以省略括号
a=>{
}
3.代码块内只有return语句时,可以直接写return后面的
(a)=>a
相当于
(a)=>{
return a
}
4.当代码块只有一行代码,但不是return可以去掉{}
(a)=>{
console.log(a)
}
简化
(a)=>console.log(a)
5.当返回值是对象时,由于对象如果写{name:'zhangsan'},程序将认为是代码块的{}。
返回值是对象,且只有返回语句时,对象需要()
(a)=>{
return {name:'zhangsan'}
}
简化(a)=>({name:'zhangsan'})
上诉简化时,程序都知对应什么执行的时候也会对应执行。

箭头函数时用来替代匿名函数,写法更为简便。箭头函数没有动态参数arguments,有剩余参数(...arr)

各类函数当中this

this是底层的一个参数,函数的隐式形参。this是调用该函数的对象。this内存存的是调用函数的对象。箭头函数没有this变量,当找不到this这个变量会去作用域链上一层找this。

为什么普通函数的调用者是window对象???

函数也是存在于变量内的。且直接写函数,有函数提升。存在于window上。调用时,我们省略了window。

数组解构

作用域链执行机制_第7张图片

数组解构是我们可以定义变量名为数组格式,内部写变量名。且内部a,b

,c也会在内存中定义一个变量,分别对应。

两个变量互换值,可以

let a=1,b=2;

[b,a]=[a,b]

这种写法把变量名都写到数组内,可以直接定义多个变量等于数组上的值。[]可以不写为变量名,直接使用也可以,作为=号的左边,作为变量,可以分别赋值。在这个符号上面也可也写剩余变量。也可也和形参一样赋一个值。

可以省略变量

const [a,b,,d]=[1,2,3,4]

相当于

const a=1

const b=2

const d=4

多维数组解构

作用域链执行机制_第8张图片

写[]的形式可以实现多个变量的赋值。且[]内也可以写[],也是实现变量的赋值。

对象解构

变量赋值时也可也用{}来同时赋多个值,无论用[]还是{},格式都必须相同,会找数组或对象对应的进行变量赋值。

但是{}变量进行赋值时,需要变量名和对象内所需要的属性名相同,还有一种就是所需属性名:自己定义的变量名,则会赋值给我们定义的变量名。

let a=0

{name:a}={name:'zhangsan'}

console.log(a)//zhangsan

数组对象解构

作用域链执行机制_第9张图片

{}和[]是可以一起用的。[]号内一个{}和一个数组元素所占一样。

多重对象解构

const pig={

name:'佩奇',

family:{

mother:'猪妈妈',

father:'猪爸爸'

},

age:6

}

const  {name,family:{mother,father},age}=pig

{}解构时,后面的:也可以是[],或者{}都可以,会给{mother,father}赋值。

我们传参时,也可以将形参写成这种形式,且以{}/[]可以只需要一部分。

写成形参其实也是赋值。赋值就和写的代码一样。就是会有多个变量赋值。不过这些变量都是形参。

以解构为一行代码开头或者立即执行函数,需要在前一句加上;代表语句的结束,否则会认为这两行是一行代码。我们平时换行都是代表语句的结束。

数组的方法

1.forEach()

作用域链执行机制_第10张图片

数组调用该方法时,执行该方法,会使得调用的数组遍历,且遍历时调用该函数。调用该函数就会执行。只要执行代码,比如参数为函数内部写了alert都会执行。

对象的创建

创建对象的方法

1.const a={name:‘张三’,age:18}

2.const a=new Object({name:‘张三’,age:18})

3.const a=new  Pig('张三',18}

functiom Pig(name,age){

this.name=name

this.age=age

}

创建对象可以用内置构造函数,但是形参是{}形式,我们直接写{},是省略了new Object()。该构造函数会创建对象。且在控制台是这种格式.构造函数内有对应的方法。

我们new这个关键词就会创建对象,然后执行对应的函数,this是执行这个对象的。new Object也是构造函数也是创建对象。这些函数可以当成普通函数。对象的创建其实是new+函数。返回值是对象也是new。不是函数来返回。

创建类似的对象,属性名相同属性值不同的对象,可以自己写构造函数,可以更为简单。

被用作构造函数的函数有两个约定;1:大写字母开头,采用大驼峰方法,每一个单词首字母大写

(普及以下小驼峰,首字母不大写,第二个单词开始首字母大写

2.创建对象需要new+构造函数()

执行过程

作用域链执行机制_第11张图片

对象内存可以直接新增属性的,如果没找到。

实例成员和静态成员

实例成员和静态成员是只有对象才存在的,如果不是对象只是简单的基本数据类型,只在变量内存存一个数字,是没有成员的。实例成员只有对象才有,通过对象才能访问的。静态成员是

作用域链执行机制_第12张图片

这种内存不在对象内存上,只能调用函数时访问。构造函数被调用也会创建函数作用域下的。

但是对象只能访问到在对象上的。且所有的构造函数.静态成员有一块内存,存在于哪,可以通过函数来访问。所有的函数可以通过程序内能访问到函数的变量.变量,可以增加该变量。且是静态变量,对象无法访问。

a.age=18

我们所有的写法写基本数据类型的时候,底层都会给数作为参数创建对应的对象。因此这些数据才可以调用属性/函数。

比如1.isFinite()自动将数字都 new Number(1).isFinite().我们这些字面值都是基本数据类型,但是这些构造函数都会创建成对象类型。且这些对象类型在输出台上还是写成基本数据类型。调用方法和变量赋值会new 构造函数。对象类也有叫Numebr的。

Object的方法

静态方法

Object.keys(对象)返回值是对象的所有属性名,按序排成数组。

Object.values(对象) 返回值是对象的所有属性值,按序排成数组。

Object.assign(对象A,对象B),给对象A增加对象B的键值对。不会返回值,直接是对象A内存发生改变。

Array方法

作用域链执行机制_第13张图片
 

该·构造函数有对应的实例函数。变量名为foreach,filter,map,reduce的方法。

foreach函数是数组调用这个函数,函数内部写的数组遍历,且每一次遍历都调用forEach参数的函数。只是调用,但是不会对数组做出什么变化。this是指向该数组。参数为函数的返回值也不会做什么

filter函数,参数是函数,函数内部是每一个this遍历,遍历的时候调用函数,return上写条件,返回值为true的那一个来组成新数组,返回。

reduce函数,也是一个参数是函数,作用是遍历数组,遍历数组的时候,如果有第二个参数,则第一次调用数组的时候,传的两个参数第一个是第二个参数,第二个是数组的第一个元素,然后得到返回值,遍历调用第二次传的是这个第一次的返回值,第二个参数是数组第二个元素。依次。得到左后一次遍历的值。返回这个值。如果reduce没有第二个参数,则第一次调用传数组第一个和第二个元素。

map函数,参数是函数,遍历这个数组,然后遍历的时候调用这个函数参数。将每一次调用的返回值组成新的数组返回。

join方法,遍历数组,每一次都将数组的元素和参数拼接,最后输出最终的字符串。

find方法,参数是函数,每一次都去遍历数组,调用参数,传的是数组元素,return上是条件,当第一次return true的时候,停止遍历,返回当前的数组元素。

作用域链执行机制_第14张图片

erery方法,参数也是函数,遍历数组,每一次都去调用这个函数,每一次都返回true,最后就返回true,否则返回false

some方法,参数是函数,遍历数组,每一次都去调用,调用return返回的只要有true,最后就是true

String常见方法

length属性,得到字符串内部多少个字符

split方法,将调用的字符串以split的参数分开,返回数组,数组内是字符串。

(数组的join方法,返回字符串)

subString方法,第一个参数是字符串内第几个字符,开始截取,第二个参数是截取到第几个的前一个字符,subString(1,3)截取第1和第2个字符,字符从0开始算。如果没写第二个参数,会截取到最后一个字符,包括最后一个。

statesWith方法,对比调用的和传入的是否相同,且,没传入第二个参数默认是0,从第0个下标开始对比,第二个参数是多少就从第几个下标开始,一个一个字符对比。

作用域链执行机制_第15张图片

includes方法,

作用域链执行机制_第16张图片

字符串的该方法会对比调用的字符串和参数传入的是否有一样的,调用字符串是否包括传入的字符串,第二个参数可以写数字,表示从调用字符串的第多少个字符开始看,第一个字符下标是0.返回值是true/false,空格也是字符,这里对比可以是第二个下标后的任意一个下标相同。

Number的方法

作用域链执行机制_第17张图片

该构造函数,是对象调用方法,参数是几就保留几位小数,没有对应位的小数就补0,有的话,保留的最后一个小数位四舍五入。

返回值是数字。

你可能感兴趣的:(前端,javascript,开发语言)