• 《javascript面向对象编程指南》——闭包


    闭包:有权访问另一个函数作用域中的变量的函数,这样的话每个函数都可以被认为是一个闭包。但是大多数时候,该作用域在函数体执行完之后就自行销毁了

    如果一个函数会在其父级函数返回之后留住对父级作用域链的话,相关闭包就会创建

    首先是一个一般函数

    var a = "global variable";
    var F = function() {
    	var b = "local variable";
    	var N = function() {
    		var c = "inner local";
    	};
    };
    

    从全局到最里面的作用域链依次是:

    • a、F()
    • b、N()
    • c

    现在将N的空间扩展到F以外,并止步于全局空间以内,就产生闭包

    var a = "global variable";
    var F = function() {
    	var b = "local variable";
    	var N = function() {
    		var c = "inner local";
    		return b;
    	};
    	return N;
    };
    
    var inner = F();
    inner();	//"local variable"
    

    如上,只需在F空间return出N空间,然后将F()的调用赋值给全局变量inner,此时inner就是N函数,调用一下inner(),就相当于执行N(),但是这里N(),既可以访问其原有的作用域,也是全局函数

    上述步骤就是突破作用域链

    下面这种闭包,不是F()返回函数,而是直接在函数体内N赋值给全局变量inner

    var inner;
    var F = function() {
    	var b = "local variable";
    	var N = function() {
    		return b;
    	};
    	inner = N;
    };
    
    F();		//需要调用,才能将N赋值给inner
    inner();	//"local variable"
    

    相关定义与闭包

    如果一个函数会在其父级函数返回之后留住对父级作用域链的话,相关闭包就会创建

    function F(param) {
    	var N = function() {
    		return param;
    	};
    	param++;
    	return N;
    }
    
    var inner = F(123);
    inner();	//124
    

    如上,当返回的函数被调用时,param++已经执行过一次递增操作了,所以inner()返回的是被更新后的值

    由此,函数所绑定的是作用域本身,而不是在函数定义时该作用域中的变量或变量当前返回的值

    循环中的闭包

    如下,是一个三次循环操作,每次迭代中都会创建一个返回当前循环序号的新函数

    function F() {
    	var arr = [],
    		i;
    	for (i = 0; i < 3; i++) {
    		arr[i] = function() {
    			return i;
    		};
    	}
    	return arr;
    }
    
    var newArr = F();
    console.log(newArr[0]());	//3
    console.log(newArr[1]());	//3
    console.log(newArr[2]());	//3
    

    如上,结果都是3

    我们在这里创建了三个闭包,而他们都指向了一个共同的局部变量i。但是,如上节所说,闭包并不会记录他们的值,他们所拥有的只是相关域在创建时的一个连接(引用)

    当循环结束时i的值为3,所以这三个函数都指向这一个共同值(注意不是2)

    解决1

    function F() {
    	var arr = [],
    		i;
    	for (i = 0; i < 3; i++) {
    		arr[i] = (function(x) {
    			return function() {
    				return x;
    			};
    		})(i);
    	}
    	return arr;
    }
    
    var newArr = F();
    console.log(newArr[0]());
    console.log(newArr[1]());
    console.log(newArr[2]());
    

    如上,将i传递给另一个即时函数

    解决2

    function F() {
    	function binder(x) {
    		return function() {
    			return x;
    		};
    	}
    	var arr = [],
    		i;
    	for (i = 0; i < 3; i++) {
    		arr[i] = binder(i);
    	}
    	return arr;
    }
    
    var newArr = F();
    console.log(newArr[0]());
    console.log(newArr[1]());
    console.log(newArr[2]());
    

    如上,定义一个内部函数,将i本地化

  • 相关阅读:
    浅谈Linux文件操作
    数据结构学习--队列
    CODE[VS] 1099 字串变换
    CODE[VS] 1026 逃跑的拉尔夫
    CODE[VS] 3027 线段覆盖 2
    LeetCode8.字符串转换整数(atoi) JavaScript
    JS实现继承 JavaScript
    LeetCode7.整数反转 JavaScript
    LeetCode6.Z字形变换 JavaScript
    LeetCode5.最长回文子串 JavaScript
  • 原文地址:https://www.cnblogs.com/u14e/p/5463692.html
Copyright © 2020-2023  润新知