第二章:在html中使用javaScript
第三章:基本概念
第四章:变量作用域和内存问题
第五章:引用类型
目录
系列文章目录
前言
一、基本数据类型和引用类型的值?
1.数据类型
2.赋值
3.传参
4.检测数据类型
二、执行环境及作用域
1.执行环境和作用域概念
2.延长作用域链
3.没有块级作用域
4.垃圾收集
4.1.标记清除法
4.2引用计数法
总结
这本书是我刚入行的时候我师傅推荐给我的,当时只想获得实现的满足感,而一直没有深入学习。随着页面实现了更多后,发现学好javascript非常的有必要,这也是这个系列出现的缘由~
我将分章节学习并记录(第一章简介我就不记录了,有兴趣自己去看看),如果内容太多也会分为上下两小节。
学习过程中也会拓展一下相应内容,思考一些问题,感兴趣就继续往下看看吧~
这一章主要记录一些基本数据类型如何检测、作用域及垃圾回收的一些方法,这一块在面试的时候常常会被问道~
第三章提到基本数据类型有:null nudefined string boolean number(es6还有syblom),引用类型有object
这里我们要明白他们存放位置,基本数据类型存放在栈里面,引用数据类型在栈里面存放指针,指针指向队里面的内存。
所以,当我们进行赋值的时候,如下:
根据上面的图我们可以看清区别:基本数据类型会开启一个新内存赋值,引用类型会开启一个新的内存存指针。
传参最常见于函数,当我们将变量当作参数传递给函数的时候。
对基本数据类型来说,参数是函数的一个局部变量,他的变化不会改变全局变量,如下:
function add(a){
a +=20
}
var age = 80
add(80)
console.log(age)//这里输出80
对引用类型来说,他的变化会改变原始引用值(因为引用地址都相同,所以会改变),如下:
function add(obj){
obj.age="18"
}
var obj = {
name:"lily"
}
add(obj)
console.log(obj.age)//这里输出18
虽然这样会改变引用值,但是并不代表是引用的地址,如下:
function add(obj){
obj.age="18"
obj = new Object()
obj.age="80"
}
var obj = {
name:"lily"
}
add(obj)
console.log(obj.age)//这里输出18,obj并不会将后面的内存赋值上面,后面的只是一个局部变量,函数的参数还是外面的obj
如何检测类型呢,这里提供三种方法:
首先我们知道JavaScript是单线程的语言,我们的语言会按照编码顺序一步一步的执行,执行环境中有一个变量对象,变量对象包括函数和变量。
我们有全局执行变量,就是我们常说的window对象,可以访问他。在我们浏览器关闭或页签关闭的时候全局执行变量才会销毁。
当我们执行的时候遇见了函数,首先会将他放入环境栈里面,等待改函数执行完毕后弹出栈。
我们一步一步执行的时候,会创建变量对象的一个作用域链,我们可以理解为函数内部找不到该变量则向外层执行环境会寻找,直到windows变量。这样形成的一个链路叫作用域链。这里值得注意的是,内部变量可访问内部执行环境,但外部执行环境不能访问内部变量
作用域分为全局作用域和局部(函数)作用域,通常我们执行完后就会移除。但有的时候我们需要延长作用域链,我们只需要在作用域前端添加一个变量对象就可以了啦,可以使用with或try catch中的catch块。
with在我们第三章就说过,它可以将指定对象添加到作用域链上,如下:
function add(){
var name = "lily"
with(location){//将location变量对象添加到作用域链前端
var url = href
}
retrun url
}
try catch会创建一个 新的变量对象
try{
console.log("成功")
}
.catch(err){
var a = "报错啦"
console.log(a)
}
在catch块中将变量对象添加到作用域前端,从而延长作用域链
当然,除了这两种方法,我们还可以使用eval()这个内置对象来延迟那个作用域链,如下:
function add(str){
eval(str)//eval会将字符串解析为js,从而将变量对象添加到作用链前端,延长作用域链
}
add("var a= 0")
这个标题很不理解哈,其他语言不是说{}里面的都是块级作用域吗?在JavaScript中我们陈伟执行环境。作用域也可以叫全局作用域和局部(函数)作用域,但不能说{}里面包裹的就是块级作用域,为什么这样说呢?如下:
//if语句
if(true){
var a ="你好"
}
console.log(a)//输出:你好
//for语句
for(var i=0;i<10;i++){
...
}
console.log(i) //输出10
看到上面这两个语句了嘛,我们都是在{}内部的,但是呢,在{}外部访问也是能访问的,所以这也证实了JavaScript没有块级作用域。
当然,我们在函数内部定义的变量不管是var let const ,在全局执行环境中式无法访问的,但是如果没有用标识符定义,则会将这个变量沿着作用域链查找,直到找个这个标识符的变量(定义这个变量的地方),如果查找到window还没找到,则将这个变量挂载到window上(全局变量)。
我们前面说了,当代码一步一步的执行的时候,会将变量分配内存,当我们变量不在使用得时候,则弹出栈,让内存空出来,这就是垃圾回收机制,这样保证了我们性能和速度。
关于垃圾回收的方法有两种:标记清除法和引用计数法。
执行代码的时候,将变量进行标记,将正在执行环境中的变量和环境中的变量去除标记,将没有标记的变量清除掉,这就是标记清除法。
当我们声明和一个变量或赋值的时候,计数为1,如果又被赋值给另一个变量计数为2,每次被赋值或引用则加1;如果包含这个值得变量被重新赋值,则减1,直到为0时,就会被清除。
但是这个方法如果存在于循环体内,被重复得引用,那他永远都不能被清除,而回导致内存得不到回收,所以不建议用这个方法。
最后,为了得到更好得性能,所以最好在不用该数据得时候将其设置为null,这样下次垃圾回收得时候,就会清除掉,释放内存。
以上就是今天要讲的内容,本文简单介绍了基本数据和引用数据得值,作用域和作用域链,内存及垃圾回收机制。