上下文 + 作用域
1let a = 'global';2 console.log(a);34 function course() {5 let b = 'zhuawa';6 console.log(b);78 session();9 function session() {10 let c = 'this';11 console.log(c);1213 teacher();14 function teacher() {15 let d = 'yy';16 console.log(d);1718 // 作用域查找19 console.log(b);20 }21 }22 }23 course();2425 // 取消了全局、块级作用域26 if(true) {27 let e = 1111;28 console.log(e);29 }
this 上下文 context
this 是在执行时动态读取上下文决定的,不是在定义时决定
函数直接调用 - this 指向 window
1function foo() {2 console.log("函数内部的this:", this);3}45foo();
隐式绑定 - this 指向调用堆栈的上一级
1function fn() {2 console.log("隐式绑定:", this.a);3}4const obj = {5 a: 1,6};78obj.fn = fn;9obj.fn();
实战:
1const foo = {2 bar: 10,3 fn: function () {4 console.log(this.bar);5 console.log(this);6 },7};8let fn1 = foo.fn;9fn1();1011// 如何改变指向1213const o1 = {14 text: "o1",15 fn: function () {16 return this.text;17 },18};19const o2 = {20 text: "o2",21 fn: function () {22 return o1.fn();23 },24};25const o3 = {26 text: "o3",27 fn: function () {28 let fn = o1.fn;29 return fn();30 },31};3233console.log(o1.fn());34console.log(o2.fn());35console.log(o3.fn());
- 在执行函数时,如果函数被上一级所调用,那么上下文即指向上一级
- 否则为全局孤立,指向 window
将 console.log(o2.fn())结果是 o2
1// 1 - 人为干涉、改变this - bind/call/apply2// 2 - 不许改变this3const o1 = {4 text: "o1",5 fn: function () {6 return this.text;7 },8};9const o2 = {10 text: "o2",11 fn: o1.fn,12};13// this指向最后调用他的对象,在fn执行时,函数挂到o2上即可
显式绑定(bind | apply | call)
1function foo() {2 console.log("函数内部的this:", this);3}4foo();56foo.call({ a: 1 });7foo.apply({ a: 1 });89const bindFoo = foo.bind({ a: 1 });10bindFoo();
new - this 指向的是 new 之后得到的实例
1class Course {2 constructor(name) {3 this.name = name;4 console.log("构造函数中的this", this);5 }67 test() {8 console.log("类方法中的this", this);9 }10}11const course = new Course("this");12course.test();
异步方法中 this 有区别么
1class Course {2 constructor(name) {3 this.name = name;4 console.log("构造函数中的this", this);5 }67 test() {8 console.log("类方法中的this", this);9 }1011 asyncTest() {12 console.log("异步方法外", this);13 setTimeout(function () {14 console.log("异步方法中的this", this);15 }, 100);16 }17}18const course = new Course("this");19course.test();20course.asyncTest();
- 执行 setTimeout 时,传入匿名 function 执行,效果和全局执行函数效果相同
- 把 function 改为无独立上下文的箭头函数即可
bind 原理 / 手写 bind
- bind 在哪里
1function sum(a, b, c) {2 console.log(a, b, c, this);3 return a + b + c;4}5// 1. sum.bind - 在哪里 ? => Function.prototype6//7Function.prototype.newBind = function () {8 // 2. bind 是什么?9 // a.返回一个函数 b. 返回原函数执行结果 c. 传参不变10 const _this = this;11 const args = Array.prototype.slice.call(arguments);12 // args特点: 第一项 - newThis, 第二项 ~ 最后一项 - 函数传参13 const newThis = args.shift();1415 return function () {16 return _this.apply(newThis, args);17 };18};
- apply 应用 - 多传参数组化
1Math.max(2, 4, 5, 6);2const arr = [2, 4, 5, 6];3let max = Math.max.apply(this, arr);
优先级 - new > 显式 > 隐式 > 默认
1function fn() {2 console.log(this);3}45const obj = {6 fn,7};89obj.fn(); // obj1011// 显式 > 隐式12obj.fn.bind(111)();1314function foo(a) {15 this.a = a;16}1718const obj1 = {};1920var bar = foo.bind(obj1);21bar(2);22console.log(obj1.a); // 22324// new25let baz = new bar(3);2627// new > 显式28console.log(obj1.a); // 229console.log(baz.a); // 3
闭包: 一个函数和他周围状态的引用捆绑在一起的组合
函数作为返回值场景
1function mail() {2 let content = "信";3 return function () {4 console.log(content);5 };6}7const envelop = mail();8envelop();
- 函数外部获取到了函数作用域内的变量值
函数作为参数
1let content;2function envelop(fn) {3 content = 1;45 fn();6}7function mail() {8 console.log(content);9}10envelop(mail);
函数嵌套
1let counter = 0;23function outerFn() {4 function innerFn() {5 counter++;6 console.log(counter);7 }8 return innerFn;9}
事件处理(异步执行)的闭包
1let lis = document.getElementsByTagName("li");23for (var i = 0; i < lis.length; i++) {4 (function (i) {5 lis[i].onclick = function () {6 console.log(i);7 };8 // setTimeout(function() {9 // console.log(i);10 // }, 100)11 })(i);12}
立即执行嵌套
1(function immediateA(a) {2 return (function immediateB(b) {3 console.log(a); // 04 })(1);5})(0);
立即执行遇上块级作用域
1let count = 0;2(function immediate() {3 if (count === 0) {4 let count = 1;56 console.log(count);7 }8 console.log(count);9})();
拆分执行 多个闭包
1function createIncrement() {2 let count = 0;34 function increment() {5 count++;6 }78 let message = `count is ${count}`;910 function log() {11 console.log(message);12 }1314 return [increment, log];15}1617const [increment, log] = createIncrement();18increment();19increment();20increment();21log(); // count is 0
实现私有变量
1function createStack() {2 return {3 items: [],4 push(item) {5 this.items.push(item);6 },7 };8}9const stack = {10 items: [],11 push: function () {},12};1314function createStack() {15 const items = [];16 return {17 push(item) {18 items.push(item);19 },20 };21}