this pointer/closure and scope (advanced)

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)
                }
            }
        }

Guess you like

Origin blog.csdn.net/huihui_999/article/details/131735502