高级程序设计开发笔记3(必须懂的闭包和高阶函数)

闭包的形成与变量的作用域和变量的生命周期有关

var func = function () {
  var a = 1;
  console.log(a);
};

func();  //1
console.log(a); //ReferenceError: a is not defined

作用域的面试题

var func1 = function () {
  var b = 2;
  var func2 = function () {
    var c = 3;
    console.log(b); //2
    console.log(a); //1
  };
  func2();
  console.log(c); //c is not defined
};
func1();

经典的闭包面试题2

var nodes = document.getElementsByTagName('div');
        for (var i = 0, len = nodes.length; i < len; i++) {
            (function (i) {
                console.log(i, 'i')
                nodes[i].onclick = function () {
                    console.log(i);   //0 1 2 3 4
                }
            })(i)
        };

可以看到用了自执行的闭包函数后,我们打印出的就是想要 的效果了

判断数据类型的工具方法

var Type = {};
for (var i = 0, type; (type = ["String", "Array", "Number"][i++]); ) {
  (function (type) {
    Type["is" + type] = function (obj) {
      return Object.prototype.toString.call(obj) == `[object ${type}]`;
    };
  })(type);
}
console.log(Type.isArray([]));
console.log(Type.isString("str"));

//版本1;声明一个私有变量

var mult = function () {
  var a = 1;
  for (var i = 0; i < arguments.length; i++) {
    a *= arguments[i];
  }
  return a;
};

console.log(mult(1, 2, 3));

//版本2;避免相同的参数的重复计算,利用对象的key值的唯一性进行判断

var cache = {};

var mult1 = function () {
  var args = [].join.call(arguments, "-");
  console.log(args);
  if (cache[args]) {
    return cache[args];
  }
  var a = 1;
  for (var i = 0; i < arguments.length; i++) {
    a *= arguments[i];
  }
  return (cache[args] = a);
};

console.log(mult1(1, 2, 9), "----");
console.log(mult1(1, 2, 9), "----");

//版本3;将cache生命在闭包内部,避免全局污染

var mult3 = (function () {
  var cache = {};
  return function () {
    var args = [].join.call(arguments, "-");
    console.log(args);
    if (cache[args]) {
      return cache[args];
    }
    var a = 1;
    for (var i = 0; i < arguments.length; i++) {
      a *= arguments[i];
    }
    return (cache[args] = a);
  };
})();

console.log(mult3(2, 3, 4));
console.log(mult3(2, 3, 4));

//版本4,函数的提炼

var mult4 = (function () {
  var cache = {};
  var calculate = function () {
    var a = 1;
    for (var i = 0; i < arguments.length; i++) {
      a *= arguments[i];
    }
    return a;
  };
  return function () {
    var args = [].join.call(arguments, "-");
    console.log(args);
    if (cache[args]) {
      return cache[args];
    }
    // calculate.call(null, arguments);
    return (cache[args] = calculate.apply(null, arguments));
  };
})();

console.log(mult4(5, 3, 4));
console.log(mult4(5, 3, 4));

//图片上报的数据丢失,函数执行完成后img会被销毁,而此时的ajax请求可能还未执行

var report = function (src) {
  var img = new Image();
  img.src = src;
};

report("xxxxxxxxxx");

var report2 = (function () {
  var imgs = [];
  return function (src) {
    var img = new Image();
    img.src = src;
    imgs.push(img);
  };
})();

//过程与数据的结合是形容面向对象的"对象"时经常使用的表达
//对象以方法的形式包含了过程,而闭包则是在过程了以环境的
//形式包含了数据

var extent = function () {
  var value = 0;
  return {
    call1: function () {
      value++;
      console.log(value, "aaaa");
    },
  };
};
var e = extent();
e.call1(); //1 aaaa
e.call1(); //2 aaaa
e.call1(); //3 aaaa

//版本1,改成面向对象的形式

var test = {
  value: 0,
  call1() {
    this.value++;
    console.log(this.value, "++++");
  },
};
test.call1();
test.call1();
test.call1();

//版本2

var Extent = function () {
  this.value = 0;
};
Extent.prototype.call1 = function () {
  this.value++;
  console.log(this.value, "构造函数");
};

let test2 = new Extent();

test2.call1();
test2.call1();
test2.call1();
 <div class="btns">
        <button id="excute">打开电视机</button>
        <button id="undo">关闭电视机</button>
    </div>
