全局变量与局部变量、闭包 -JavaScript

全局变量与局部变量、闭包

定义在function外部的变量:全局变量

定义在function内部的变量(有var):局部变量

定义在function内部但没有var的变量:全局变量;想要在全局中使用,必须先调用一次方法

使用场景:

全局变量:少用,一直常驻内存中,不易被销毁,容易出现命名冲突,适合公用的变量

局部变量:函数执行完即被销毁,无法被持久化

作用域

函数作用域:函数内部使用

全局作用域:整个网页范围

块级作用域:{},在整个大括号内

let的特点:

  1. let增加了块级作用域,就是大括号{}

  2. 不能在初始化之前去访问let修饰的变量:暂时性死区

  3. 用let定义的全局变量不属于window,用var定义的全局变量属于window。

//暂时性死区
function run() {
    //不能在初始化之前去访问let修饰的变量:暂时性死区
     console.log(x); //Cannot access 'x' before initialization
     let x = 66;
 }
 run()

//let定义的变量不属于window
var global_name = 'frank'
let global_age = 19
//用let定义的全局变量,不属于window,用var定义的全局变量是属于window的
console.log(window.global_name);
console.log(window.global_age);

const的特点:

命名:要求全部大写,多个单词之间用_隔开

  1. 定义一个常量,不能被修改的

  2. 必须在定义的时候进行初始化

  3. 如果将const当成局部变量使用,则特点和let一样。

//常量:定义的时候就得初始化它的值,且后面不能再修改
const IP_ADDRESS = '172.168.2.1';
// IP_ADDRESS="127.0.0.1";  错误的:Assignment to constant variable.对常量变量的赋值。

//如果要将const当成局部变量去使用,则特点和let一样的
if(1==1){
    const ONE=1;
}
console.log(ONE); //报错:ONE is not defined

但是如果用const定义一个对象,是可以修改对象内部属性的。

不能修改整个对象

const OBJ = {name:'jack',age:20}
OBJ.name = 'rose';
console.log(OBJ);
//OBJ中的name属性已经被修改为rose

OBJ = {name:'rose',age:18}//这样修改会报错

var的特点:

  1. 没有块级作用域,只有个全局作用域和局部作用域

  2. 可以提前声明

  3. 属于window

一个经典题目
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>

<body>
    <script>
        for (var i = 1; i <= 3; i++) {
            //定时器异步执行,等待外部代码执行完毕后执行定时器。
            setTimeout(function() {
                alert(i);
            }, 1000)
        } //弹出三个弹框,结果分别为4,4,4

        for (let i = 1; i <= 3; i++) {
            //let在每次循环的时候都创建l副本,将i的值保存了下来。
            setTimeout(function() {
                alert(i);
            }, 1000)
        } //弹出三个弹框,结果分别为1,2,3

        //即使定时器的时间变化,运行的结果也不会变化
    </script>
</body>

</html>
IIFE(立即执行函数表达式)

语法:

(function([形参]){

	//函数体

[return]

}([实参]))

作用:

  1. 早期模块化解决方案,避免了命名冲突。
  2. 防止外部代码来访问我内部的一些变量,提高了安全性。

闭包

函数嵌套函数,内部函数可以访问外部函数的局部变量。闭包环境是内部函数和外部函数沟通的桥梁。

var fn = (function(){
    var num = 10;
    return function(){
        num++;
        console.log(num);
    }
})()
fn();//11
fn();//12
//在外部执行fn,不论执行多少次,num变量一直存在,从未还原过。
//好处:num既有了全局变量的常驻内存不销毁的特点,并且num又不会和外部名称重名。

缺点:不销毁,会增大内存消耗,不会被垃圾回收器回收,容易造成内存泄漏。

<ul>
    <li>1</li>
    <li>2</li>
    <li>3</li>
    <li>4</li>
</ul>

<script>
	let lis = document.querySelectorAll('li');
    for (var i=0;i<lis.length;i++){
        (function(s){
            lis[s].onclick = function(){
                alert(s);
            }
        })(i)
    }
</script>

垃圾回收机制(GC)

一个变量没在任何地方被使用,会被垃圾回收器收走,释放内存空间。

如何让GC回收num?

fn = null//将fn设置为null,没有地方使用num,则会被GC收走
arguments

当前函数的实参列表

arguments.callee

当前函数(只能在函数内使用)

call&&apply
function play(a,b){
    console.log(this,a+b)
}
play();this为window
var person{};
//动态改变当前函数的this指向,改成person
play.call(person,1,2);//调用函数,参数传递采用序列方式
play.apply(person,[1,2]);//调用函数,参数传递采用数组方式

相同点:都是调用函数并且修改函数里面的this值

不同点:

​ 函数名.call(this新值,参数1,参数2,…,参数N)

​ 函数名.apply(this新值,[参数1,参数2,…,参数N])

函数柯里化

把接受多个参数的函数变换成接受一个单一参数(最初函数的第一个参数)的函数,并且返回接受余下的参数而且返回结果的新函数。

 function sum(){
            //调用slice方法,但是把slice里面的this改成arguments,然后产生一个新数组
            let args = [].slice.call(arguments);//1,3
            function exec(){
                args.push(...arguments);// args = [1,2,3,4]
                return exec;
            }
            exec.calc=function(){
                return args.reduce(function(total,current){
                    return total+current;
                })
            }
            return exec;
        }
        console.log(sum(1,3)(2,4)(100)(1).calc());

//slice截取的时候,找的是 this
let args = [7,8,9].slice();//还是7,8,9 从原数组截取的
let args = [7,8,9].slice.call([1,2,3]);//1,2,3,从后面这个数组截取的

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值