全局变量:
定义:可以提供给所有代码块和函数调用
私有变量:
定义:在js下,只有函数里定义的变量才是私有的 //在函数中调用可以,但在函数外边调用不到 //只有function中的变量获得不到,其余代码块都可以获取到
基本数据类型:null,undefined,number,string,bollean
引用数据类型:object
栈中存放基本变量,栈是先进后出
堆中存放引用类型对象,通过栈中的地址找到堆中的数据,堆是无序的,function也存在堆中
变量提升和作用域
域解释(变量提升):在当前的作用域中,js代码执行之前,浏览器首先会把带var和function的声明内容,进行提前声明或定义
var a //声明告知浏览器在内存中存储一个变量
var b=11//定义:不但定义了变量,还进行了赋值
变量提升的函数和变量的区别
var在内存中只完成了声明
function在内存中完成了声明和定义,只是函数没调用时存储的是字符串
例如:
console.log(a) //输出undefined
var a =11
fun() //函数未执行前已经完成声明和定以了,且将函数体转换成字符串
//在输出的时候就会输出该function的函数体转换成的字符串
function fun(){
console.log("这是函数")
}
变量提升注意事项
1.不定义var的区别:
console.log(a) //输出undefined
console.log(b) //报错,没有变量提升的过程
var a=11
b=22
2.不管条件是否成立,都要进行变量提升
console.log(a) //输出undefined变量还存在
if(false){
var a=12
}
3.当执行一个匿名函数的时候,是不进行域解释的,代码的执行和定义一起完成了
(function(){
var a=b=3 //var b=3,a=b所以a没有变量提升
})()
console.log(b) //输出3,b变量提升了
console.log(a)//报错,没有变量提升的过程
4.当函数里的return语句执行时,下面的语句虽然不执行但是也需要变量提升
注意:函数作用域下,有私有变量找私有变量,没有形参找全局变量,但是如果形参和私有变量有了变量提升,就不会找全局变量了
function fun(a){
console.log(a)
return false
var a=66
}
fun()
5.在js中,变量和函数名称重复,也冲突,在变量提升时,如果名称声明过了,不会再次声明,但是可以重新赋值
function num(){
console.log(111)
}
num()
var num=66
console.log(num)//输出66,var不会重新声明,但是可以改变值
num() //报错
垃圾回收
js具有自动垃圾回收机制,无需手动清除
标记清除
原理:当js中声明一个变量的时候,将变量标为“进入环境”,则变量在内存中占有位置,当变量执行完毕,会将其标记为“离开环境”js垃圾回收机制检测到“离开环境”就会自动回收
在标准浏览器下常用这个回收方式,只是时间间隔不一样
引用计数
原理:js会跟踪每一个变量的引用次数,当变量被声明,并将一个值赋给变量,则引用计数会标注为1,如果变量执行元素或有进行了赋值,则引用计数进行加1,相反,变量赋给其他变量,或者没再进行操作,则次数减1,直到次数变为0,则回收销毁
如果出现循环引用,a调用b,b调用a,则内存会一直没有释放,容易出现内存泄漏
内存泄漏和溢出的区别
内存泄漏:动态给内存分配空间,在使用完毕之后,没有进行释放,直到程序结束
内存溢出:不顾堆栈分配的数据大小,向内存写入过多的数据,导致数据越界
栈和堆的销毁方式
栈内存
全局变量:只有浏览器关闭的时候才会回收
局部变量:只有定义在函数里的才是局部变量,函数会产生自己的作用域,当函数执行完毕时,js内存机制会自动进行释放
堆内存
对象或函数在堆内存开辟空间,堆内存就会生成一个引用地址,如果有代码引用了这个地址,则对象不会被销毁。
如果想销毁,需要把引用设置成null即可
例如:
varx=new Array()
x=null//销毁了
不被销毁特殊情况
1、函数执行时,返回了一个对象,并在函数外调用,则私有变量不会被销毁
function fun(){//延长作用域链
var x=[1,2,3]
return x
}
var arr=fun()
console.log(arr)//数组可以在函数内访问,不会被销毁
2、在一个私有作用域中,给dom元素绑定事件,这个私有作用域不被销毁
var btn=document.getElementById("btn")
btn.οnclick=function(){
var num=11
alert(num)
}
3、闭包(特殊作用域)
闭包是能够有权访问其他函数内部的私有变量的函数,可以理解为函数嵌套函数。
必须满足以下特点,缺一不可:
1、函数嵌套函数
2、内部函数访问外部函数的变量
3、变量不会被垃圾机制所回收
例如:
function fun(){
var a=22
console.log("fun")
return function (){
var b=1
return ++a+(++b)
}
}
var f=fun()
var v2=f()
console.log(v2)//14
var v3=f()
console.log(v3)//15
注意:fun只执行一次,a不被销毁,闭包执行多选,b每次执行都重新赋值成了1
闭包的作用:
1、可以模拟私有方法
2、用来实现对象的封装
3、用闭包可以访问缓存(存在本地的),当代码执行时间过长,可以先从缓存中读取
面向对象
对象:现实中一切事物都叫做对象
面向对象的实体:包含属性和行为的集合
js没有类的概念,叫做对象,思想上是基于对象,js下定义对象还是用函数体定义
基于对象和面向对象的区别
面向对象:自己设置图纸,照着图纸盖房子
基于对象:别人有一个房子,我照着房子创建
面向对象的三大特征:封装、继承、多态
封装:每一个对象就是一个封装,把具有共同属性和行为的事物放在一起
定义对象
1.通过object创建
var p =new Object()
p.name="小明" //创建变量
p.say=function(){ //创建方法
console.log(p.name,p.age)
}
p.say() //调用方法
2.简写
var p={
name:"小明",
age:23,
say:function(){
console.log(this.name,this.age) //this表示调用当前对象的属性
}
}
p.say()
属性操作
configurable 是否可以通过delete删除
enumerable 是否可以通过for-in进行遍历
writable 是否可以修改属性
value 给属性添加默认值
get 获取属性的方法
set 设置属性的方法
思想:限定陌生人不能操作,但是自己可以通过get和set方法访问
例如:
var obj={name:"小明",age:22}
//对象的属性限定
Object.defineProperty(obj,"name",{
configurable:false,
writable:false,
value:"小蓝"
})
设置get和set
var obj={_name:"小明",age:22}
Object.defineProperty(obj,"name",{
get:function(){ //获得变量
return this._name+"111"
},
set:function(name){ //修改变量
this._name=name
}
})
设置多个属性
var obj={_name:"小明",age:22}
Object.defineProperties(obj,{
name:{writable:false},
age:{enumerable:false}
})
自己创建get和set方法
var obj={
name:"小明",
getName:function(){return this.name},
getAge:function() {return this.age},
setName:function(name){ //有this的是对象里边的变量,没有是外界的变量
this.name=name
},
}
console.log(obj.getName(),obj.getAge())
构造器
用来给对象赋初始值,构造器是一种特殊的函数,如果不写,js会自动分配一个默认无参的构造器
例如:
function Emp(name,age){ //构造器
this.name=name
this.age=age
this.say=function(){
console.log(this.name,this.age)
}
}
var e=new Emp("小丽",21) //调用构造器
new关键字具体做了什么
1.创建了一个新对象
2.将构造器的作用域赋给新对象
3.用this关键字指向这个对象
4.通过proto寻找父类对象
5.返回新对象给调用者
私有变量
在对象下变量通过this关键字进行执行,表示通过地址找到对象下的属性和方法,如果要定义私有的属性和方法,可以不通过this关键字定义
例如
function Emp(age){
var name="小明" //私有变量
this.age=age
}
var e=new Emp(22)
console.log(e.age)
console.log(e.name)
this指向
this关键字用于对象体内,用来指向对象下的属性和方法,方便调用
Global:在node环境下,this的全局作用域指向Global
window:在浏览器环境下,this的全局作用域指向window
例如:
var a=11 //代码题:变量提升、闭包、对象的变量传值和this指向
console.log(a)
console.log(window.a)
console.log(this.a)
this的指向和在哪儿定义,在哪执行都没有关系
函数执行时,看函数前面是否有“.”,有的话点前面是谁就指向谁,如果没有就指向window
例如:
var name="我是window"
var obj={
name:"我是obj",
info:function(){
console.log(this.name)
}
}
console.log(obj.name) //obj
console.log(name) //window
特殊情况
1.当this出现在匿名函数里,永远指向的是window
var name="我是window"
var obj={
name:"我是obj",
info:function(){
return function(){ return this.name }
}
}
var n=obj.info()()
console.log(n) //window
2.当给一个dom元素绑定一个事件的时候,事件执行的方法体内,this指向的是当前元素
btn.οnclick=function(){
console.log(this) //指向btn按钮
}
改变this指向
var name="我是window"
var obj={
name:"我是obj",
info:function(){ //匿名函数
var th=this //在obj环境下存一个对象
return function(){ return th.name //obj }
}
}
var n=obj.info()()
console.log(n) //obj