1. Scope chain
1. Through an example
let a='global'
console.log(a);//'global'
function course(){
let b='js'
console.log(b);//'js'
session()
function session(){
let c=this
console.log(c);//Window
teacher()//函数提升
function teacher(){
let d='steven'
console.log(d);//'steven'
console.log('test1',b);//'js'
}
}
}
course()
2. Modify this example
let a='global'
console.log(a);//'global'
function course(){
let b='js'
console.log(b);//'js'
session()
teacher()//报错
function session(){
let c=this
console.log(c);//Window
// teacher()
//函数提升--在作用域内提升(超出了当前作用域,所以报错)
function teacher(){
let d='steven'
console.log(d);
console.log('test1',b);
}
}
}
course()
3. Continue to modify this example (can let and var promote variables)
let a='global'
console.log(a);//'global'
function course(){
let b='js'
console.log(b);//'js'
session()
function session(){
let c=this
console.log(c);//Window
teacher()
//2.函数提升-作用域之内
function teacher(){
//2.1 let不支持提升
//2.2 变量通过var支持提升,变量的声明可以提升
//相当于执行了这样一个操作: var e=underfined(提升)
console.log('e',e);//undefined
let d='steven'
console.log(d);
//e='tom'
var e='tom'
console.log('test1',b);//'js' //3.作用域向上查找,向下传递
}
}
}
course()
4. Raise the priority
//提升优先级
console.log('yunyin',yunyin);
function yunyin(){
this.course='js'
}
yunyin='course'
//变量优先,函数需要变量,所以变量最终会覆盖函数
//块级作用域
if(true){
let e=11
var f=222
}
console.log(f);
// console.log(e);
//1.对于作用域链我们可以直接通过创建态来定位作用域链 --静态创建
//2.手动取消全局
5. Function hoisting - within scope
let a='global'
console.log(a);//'global'
function course(){
let b='js'
console.log(b);//'js'
session()
function session(){
let c=this
console.log(c);//Window
teacher()
//函数提升-作用域之内
function teacher(){
console.log(d);//报错
let d='steven'
console.log(d);
console.log('test1',b);
}
}
}
course()
6.this/context context
Example: There is a river in front of my house, there is a bridge on the river in front of the door, and there are ducks in the river in front of the door.
There is a river in front of my house, there is a bridge on the river, and there are ducks in the river.
This refers to the river in front of my house, which is the context.
Conclusion: this is determined by dynamically reading the context at execution time, not at creation time.
7. The focus of the investigation - the pointers of each usage state
(1) In the direct call of the function, this points to the window
==>Environment executed globally =>Function expression/anonymous function/nested function
Why? Because it is determined by the execution environment of the caller that invokes it.
function foo(){
console.log(this)
}
foo() //window.foo()
(2) Implicit binding -- this refers to the upper level of the call stack => object/array and other reference relationship logic
function fn(){
console.log('隐式绑定',this.a);//1
}
let obj={
a:1,
fn
}
obj.fn=fn
obj.fn()
Interview questions:
const foo={
bar:10,
fn:function(){
console.log(this.bar);//undefined
console.log(this);//Window
}
}
//取出
let fn1=foo.fn
//独立执行
fn1()
Question 1: How to change the direction of this?
const o1={
text:'o1',
fn:function(){
//直接使用上下文--传统派活
console.log('o1fn',this);
return this.text
}
}
const o2={
text:'o2',
fn:function(){
//呼叫领导执行,部门协作
return o1.fn()//o1的执行态
}
}
const o3={
text:'o3',
fn:function(){
//直接内部构造,公共人
let fn=o1.fn
return fn()//挂载在全局公共的一个方法
}
}
console.log('o1fn',o1.fn());
console.log('o2fn',o2.fn());
console.log('o3fn',o3.fn());
Follow-up 2: Now I want the result of concole.log('o2fn', o2, fn()) to be o2.
(1) Human intervention, change this--bind/apply/call
o2.fn().call(o2)
(2) No artificial changes are required
const o1={
text:'o1',
fn:function(){
//直接使用上下文--传统派活
console.log('o1fn',this);
return this.text
}
}
const o2={
text:'o2',
fn:o1.fn
}
console.log('o2fn',o2.fn());
(3) Explicit binding (bind | apply | call)
function foo() {
console.log('函数内部', this);
}
foo()
foo.call({
a: 1
})
foo.apply({
a: 1
})
const bindFoo = foo.bind({
a: 1
})
bindFoo()
Interview question: the difference between call/apply/bind
1. Call vs. apply parameters are passed in differently, sequentially passed in/array passed in
2.bind returns directly different, need to call again
###The principle of bind / write a bind by hand
//1.需求:手写bind=>bind挂载位置(挂载在哪里)=>Function.prototype
Function.prototype.newBind = function () {
//2.bind是什么?
//改变this
const _this = this
//接收参数args,第一项参数是新的this,第二项到最后一项是函数传参
const args = Array.prototype.slice.call(arguments)
console.log('args', args);
const newThis = args.shift()
console.log('newThis', newThis);
//3.返回值
return function () {
return _this.newApply(newThis, args)
}
}
Function.prototype.newApply = function (context) {
context = context || window
//挂载执行函数
context.fn=this
let result=arguments[1]
? context.fn(...arguments)
:context.fn()
delete context.fn
return result
}
### Closure: A combination of a function bundled with references to its surrounding state
1. The scene where the function is used as the return value
//函数作为返回值的场景
function mail(){
let content='信'
return function(){
console.log(content);//信
}
}
const envelop=mail()
envelop()
2. When the function is used as a parameter
let content=0
function envelop(fn) {
content = 1
fn()
}
function mail(){
console.log(content);//1
}
envelop(mail)//把mail函数嵌入到了envelop函数中
3. Nesting of functions
let counter = 0
function outerFn() {
function innerFn() {
counter++
console.log(counter);//1
}
return innerFn
}
outerFn()()
Extension: 1. Immediate execution function => the cornerstone of js modularization
let count=0
(function immediate(args){
if(count===0){
let count=1
console.log(count);
}
})(args)
2. Implement private variables
function createStack() {
return {
items: [],
push(item) {
this.item.push(item)
}
}
}
const stack={
items:[],
push:function(){}
}
function createStack(){
const items=[]
return {
push(item){
items.push(item)
}
}
}