JS中this指向问题

2 篇文章 0 订阅

默认绑定

  • 默认绑定就是独立函数调用,可以理解为用window调用了这个函数只不过没有加.所以独立函数调用中this为window
    <script>
        function fn(){
            console.log(this);//this表示window
        }
        fn();//window
    </script>
  • 独立函数调用,把对象内的方法地址传给外部变量,通过外部变量加()调用对象里面的方法,此时方法里的this表示的是window
    <script>
        let obj = {
            name:'cc',
            run:function(){
                console.log(this);
            }
        }
        let c = obj.run;//把run方法的地址 赋值给c 此时c指向了run所对应的堆
        c();//调用run方法 是 独立函数调用 那么this 表示的是window
    </script>

隐式绑定

  • 通过对象.方法名+()调用对象内部的方法,方法中出现的this就看.前面的是谁,this就代表了谁。
    <script>
        let obj = {
            name:'cc',
            run:function(){
                console.log(this);//this表示的是obj
            }
        }
        obj.run();//用.调用方法 方法名前面是obj
    </script>

显示绑定

  • 函数也是对象 上面有几个默认的方法 通过call apply bind 可以改变this指向
    使用方法:想要改变this指向的函数名.call(想要指向的东西);
    使用方法:想要改变this指向的函数名.apply(想要指向的东西);
    使用方法:想要改变this指向的函数名.bind(想要指向的东西);
    注意:
    call 和 apply 不仅可以显示绑定this 而且还会让函数执行
    call 会将传入想要指向的东西 包装成一个新的对象返回
    bind 显示绑定this 不会让函数执行 返回一个绑定this 之后新函数
  • call显示绑定
    <script>
        function fn(){
            console.log(this);
            console.log('fn---');
        }
        var obj2 = '修狗';      //call绑定会执行函数
        let obj = fn.call('修狗');//会把"修狗"包装成一个新的对象传给this
    </script>
  • apply显示绑定
    <script>
        function fn(){
            console.log('fn---');
            console.log(this);
        }
        var obj = {
            name:'修狗'
        }
        fn.apply(obj);//apply让函数执行 并且更改this指向
    </script>
  • bind显示绑定
    <script>
        function fn() {
            console.log(this);
            console.log('fn---');
        }
        var obj2 = {
            name: 'xq'
        }
        let newFn = fn.bind(obj2);//bind绑定不会执行函数 
        newFn();//调用 绑定this后新函数  执行函数  {name:'xq'}  fn---
    </script>
  • apply call bind 3中方式的区别
    <script>
        //apply 和bind 会执行函数 如果传入的是基本数据类型 返回结果如下
        //call绑定的是返回的是与传入数据的类型相对应的对象
        function fn(){
            console.log('fn---');
            console.log(this);
        }
        fn.apply('hello'); //fn--- String 
        fn.call(null);//fn--- window
        fn.call(undefined);//fn--- window
        fn.call(10);//fn--- Number
        fn.call('world');//fn--- String
    </script>

new绑定

  • 使用new创建一个对象
    第一步这个new会在类中生成一个空的对象(堆)
    第二步这个new中会生成一个this 这个this指向了这个堆
    第三步使用类生成的这个对象也会指向这个堆
    <script>
       function Person(name,age){
           this.name = name;
           this.age = age;
       }
       //函数类中 默认使用this 会生成一个空的对象 this指向了这个空的对象 
       //使用new创建了一个对象以后,里面的this指向空对象(堆) 把这个空对象(堆 )地址赋值给cc
       //此时 cc 和 函数类中的this指向了同一个堆
       let cc = new Person()
       cc.name = '陈城'; //通过对象名.属性给对象cc赋值 就相当于this对象中的属性同步增加
       cc.age = 21;
       console.log(cc);

       let gh = new Person('高涵',22);
       console.log(gh);
    </script>
   <script>
        function Hero(name,age){
            this.name = name;
            this.age = age;
        }
        let superMan = new Hero('超人',24);
        console.log(superMan);//得到一个superMan对象
    </script>
  • 监听器中的this
    <div id="box">点我</div>
    <script>
        //监听器中的this
        var box = document.getElementById('box');
        box.onclick = function(){
            console.log(this);//输出事件源  监听器中的this表示绑定了事件的元素
        }
    </script>

