
函数的声明方式
var f = function (){}
function f(){}
var f =()=>{}
形参 实参
var f=function(a=10,b=100,...c){
// a=a||10;b=b||100;
console.log(c)
return a+b
}
f(1,2);
f(1);
f();
(形参默认值:a=a||10;b=b||100;
形参=形参||默认值 ,这是es6之前的赋值方法
es6之后 就是直接赋值:a=10,b=100;
)
(剩余运算符: ...形参c;
把剩余的所有实参都放到c这个形参对应数组中去
)
var f=(..ary)=>{
console.log(ary)
}
f(1,2,3,4)
f(1,2)
(arguments实参集合 箭头函数中没有这个关键字)
(this 函数的执行主体 谁让这个函数执行的)
(return 一个决定返回值 另一个是打断函数的执行)
例如:
var a='123465';
a();
这样会报错,是因为函数才会加小括号
var ary =[1,2,f2];
ary[2]();
// 索引2就是f2 再加上一个小括号,就代表f2().
// 也就是相当于 函数执行,就是函数名加小括号
function fn2() {
return function () {
console.log(666)
}
}
fn2()(); //这是一个种写法
(function(){
})() //这是另一种写法
变量提升
f();
var f =()=>{
console.log(1)
}
f();
var f () {
console.log(2)
}
f();
- js 代码执行之前,先把代码中带var和带function的提前声明了,
- var只声明不定义,function是声明+定义
var a; //声明
a=12; //定义
- let const 暂时性死区: 也就是在let之上绝对不能调用对应的变量,一调用就报错。
例如:
var a=10;
funcution f(){
console.log(a);
let a =12;
}
console.log(a);
let a =12;
console.log('a'in window)
//let 和 const声明的变量是不存在变量提升的,不能在let 之前使用该变量 ,用了就报错..
//false let声明的变量不会用在window中
- 变量提升只会提升等号左边的部分
- var 出来的变量会在window增加一个对应属性:window是全局大对象
- let const 声明的变量,不会再window中增加对应的属性
例如:
console.log(a);
console.log(b);
var a=b=21; //这样就是 一个undefined,一个报错
var a=12,b=13;//这样就是undefined
- function 声明的在{}块级作用域中只声明不定义;声明不定义默认值是undefined
- function 声明的函数在整个代码执行之前,早就已经存在了,所以在整个js中都可以执行在条件句中的代码,也会进行变量提升,不管条件是否成立。此时的function只有声明,没定义。
let const var 之间的区别?
- var 可以重复声明,let和const不能重复声明
- let是变量,const是常量。
- let const 没有变量提升,
- let const 存在暂时性死区
- let const 能够识别块级作用域
堆栈内存
if(1<2){
let a=123;
}
console.log(a); //这样就会报错
- 栈内存 : 存储值类型,提供代码的运行环境;
- 堆内存 : 存储引用数据类型;
- 作用域 : 每个作用域就是js中的一个栈内存;
-
全局作用域:页面打开的一瞬间就形成了。页面关闭时全局作用域销毁。
-
私有作用域:在函数执行的时候才会形成。一般执行完函数后作用域就会销毁。但是,函数的返回值若是引用数据类型,则不能销毁。
全局变量:在全局声明的变量 私有变量:在私有作用域中声明的变量,形参 函数执行:先开辟一个私有作用域,形参赋值 变量提升 代码执行
-
块状作用域:在es6之后,所有的{}(除了对象)都是块状作用域。只有let const 能识别块状作用域,var不可以。这个大括号{}不是对象。理解成私有作用域就可以了。
-
上级作用域 : 一个私有作用域的上级作用域是看 该函数在哪儿声明的。跟函数在哪里执行没有关系。
- 对象的存储过程:
先开辟一个堆内存,把键值对一对儿对儿的存进去,完成之后把地址赋给对应的变量
- 函数执行的过程:
先开辟一个私有作用域(也就是栈内存),然后给形参赋值(函数传参不传参都是有赋值的,因为默认值就是undefined),然后在执行变量提升。然后代码从上到下执行。
for(var i = 0; i < 4 ; i++){
setTimeout(()=>{
console.log(1)//如果想要每秒输出i的值加一,就把var换成let 然后输出写i+1。
}),(1000*(i+1));//这个意思就是一秒输出一次。如果不加*(i+1),那就是同时输出四个1。
}
/************************ 换一个方法执行 ***********************/
for(var j = 0; j < 4 ; j++){
(function(n){
setTimeout(()=>{
console.log(n)
}),(6000);
})(j+1)
}
接下来再看看几个简单例子:
var a =12; //全局变量
var f = function(){
console.log(a) //undefined 存在变量提升的原因
var a =100; //私有变量
console.log(a) //100 内部复制为100
}
f()//在代码执行之前,就有变量提升的这个阶段
console.log(a) //12,全局和私有两个不是同一个东西
/*********************** 两个对比看 ********************/
var n=10;
var f2=function(){
console.log(n)//10
n=200;
console.log(n)//200
}
f2()
console.log(n)//200
let例子:
0
var f3=function(c){
//先形参赋值,在变量提升
let c =100;
}
// 暂时性死区:在let和const之前不能使用他们声明的任何变量
1
var d=10;
var f4=function(){
console.log(d)
let d=100;
}
f4();
2
if(1<2){
var e =12;
let z =13;
}
console.log(e);
console.log(z);
this函数执行主体
var ary=[
1,
2,
function(){console.log(this)},
()=>{console.log(this)};
];
let f=ary[2];
f(); //window
ary[2](); //ary.2() ary
ary[3](); //ary.3 //window
- 时间绑定中的this都是当前操作的元素
- 自执行函数中的this是window。
- 一般函数执行时,内部this 看’点‘,点前边是谁this就是谁
总结:
1.箭头函数的this 当做变量去处理了。
2.普通函数this指向规律:
*是将绑定函数中的this,是指向当前操作元素的
*自执行函数中this是指向window的
*其他的函数执行中的this看点(执行的时候看前面有没有点)
闭包(最终目的就是为了保护私有变量)
- 闭包是什么?
本质上就是一个变量保护机制,但平时说的闭包都是置一个不销毁的作用域,用来保护私有变量和存储某私有值。
- 那些地方用过闭包?
自己开发某个模块时,或者自己封装一个写工具库的时候才会使用闭包。
- 闭包的优缺点?(→)
一个不销毁的作用域(栈内存).
-
1.保护私有变量不受外界的污染
-
2.存储值
闭包缺点: 不销毁的作用域,用的多了会造成内存泄漏
a=123;
var f=function(){
var a=10;
var b=13;
var f1=function(){
console.log(a,b)
}
return {f1}
}
var obj = f()
obj.f1()
var obj1=(funcution(){
var a =12;
var b=13;
return function(){
console.log(a,b)
}
})()
obj1()
垃圾回收、堆栈内存销毁:
- 堆内存的销毁:
谷歌浏览器会定期检查堆内存,会销毁没有被引用的堆内存。
- 栈内存的销毁:
全局作用域销毁:只有在页面关闭的时候才会被销毁
- 私有作用域销毁:只有当函数的返回值是一个引用数据类型的时候才不会被销毁。