Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

JavaScript【闭包】 #4

Open
Kelichao opened this issue Oct 21, 2016 · 0 comments
Open

JavaScript【闭包】 #4

Kelichao opened this issue Oct 21, 2016 · 0 comments

Comments

@Kelichao
Copy link
Owner

Kelichao commented Oct 21, 2016

闭包(closure)在各种编程语言中有广泛的用途

  • 闭包是指有权访问另一个函数作用域中的变量的函数。
  • 当代码在一个环境中执行时,会创建变量对象的一个作用域链,用来保证对执行环境有权访问的所有变量和函数的有序访问。内部环境可以访问所有的外部环境,但外部环境不能访问内部环境中任何的变量和函数,而且这些变量不会随上一级函数的执行完成而销毁。

在PHP、Scala、Scheme、Common Lisp、Smalltalk、Groovy、JavaScript、Ruby、 Python、Go、Lua、objective c、swift 以及Java(Java8及以上)等语言中都能找到对闭包不同程度的支持。

Javascript闭包就是在另一个作用域中保存了一份它从上一级函数活作用域取得的变量(键值对),而这些键值对是不会随上一级函数的执行完成而销毁。

    function a() {
        var i = 0;
        var b = function () {
            console.log(++i);
        };
        return b;
    }

    var c = a(); 
    console.log(c);

    // function() {
    //      console.log(i);
    //  }

    // 不考虑闭包,然后去执行c,是不是会很奇怪
    // 此时的i仍然保留在函数a的作用域内,只有b才能访问到。
    c(); // -> 1
    c(); // -> 2  会累加起来,说明i的值进行了保存。

如何判断是不是闭包:函数里面套函数,且有return返回相关函数体

附带闭包经典案例,作用域链导致的问题

    function box() {
        var arr = [];
        for (var i = 0; i < 5; i++) {
            arr[i] = function() {
                console.log(i);
            };
        }
        return arr;
    }

    var val = box();

    val[0]();// ->5
    val[1]();// ->5
    val[2]();// ->5

保存的值都是一样的,说明值只有一份,是在函数调用的时候才去取的。

闭包的应用

var module = (function() {
    var object = {};
    var value1 = 10;// 变量不会污染环境,而且不会被GC回收

    object.a = value1;
    object.fn = function() {
        console.log(value1);
    };

    return object;
})();

console.log(module);// Object-> {a: 10,fn: function()...}
module.fn();// 10

附上一个转自百度的图,内部的函数体有访问外部函数体变量的权力。

image

闭包中关于this的问题

在匿名函数中,以及直接通过函数名调用的函数中,this始终是window,除非通过apply或者call改变过值

  • 例一:
var a = {
	b: function() {
		(function() {
			console.log(this);// window
		})();
		console.log(this);// a对象
	}
};

a.b();

image

  • 例二:
var name = "Im window";
var obj = {
	name:"Im obj",
	aaa: function () {

		console.log(this);// obj

		function werw() {
			// 这里的this始终指向window
			console.log(this.name);
		}

		werw();// Im window
		return werw;
	}
};

obj.aaa()();// window
// 等同
(obj.aaa())();// window

this可以通过闭包中的变量,保存在外部作用域中。

var a = {
	b: function() {
		var that = this;
		(function() {
			console.log(that);
		})();
		console.log(this);
	}
};

a.b();

image

在某些特殊的情况下,this的值可能会意外的改变

var a = {
	b: function() {
		(function() {
			console.log(this);
		})();
		console.log(this);
	}
};

(a.b = a.b)();

image

// 这个以后还要研究下
var a = {
	b: function() {
		console.log(this);
	}
};
a.b();// Object {}
(a.b = a.b)();// Window

// 感觉类似这么调用
var x = (a.b = a.b);
x();// window

闭包保存的变量值是当前作用域的值,与实参,形参名无关

var aaa = 222;
var bbb = function(){
	console.log(aaa);
};

(function(){
    var aaa = 111;
    bbb();// 222
})();

所以函数里面套函数,变量就必须要通过传参进行(以便达到即时赋值)。

巧用闭包形成的防止全局变量污染的方法

	var proTimer = (function() {
		var num = 0;
		return function() {
			num ++;
			console.log(num);
		}
	})();

image

解决闭包所带来的问题

  • 问题,输出都是最后的值
var obj ={};
for (var i = 0; i<10; i++ ) {
	obj[i] = function() {
		console.log(i);
	}
}
obj[5]();// 10
obj[8]();// 10

方案一

  • 如果是返回值的,可以用立即执行函数直接存储变量,就是把函数带来的影响消掉
var obj ={};
for (var i = 0; i <= 10; i++ ) {
	obj[i] = (function() {
		// console.log(i);
		return i;
	})();
}
obj[5];// 5
obj[8];// 8

方案二

var obj ={};
for (var i = 0; i <= 10; i++ ) {

	// 原理是将每个函数对象的数据都生成一个独立的闭包
	// 然后再在调用的时候取得保存的对应数据
	obj[i] = (function(num) {
		return function() {
			return num;
		};
	})(i)
}
console.log(obj[5]());// 5
console.log(obj[8]());// 8
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

1 participant