1.闭包原理
闭包是指我们想要返回一个函数,并且返回的函数内部引用着函数外部的变量,保存函数外的值。这个变量就相当于整个函数的一个背包。
function foo(){
let counter = 0;
let inner = function(){
counter +=1
return counter;
}
return inner
}
let f1 = foo()
console.log(f1())
//1
console.log(f1())
//2
面试考题
var data = [];
for (var i = 0; i < 3; i++) {
data[i] = function () {
console.log(i);
};
}
data[0]();
//3
data[1]();
//3
data[2]();
//3
本质上data数组里面存着都是一个函数,整个函数体就是console.log(i),而执行data中的函数时寻找i时,函数体内没有i,只能找到全局的i,当然是3了。
修改成闭包形式
var data = [];
for (var i = 0; i < 3; i++) {
data[i] = (function (j) {
return function(){
console.log(j)
}
})(i);
}
data[0]();
//1
data[1]();
//2
data[2]();
//3
2.手写call。
使用 call() 方法,您可以编写能够在不同对象上使用的方法,方法重用。
实现效果
let obj = {
value: 'foo'
}
let value = 'outValue'
function foo(){
console.log(this.value)
}
foo.call(obj)
//foo
思路:
将目标函数当成这个对象的一个属性,调用完成将其删除。
版本1(无参数)
Function.prototype.call1 = function(obj){
obj.fn = this;
obj.fn()
delete obj.fn
}
foo.call2(obj)
版本2(有参数)
Function.prototype.call2 = function(obj){
let obj = obj || window //传递为null时指向window
obj.fn = this;
let arg = []
for(let i = 1;i<arguments;i++){
arg.push(`arguments[${i}]`)
}
let result = eqal(obj.fn(arg.join(','))) //别忘了返回值
delete result
}
3.手写apply。
与call类似,只是传递参数的时候传递的是数组。
Function.prototype.apply1 = function (obj, arr) {
obj = obj || window
obj.fn = this
let result
if (!arr) {
result = obj.fn()
} else {
let arg = []
for (let i = 0; i < arguments.length; i++) {
arg.push('arr[' + i + ']');
}
result = eval(`obj.fn(${arg.join(',')})`)
}
return result
}
4.手写bind。
版本1
Function.prototype.bind1 = function (obj) {
self = this
return function () {
return self.apply(obj)
}
}
foo.bind1(obj)()
版本2(可以传入参数,并且参数可以不定)
Function.prototype.bind2 = function (obj) {
self = this
//第一次传入参数
let arg1 = [].slice.call(arrguments,1)
return function () {
//第二次传入参数
let arg2 = [].slice.call(arrguments)
let arg = arg1.concat(arg2)
return self.apply(obj,arg)
}
}
版本3(bind绑定后可以作为构造函数使用,可以使用new)
self = this
//第一次传入参数
let arg1 = [].slice.call(arrguments,1)
return function () {
//第二次传入参数
let arg2 = [].slice.call(arrguments)
let arg = arg1.concat(arg2)
return self.apply(this instance that ? this:obj,arg)
}