介绍
本期介绍作用域和闭包的知识点和题目。包括作用域,自由变量,闭包,this 等部分。作用域是 “JS 三座大山” 之二,不知道闭包的话,面试通过概率不大。
变量合法的使用范围
// ES6 块级作用域
if (true) {
let x = 100
}
console.log(x) // 会报错
什么是自由变量?
有两种情况:
// 函数作为返回值
function create() {
let a = 100
return function () {
console.log(a)
}
}
let fn = create()
let a = 200
fn()
// 函数作为参数
function print(fn) {
let a = 200
fn()
}
let a = 100
function fn() {
console.log(a)
}
print(fn)
注意:所有自由变量的查找是在函数定义的地方,向上级作用域查找,不是在执行的地方
实际开发中闭包多用于隐藏数据 ,只提供API进行修改数据
this 有几种赋值情况apply和call会让当前函数立即执行,而bind会返回一个函数,后续需要的时候再调用执行
注意:this取什么值是在函数执行的时候确定的,不是在函数定义的时候确定的
手写call
function myCall() {
const content = [].shift.call(arguments) || window;
content.fn = this;
const result = content.fn(...arguments);
delete content.fn;
return result;
}
Function.prototype.myCall = myCall;
fn.myCall(obj, 'arg1', 'arg2'); // {a: '这是obj'}
手写apply
function myApply() {
const content = [].shift.call(arguments) || window;
content.fn = this;
const result = content.fn(...arguments[0]);
delete content.fn;
return result;
}
Function.prototype.myApply = myApply;
fn.myApply(obj, ['arg1', 'arg2']); // {a: '这是obj'}
手写bind
function myBind() {
const content = [].shift.call(arguments) || window;
content.fn = this;
const args = arguments;
return () => {
const result = content.fn(...args);
delete content.fn;
return result;
}
}
Function.prototype.myBind = myBind;
fn.myBind(obj, 'arg1', 'arg2')(); // {a: '这是obj'}
示例:
const obj = {a: '这是obj'};
function fn(arg1, arg2) {
console.log(this);
}
fn.call(obj, 'arg1', 'arg2'); // {a: '这是obj'}
fn.apply(obj, ['arg1', 'arg2']); // {a: '这是obj'}
fn.bind(obj, 'arg1', 'arg2')(); // {a: '这是obj'}
原理:
注:此原型图解可对照[JS基础—原型和原型链](https://blog.csdn.net/qq_37215621/article/details/126790301)中class 实现继承定义的类理解
解释:直接xiaoluo.sayhai,调用对象是xiaoluo,所以this是能找到的用__proto__原型去访问的话,调用对象是__proto__,所以name和number是未定义的