关于闭包和this 指向

有关闭包

什么是闭包?

定义

  • 官方定义:闭包 (closure) 指有权访问另一个函数作用域中变量的函数 。
  • 简单理解:闭包就是一个函数,这个函数能够访问另一个函数中的变量
  • 注意:被访问的这个变量所在的函数就是闭包函数

作用

最本质的作用就是:延申了变量的作用范围

闭包的原理

高阶函数

闭包就是典型的高阶函数的用法,它内部返回的是一个函数

主要实现原理

  • 要使用闭包函数中的局部变量,我们就在闭包函数中 ==return ==一个函数,再在外面调用就可
  • 这个局部变量不会立即销毁,因为内部还返回了函数,需要这些函数全部被调用之后再销毁

闭包的应用以及说明

点击 li 获得该 li 的索引号

下面展示一些 内联代码片

// 代码
<ul class = 'nav'>
<li>苹果</li>
<li>香蕉</li>
<li>榴莲</li>
</ul>
// 获取所有的li
var lis = document.querySelectorAll('.nav li');
// for 循环给每个li 注册点击事件
// 原理:立即执行函数,将索引号i作为实参传递给立即执行函数,再将这个i打印出来
// 这里的立即执行函数形成了一个小闭包,它里面的变量i 都可以被里面的任何一个函数使用

for(var i = 0; i<lis.length; i++){
    
    
(function(i){
    
    
lis[i].addEventListener('click',function(){
    
    
   console.log(i);
})
 })(i);
}

打车计价

下面展示一些 内联代码片

// 功能说明:起步价13元(3公里内);每增加一公里,就多收5元;如果有拥堵情况,就再加收10元,根据目的地的公里数,自动计算打车价格

var car = (function(){
    
    
var start = 13;   // 这两个变量在函数内部,所有就是局部变量,但里面的返回函数能访问它,所有这个函数就形成了闭包函数
var total = 0;
	return {
    
       // 由于需要返回两个函数,我们利用在对象中添加方法这种方式
		price: function(n){
    
    
		if(n>=3){
    
    
		total = start + (n-3)*5;
          }
          else{
    
    
          total = start;
          }
          return total
          },
          YD: function(flag){
    
    
			return	flag = true? total+10 :total
		}
           }
       })()
// 调用函数
console.log(car.price(5));
console.log(car.YD(ture));

这两个小案例中都用到了闭包,使局部变量也能被其他函数访问,延申了变量的作用域,节约了内存空间。

思考题:下面案例中有没有用到闭包

案例1

下面展示一些 内联代码片

 var name = 'The Window';
        var o = {
    
    
            name:'My object',
            getName: function(){
    
    
                return function(){
    
    
                    return this.name;
                };
            }
        };
        console.log(o.getName()());
// 问题1? 这里的this 指向什么?结果是什么

相当于指向了以下步骤:

var f = o.getName();
// 对象的方法是返回一个函数
f =  function(){
    
    
              return this.name;
                };
f();
function(){
    
    this}();  // 这就是立即执行函数,而立即执行函数中的This指向的是window
// 因此输出的结果应该是全局变量的Name   “The Window’

以上输出的结果应该是全局变量的Name “The Window“
这里没有闭包的产生。

案例2

下面展示一些 内联代码片

// An highlighted block
 var name = 'The Window';
 var object = {
    
    
      name : 'my object';
      getName:function(){
    
    
           var that  = this;   // 对象中的方法中的this指向的是函数的调用者,而根据 object.getName() 我们得知是对象调用了这个函数,因此this 指向object
              return function(){
    
    
                  return that.name;
                };
            }
        };
  console.log(object.getName()());
  // 和以上分析一样,只不过这里的this 指向的不window 而是object
  

以上输出的结果是‘my object’
因为返回的函数里面用到了getName 这个函数中的变量,所有用到了闭包,getName()就是闭包函数。

谈谈this 的指向问题

普通函数 : this指向window
对象中的方法: this指向方法的调用者,一般是所在的这个对象
构造函数 : this指向的是一个实例对象
绑定事件函数(按钮绑定点击事件) : this 指向函数的调用者
定时器函数 : this 一定指向的是window
立即执行函数 : 和普通函数一样指向window

函数 this指向
普通函数 window
对象中的方法 方法的调用者,一般是所在的这个对象
构造函数 一个实例对象
绑定事件函数(按钮绑定点击事件) 函数的调用者
定时器函数 window
立即执行函数 和普通函数一样指向window

改变this 的指向问题

一般来说,This 的指向是固定的,在实际开发需求中,我们往往想要改变this 的指向,更利于开发
改变this 指向有三种方法:

  • call () : 主要应用于继承;

  • apply() : 由于它传递的参数必须是数组形式或者伪数组 形式,所有它主要应用于跟数组有关的场景
    3.== bind()== : 应用于我们想要改变this 的指向而又不想让这个函数立即调用,比如定时器,定时器函数就是在时间到了才调用函数的,

  • 对于apply() 的主要应用:我们来用它求一个数组中的最大值

  • apply(指向目标,数组1,数组2,…)

// An highlighted block
var arr = [1,66,0,89,234]
var max = Math.max.apply(Math,arr);
// 这里的apply(Math,arr)中的Math 代表不改变this的指向,还是指向原来的Math 这个内置对象,也可以写成null 但是严格模式下不建议写null,

 console.log(max);
下面来重点说说这个bind() 它也是在实际开发中用的最多的方法;

问题描述:
我们有三个按钮,当点击按钮,被点击的按钮禁用了,3秒之后又开启:
我们用两种方法来对比效果,看看哪种方式更灵活

  1. 传统方法
    下面展示一些 内联代码片
// Body部分
<button>key1</button>
<button>key2</button>
<button>key3</button>
// script部分
<script>
var btns = document.querySelectorAll('button');
// for 循环绑定事件
for(var i=0; i<lis.length; i++){
    
    
btns[i].onclick = function(){
    
    
	this.disabled = true;  // 点击就禁用
	setInterval(function(){
    
    
		btns[i].disabled = false   // 注意这里只能写btns[i]  绝对不能写this, 这里的this 指向的是window
	},3000)
}
}

</script>
  1. 用bind() 方法
// Body部分
<button>key1</button>
<button>key2</button>
<button>key3</button>
// script部分
<script>
var btns = document.querySelectorAll('button');
// for 循环绑定事件
for(var i=0; i<lis.length; i++){
    
    
btns[i].onclick = function(){
    
    
	this.disabled = true;  // 点击就禁用
	setInterval(function(){
    
    
		this.disabled = false   //这里的this 来源于Bind传递的参数
	}.bind(this),3000)   // 这里的this 在定时器的外面,指向的不是window ,而是函数的调用者btns[i],把这个this 传递给定时器函数
}
}
</script>

方法2 改变了this 的指向,原本定时器函数中的this 指向的window ,这里利用bind 将this 指向了绑定事件的对象–按钮!
nice!!

猜你喜欢

转载自blog.csdn.net/lucky_ferry/article/details/119064689
今日推荐