规则优先级

  • 默认规则的优先级最低
  • 显示绑定优先级高于隐式绑定
  • new绑定优先级高于隐式绑定
  • new绑定优先级高于隐式绑定
  • new绑定优先级高于bind
  • new绑定和call、apply是不允许同时使用
  • new绑定可以和bind一起使用,new绑定优先级更高
    <script>
        function fn(){
            console.log(this);//this先显示绑定为{name:'wc'} 
        }
        var gn = fn.bind({name:'wc'});
        gn();                 //返回新函数给gn 调用gn 
        var kn = new gn();    //new gn() this 绑定了新的对象

    </script>

忽略显示绑定

  • 如果在显示绑定中,我们传入一个null或者undefined,那么这个显示绑定会被忽略,使用默认规则
    <script>
        function fn() {
            console.log(this);
        }
        fn.apply({name:'wc'}) //{name:'wc'}

        fn.apply(null);//window
        fn.apply(undefined);//window
        var gn = fn.bind(null);
        gn();//window
    </script>

间接函数引用

    <script>
        var obj = {
            name:'wc',
            fn:function(){
                console.log(this);
            }
        }
        var obj2 = {
            name:'xq'
        };
        ;(obj2.gn = obj.fn)();//obj2.gn();
        ;(function(){console.log(this);}())
    </script>

箭头函数

    <script>
        var fn1 = function (a, b) {
            return a + b;
        }
        //箭头函数 将原本的function 省略 并且在小括号 后面增加 =>
        var fn2 = (a, b) => {
            return a + b;
        }
        console.log(fn2(1, 2));
    </script>
    <script>
        //箭头函数 如果函数形参只有一个 那么不仅可以省略 function 还可以省略小括号
        var fn3 = a => {
            return num * 10;
        }
        console.log(fn3(10));
    </script>
    <script>
        //箭头函数 如果函数体中只有一行语句 {}可以不写
        var fn = num=> console.log(num+100);
        fn(100);
    </script>
    <script>
        //箭头函数 如果函数体中只有一行代码 而且这行代码是return 语句 
        //{}可以不用写 return 也不用写
        var fn = num=> num*10;
        console.log(fn(1));
    </script>
  • 箭头函数 函数体只有一行代码返回了一个对象
    <script>
        var fn = function(){
            return {name:'wc'}
        }

        //转为箭头函数
        //此时会把return语句里对象{}当成函数里的{} 
        //解决:需要使用()把对象包起来
        var fn = ()=>({name:'wc'})
    </script>

箭头函数中this指向

    <script>
        //箭头函数中的this表示window
        var fn = ()=>{
            console.log(this);
        }
        fn.call('hello');//window
        fn.apply(null);//window
        fn.apply(undefined);//window  
    </script>
    <script>
        var fn = ()=>{
            //箭头函数的this都要向外找一级
            console.log(this);
        }
        fn();//window
        var obj = {name:'cc'};
        fn.call(obj);//window
    </script>
    <script>
        var obj = {
            name:'cc',
            fn:()=>{
                console.log(this);
            }
        }
        obj.fn();//window 因为箭头函数里的this表示window
    </script>

this练习题

    <script>
        let obj = {
            name:'cc',
            run:function(){
                console.log(this);
            }
        }
        let c = obj.run();//通过对象打点的方式调用对象内的方法 那么this 表示的是obj
                          //obj.run();是一个值 为undifined  把undefined赋值给了c
        c();//undefined()报错 c is not a function
    </script>
    <script>
        function fn1(){
            console.log(this);
        }
        let obj = {
            name:'cc',
            play:fn1//把外部函数 传入对象 此时 play指向了函数fn1()
        }
        obj.play();//对象打点调用对象内的方法 那么this指向了obj
    </script>
    <script>
        let name = 'xx'
        let obj = {
            name:'cc',
            running:function(name){
                console.log(this.name + '爱跑步');
            },
            codding:function(name){
                console.log(this.name + '爱代码');
            }
        }
        obj.running();//cc爱跑步
        obj.codding();//cc爱代码
    </script>
    <script>
        var obj ={
            name:'cc',
            fn:function(){
                console.log(this);
            }
        }
        var obj2 = {
            name:'gh',
            gn:obj.fn //把obj中的方法传给了gn
        }
        obj2.gn();//obj2调用gn 所以this 表示obj2
    </script>