//面向对象的思想是做什么怎么做,和谁做要分开,进行抽象
     var Tv = {
         open() {
             alert("打开电视机")
         },
         close() {
             alert('关闭电视机')
         }
     }
      //声明了一个命令,包含各种方法,把目标对象传进去
        var OpenCommand = function (receiver) {
            this.receiver = receiver
        }
        OpenCommand.prototype.excute = function () {
            this.receiver.open()
        }
        OpenCommand.prototype.close = function () {
            this.receiver.close()
        }
        //在这个命令方法里面,配置好各种对应的执行命令
        var setCommand = function (command) {
            document.getElementById('excute').onclick = function () {
                command.excute()
            }
            document.getElementById('undo').onclick = function () {
                command.close()
            }
        }
        setCommand(new OpenCommand(Tv))

在这里插入图片描述在这里插入图片描述
这样就实现了我们的命令模式
//版本2,用闭包的方式实现命令模式
//显然比面向对象的更精简

var createCommand = function (receiver) {
            var excute = function () {
                receiver.open()
            }
            var undo = function () {
                receiver.close()
            }
            return {
                excute, undo
            }
        }
        var setCommand = function (command) {
            document.getElementById('excute').onclick = function () {
                command.excute()
            }
            document.getElementById('undo').onclick = function () {
                command.undo()
            }
        }
        setCommand(createCommand(Tv))

//版本1

        var appendDiv = function () {
            for (var i = 0; i < 100; i++) {
                var div = document.createElement('div')
                div.innerHTML = i
                document.body.appendChild(div)
                div.style.display = "none"
            }
        }

//版本2

        var appendDiv = function (cb) {
            for (var i = 0; i < 100; i++) {
                var div = document.createElement('div')
                div.innerHTML = i
                document.body.appendChild(div)
                if (typeof cb == 'function') {
                    cb(div)
                }
            }
        }
        appendDiv()  //div未被隐藏
        appendDiv(function (node) { //div被隐藏
            node.style.display = 'none'
        })

//单例模式

        var getSingle = function (fn) {
            var ret;
            return function () {
                return (ret = fn.apply(this, arguments));
            };
        };

        getSingle(function () {
            return document.createElement("script");
        });
        var s1 = getSingle()
        var s2 = getSingle()
        console.log(s1 == s2, '000');

//AOP面向切面编程,是吧一些与核心业务无关的代码抽离出来
//根据需要再动态的加入
//下面是使用方法

Function.prototype.before = function (fn) {
  var _self = this;
  return function () {
    fn.apply(null, arguments);
    return _self.apply(null, arguments);
  };
};
Function.prototype.before = function (fn) {
  var _self = this;
  return function () {
    let ret = _self.apply(null, arguments);
    fn.apply(null, arguments);
    return ret;
  };
};

var func = function () {
  console.log("我是本来要执行的");
};
func = func
  .before(function () {
    console.log("我是插入进来的,需要提前执行");
  })
  .before(function () {
    console.log("我是需要在最后执行的");
  });
func();

在这里插入图片描述
//函数节流 触发的频率太高了 window.resize docment.onmousemove
//函数节流的实现

        var throttle = function (fn, interval) {
            var _self = fn,
                timer,
                firstTime = true;
            return function () {
                var args = arguments,
                    _me = this;
                if (firstTime) {
                    _self.apply(_me, args);
                    return (firstTime = false);
                }
                if (timer) {
                    return false;
                }
                timer = setTimeout(() => {
                    clearTimeout();
                    timer = null;
                    _self.apply(_me, args);
                }, interval || 500);
            };
        };
        window.onresize = throttle(function () { console.log(1) }, 400)
        window.onresize = function () { console.log(1) }

//分批加载数据

		var ary = []
        for (var i = 0; i < 1000; i++) {
            ary.push(i)
        }
        //版本1 一次性加载1000数据
        var renderList = function (data) {
            for (var i = 0, l = data; i < l.length; i++) {
                var div = document.createElement('div')
                div.innerHTML = i
                document.body.appendChild(div)
            }
        }
        let r1 = console.time()
        // renderList(ary)
        let r2 = console.timeEnd()

        //版本2 每次只加载8条数据
        var timeChunk = function (ary, fn, count = 1) {
            var obj, t, len = ary.length
            var start = function () {
                for (var i = 0; i < Math.min(count, ary.length); i++) {
                    var obj = ary.shift()
                    fn(obj)
                }
            }
            return function () {
                t = setInterval(() => {
                    if (ary.length == 0) {
                        return clearInterval(t)
                    }
                    start()
                }, 200);
            }
        }
        var renderList2 = timeChunk(ary, function (data) {
            var div = document.createElement('div')
            div.innerHTML = data
            document.body.appendChild(div)
        }, 8)
        renderList2()
        ```
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值