三阶段:
-
js高级语法
-
异步编程+模块化+版本管理
-
node.js+mongDB+学生管理系统
代码的执行环境
-
全局执行上下文
-
函数执行上下文
-
eval执行上下文[很少使用,了解即可]
-
"字符串里面的运算也会被解析"
-
<script> var str = "1*2+3"; document.write(eval(str));//5 </script>
-
===================================
一、全局变量和局部变量
定义:
-
定义在function外部的变量:全局变量
-
定义在function内部的变量:局部变量
-
定义在function内部,但是没有var的变量也是:全局变量
使用常见
-
全局:少用,一直常驻内存中不易被销毁,容易出现命名冲突,适用于公共的变量
-
局部:函数执行完即被销毁,所以无法被持久化(保留)
作用域
-
函数作用域:函数内部使用范围(局部作用域)
-
全局作用域:整个网页范围
声明变量
(1)、let
特点
-
块级作用域
-
暂时性死区【不能在初始化前访问它】
-
当全局变量使用时,它不属于window对象
(2)、const
-
命名:要求全部大写,多个单词之间用下划线隔开
特点:
-
定义的时候就得初始化它的值,且后面不能再修改
-
当作局部变量的时候,效果和let一样
-
如果用const定义一个对象,那么是可以修改对象内部属性的
其他
一、立即执行函数(IIFE)
语法
(function([形参列表]){
//函数体(立即执行的js代码)
[return]
})([实参列表])
作用:
-
早期模块化解决方案,避免了命名冲突
-
防止外部代码来访问我内部的变量,提高了安全性
-
注意:连续写多个立即执行函数会报错,需要用分号隔开
<script>
function play(){
console.log("play")
}
play();
(function(){
console.log("IIFE")
})()
~function(){
console.log("IIFE2")
}()
+function(){
console.log("IIFE3")
}()
-function(){
console.log("IIFE4")
}()
*function(){
console.log("IIFE5")
}()
</script>
//可使用特殊符号调用立即执行函数
二、闭包
定义:
-
函数嵌套函数,内部函数可以访问外部函数的变量,闭包环境是内部函数和外部函数沟通的桥梁
特点
-
让外部访问函数内部变量成为可能
-
局部变量会常驻在内存中
-
可以避免使用全局变量,防止全局变量污染,起命名冲突
-
会造成内存泄漏(有一块内存空间被长期占用,而不被释放),使用次数多了,增加了内存消耗,容易造成内存泄漏
闭包使用场景
//点击LI,弹出LI的下标
var lis=document.querySelectorAll('li');
for(var i=0;i<lis.length;i++){
(function(s){
lis[s].onclick=function() { console.log(i) }
})(i)
}
<script>
var fn = (function(){
var num=10;
return function(){
num++;
console.log(num);
}
})()
//闭包:函数嵌套函数,内部函数可以访问外部函数的局部变量,闭包环境是内部函数和外部函数沟通的桥梁
//在外部执行fn,不论执行多少次,num变量一直存在,从未还原过
//好处:num既有了全局变量的常驻内存不销毁的特点,并且num又不会和外部名称重名
//坏处:用多了之后,增加了内存消耗,容易造成内存泄漏
//num为什么不会被num垃圾回收器收走:
//这个变量一直被内部函数(fn)所使用,所以num不会被垃圾回收器收走
fn();//11
fn();//12
fn();//13
//如何让GC回收掉num呢?
//将fn设置为null,没有地方用num了,自然就被GC收走了
fn=null;
//没有任何地方使用的变量,会被垃圾回收器收走(释放内存空间)
var s="jackie";
</script>
<script>
var name = "The Window";
let object = {
name: "My Object",
getNameFunc: function () {
console.log(this);
var that = this;//that就是object
return function () {
console.log(this);//此时this已经变化为window了,所以不要用this
return that.name;//object.name
};
//独立的创建一个函数,不论写在哪,都属于window
function play(){
console.log("play 里面的this是谁呢?",this);//window
}
var run =function(){
console.log("run 里面的this是谁呢?",this);//window
}
run();
play();
}
};
object.getNameFunc()();
</script>
三、this指向问题
this指向window
-
function 函数名(){}
-
var 函数名=function(){}
this指向当前这个对象
-
var obj = { 函数名:function(){} }
this指向当前这个btn按钮
-
btn.οnclick=function(){}
四、
(1)、arguments
含义:当前函数的实参列表(只能在函数里面使用)
(2)、argument.callee
含义:返回当前函数(只能在函数里面使用)
(3)、call/apply
相同点:都是动态修改this指向
不同的:
-
函数名.call(新的this值,参数1,参数2,……)
-
函数名.apply(新的this值,[参数1,参数2,……])
常景:
//slice截取的时候,找的是 this
let args = [7,8,9].slice();//还是7,8,9 从原数组截取的
let args = [7,8,9].slice.call([1,2,3]);//1,2,3,因为修改了this指向,所以从后面这个数组截取的
//将this指向改变为了[1,2,3]
五、函数柯里化
含义:
-
柯里化是一种将使用多个参数的一个函数转换成一系列使用一个参数的函数的技术
意义:
-
通过拆分参数的方法达到减少代码冗余,增加可读性的目的
function sum()
//通过slice方法,但是把slice里面的this改成arguments,然后产生一个新数组
let args=[].slice.call(arguments)
function exec(){
args.push(...arguments);
return exec;
}
exec.calc=function(){
return args.reduce(function(total,current){
return total+current;
})
}
return exec;
}