<button id="box">点击</button>
<script>
    let btn = document.getElementById("box");
    function f() { 
        console.log(this);  
    }
   
    btn.onclick = f(); //点击box 没反应为空  把f()函数的返回值 给了btn.onclick 
    				   执行fn() 输出的是window
</script>
<button id="box">点击</button>
<script>
    let btn = document.getElementById("box");
    function f() {
        return function () {
            console.log(this)
        }
    }
    btn.onclick = f();  //返回内部函数给 btn.onclick 每点击一次 就执行一次函数
</script>
<script>
     let wc = {
        name: "wangcai",
        age: 100,
        eat: function () { 
            console.log("eat...")
            console.log(this); 
        }
    }
    wc.eat();//eat... wc
</script>
<script>
    let wc = {
        name: "wangcai",
        age: 100,
        eat: function () {
            console.log("eat...")
            console.log(this); 
        }
    }
    let mm = wc.eat;//mm指向内部函数
    mm(); //eat...  window 
</script>
<script>
    var num = 10;//60  //65
    var obj = {
        num: 20
    }
    obj.fn = (function (num) { //形参num20
        this.num = num * 3; //window.num = 20 * 3 = 60
        num++;              //num + 1
        console.log(num);   //21
        return function (n) { 
            this.num += n;// window.num = window.num + 5;
            num++;          //22
            console.log(num) //22
        }
    })(obj.num);  //实参20 传给function(num)

    var fn = obj.fn;
    fn(5)   //独立函数调用 this表示window //22
    console.log(window.num); //15
</script>
<script>
    var num = 10;//改为60
    var obj = {
        num: 20//30
    } 
    obj.fn = (function (num) {  //把obj中的20作为实参传给了 num
        this.num = num * 3;     //this.num 是window.num =10 IIFE中的this 指向window
        num++; //num为形参 实参obj.num = 20 给num 赋值后 num 为21 
        console.log(num);//21
        return function (n) {  //返回了function(n) 也就是 给obj添加了一个fn 这个fn指向了内部函数
            this.num += n;//30
            num++;  //num+1 自身没有num 找num  num 为父级的num 
            console.log(num)  //22
        }
    })(obj.num);

    obj.fn(10);
    console.log(num)//60
    console.log(window.num)//60
    console.log(obj.num)//30
</script>
<script>
    (function () {
        var a = 1;
        var obj = {
            a: 10,
            f: function () {
                a *= 2; //a 为 var a 而不是 obj 里的键a 键a只能对象名打点调或者 中括号
            }
        }
        obj.f()
        alert(obj.a + a);  //12
    })()
</script>
<script>
    (function () {
        var a = 1;
        var obj = {
            a: 10,
            f: function () {
                this.a *= 2;
                console.log(this.a)
            }
        }
        obj.f()//调用内部函数 20
    })()
</script>
<script>
    var name = "window";
    var Wangcai = {
        name: "Wangcai",
        show: function () {
            console.log(this.name);//window
        },
        f: function () {
            var fun = this.show;//fun 指向 show
            fun();  //执行show 独立函数调用
        }
    }
    Wangcai.f();
</script>
<script>
    var fullname = "language";
    var obj = {
        fullname: "javascript",
        props: {
            getFullName: function () { 
                return this.name; //this为obj.props
            }
        }
    }
    console.log(obj.props.getFullName()); //undifined
</script>
<script>
    var fullname = "language";
    var obj = {
        fullname: "javascript",
        props: {
            fullname: "hello",
            getFullName: function () {
                return this.fullname;
            }
        }
    }
    console.log(obj.props.getFullName());//hello 执行getFullName
</script>
<script>
    var fullname = "language";
    var obj = {
        fullname: "javascript",
        props: {
            fullname: "hello",
            getFullName: function () {
                return this.fullname;
            }
        }
    }
    let qq = obj.props.getFullName; //返回getFullName这个方法的地址
    console.log(qq());//调用内部函数 返回this.fullname 独立函数调用this为window
</script>
<script>
    let obj = {
        fn: (function () {
            console.log(this); //window  
            return function () {
                console.log(this);  
            }
        })()
    }
    obj.fn();//obj obj调用内层函数 
</script>
<script>
    let obj = {
        fn: (function () {
            console.log(this)
            return function () {
                console.log(this)
            }
        })()
    }
    let qq = obj.fn;//qq指向内部函数
    qq();  //独立函数调用
</script>
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值