六、对闭包的看法,为什么要用闭包?说一下闭包的原理以及应用场景?闭包的 this 指向问题?
闭包的作用:
1. 在外部访问函数内部的变量
2. 让函数内的局部变量可以一直保存下去
3. 模块化私有属性和公共属性
闭包的原理:
全局变量生存周期是永久,局部变量生存周期随着函数的调用介绍而销毁。
闭包就是 在函数中定义且成为该函数内部返回的函数的自由变量 的变量,该变量不会随着外部函数调用结束而销毁。
(注:不光是变量,函数内声明的函数也可以形成闭包)
当函数可以记住并访问所在的词法作用域,即使函数是在当前词法作用域之外执行,这时就产生了闭包。
闭包的应用场景
// 1. 返回值 最常见的一种形式
var fun_1 = function () {
var name = "limo";
return function () {
return name;
}
}
var fun_1 = function () {
var name = "limo";
return name;
}
var fu_1 = fun_1();
console.log("fu_1():" + fu_1());
// 2. 函数赋值 一种变形的形式是将内部函数赋值给一个外部变量
var f2;
var fun_2 = function () {
var name = "limop"
var a = function () {
return name;
}
f2 = a;
}
f2();
console.log(f2);
// 3. 函数参数 通过函数参数引用内部函数产生闭包
var fn_3 = function (f3) {
console.log(f3);
}
function fun_3() {
var name = "limo";
var a = function () {
return name;
}
fn_3(a)
}
fun_3();
// 4. IIFE(自执行函数)
var fn_4 = function (f4) {
console.log(f4);
};
(function fun_4() {
var name = "limo";
var a = function () {
return name;
}
fn_3(a)
})();
// 5. 循环赋值
function foo(){
var arr = [];
for(var i = 0; i < 10; i++){
arr[i] = (function(n){
return function(){
return n;
}
})(i)
}
return arr;
}
var bar = foo();
console.log(bar[3]());
// 6. getter和setter
// getter和setter函数来将要操作的变量保存在函数内部,防止暴露在外部
var getValue, setValue;
(function () {
var num = 0
getValue = function () {
return num
}
setValue = function (v) {
if (typeof v === 'number') {
num = v
}
}
})();
console.log(getValue()); //0
setValue(10);
console.log(getValue()) //10
// 7.迭代器(计数器)
var add = function(){
var num = 0;
return function(){
return ++num;
}
}();
console.log(add());
console.log(add());
function setUp(arr){
var i = 0;
return function(){
return arr[i++];
}
}
var next = setUp(['Steve','Alex','LingYi']);
console.log(next());
console.log(next());
console.log(next());
// 8.触发事件
window.onload = function (){
var btn = document.querySelector('.btn')
btn.onclick = function (){//事件相当于在全局触发
btn.style.color = 'red'//保持对上层作用域的引用 btn
console.log('abc')
// this
}
}
闭包的this指向问题:
var myNumber = {
value: 1,
add: function(i){
var helper = function(i){
console.log(this);
this.value += i;
}
helper(i);
}
}
myNumber.add(1);
1.this指向window对象(因为匿名函数的执行具有全局性,所以其this对象指向window);
2.不能实现value加1(每个函数在被调用时都会自动取得两个特殊变量,this和arguments,内部函数在搜索这两个对象时,只会搜索到其活动对象为止,所以不能实现访问外部函数的this对象);
3.修改代码实现正确功能
第一种解决方法:
var myNumber={
value:1,
add:function(i){
var that=this;//定义变量that用于保存上层函数的this对象
var helper=function(i){
console.log(that);
that.value+=i;
}
helper(i);
}
}
myNumber.add(1);
第二种解决方法:
var myNumber={
value:1,
add:function(i){
var helper=function(i){
this.value+=i;
}
helper.apply(this,[i]);//使用apply改变helper的this对象指向,使其指向myNumber对象
}
}
myNumber.add(1);
第三种解决方法
var myNumber={
value:1,
add:function(i){
var helper=function(i){
this.value+=i;
}.bind(this,i);//使用bind绑定,和apply相似,只是它返回的是对函数的引用,不会立即执行
helper(i);
}
}
myNumber.add(1);
七、简述闭包的问题以及优化
闭包的缺点:占用内层空间 大量使用闭包会造成 栈溢出
由于闭包会一直占用内存空间,直到页面销毁,我们可以主动将已使用的闭包销毁:
将闭包函数赋值为null 可以销毁闭包