JavaScript高级 | 第三章 深入this

在方法中,this 表示该方法所属的对象;如果单独使用,this 表示全局对象;在函数中,this 表示全局对象;在函数中,在严格模式下,this 是未定义的(undefined);在事件中,this 表示接收事件的元素

this的绑定规则:

  • 默认绑定
  • 隐式绑定
  • 显示绑定
  • new绑定

3.1 默认绑定

独立函数调用就是所谓的默认绑定,独立函数调用我们可以理解为函数没有绑定在某个对象上进行调用

<script>
    function fn() {
        console.log(this);
    }
    // 独立的函数调用
    // 在浏览器中This表示window
    fn();
</script>
<script>
    function fn() {
        console.log(this);
    }
    function an() {
        console.log(this);
        fn();
    }
    function kn() {
        an();
        console.log(this);
    }
    kn();  // 输出三个window,因为都是独立函数调用
</script>
<script>
    var obj = {
        name: 'wc',
        fn: function () {
            console.log(this);
        }
    }
    obj.fn(); // {name: 'wc', fn: ƒ}
    var gn = obj.fn;
    gn();     // window
</script>

3.2 隐式绑定

通过某个对象进行调用,也就是它的调用位置中,是通过某个对象发起的函数调用。

<script>
    function fn() {
        console.log(this);
    }
    var obj = {
        name: 'wc',
        fn: fn
    }
    // fn中的this是谁呢?就看点前面是谁
    obj.fn();  // {name: 'wc', fn: ƒ}
</script>
<script>
    var obj = {
        name: 'wc',
        fn: function () {
            console.log(this);
        }
    }
    var obj2 = {
        name: 'xq',
        gn: obj.fn  // 注意这里函数没有执行,所以传入的是一个地址
    }
    obj2.gn() // obj2
</script>

可以将上面代码进行一个变形:

<script>
    var obj = {
        name: 'wc',
        fn: function () {
            return this;
        }
    }
    var obj2 = {
        name: 'xq',
        gn: obj.fn()  // 这里函数执行了,所以gn对应的是obj的值
    }
    console.log(obj2.gn)  // obj
    obj2.gn() // 这里会报错,因为gn不是函数
</script>

3.3 显示绑定

隐式绑定有一个前提条件:

​ 必须在调用对象的内部有一个对函数的引用(比如一个属性),如果没有这样的引用,在进行调用时,会有找不到函数的错误,正是通过这个引用,间接的将this绑定到了这个对象上。

如果我们不希望在对象内部包含整个函数的引用,同时又希望在整个对象上进行强制调用,该怎么做呢?

  • JavaScript的所有函数都可以使用call和apply方法(这个和prototype有关)

    • 它们的第一个参数是相同的,后面的参数,apply为数组,call是单独参数输入。
  • 这两个函数的第一个参数都要求是一个对象,调用这个函数时,会将this绑定在这个传入的对象上。

因为上面的过程,我们明确绑定了this的指向,所以称为显示绑定。

<script>
    function fn(a, b) {
        console.log(this);
        console.log(a + b);
    }
    fn(1, 2); // window  3
    
    let obj = { name: 'wc' }
    
    // call做了什么?
    // 1)让fn执行   2)改变函数中this的指向
    // 第二个函数开始传递的是实参
    fn.call(obj, 1, 2);  // obj 3
    
    // apply就是实参使用数组传入
    fn.apply(obj, [1, 2]);  // obj 3
    
    // bind的作用:
    // 1)只会改变函数中this的指向,不会让函数执行
    // 2)返回一个改变了this指向的新函数
    let newFn = fn.bind(obj,1,2);
    newFn();  // 这个实参也可以写到这里
</script>

如果call、apply和bind后面跟的是基本数据类型,如下:

<script>
    function fn() {
        console.log('fn...');
        console.log(this);
    }
    fn.call('hello');   // 把'hello'封装成一个新对象
    fn.call(undefined)  // this指向window
    fn.call(null)       // this指向window
</script>

3.4 new绑定

function Fn() {
    // new做了什么
    // 1)在类中创建一个对象
    // 2)让类中的this绑定到对象
    // 3)返回对象
    this.name = 'wc';
    this.age = 18
}
let f1 = new Fn();
console.log(f1); // Fn {name: 'wc', age: 18}

3.5 内置函数中的this绑定

<script>
    setInterval(function () {
        console.log(this); // window
    }, 2000)
</script>

事件中的this:

<button>点击</button>
<script>
    let btn = document.querySelector('button');
    btn.onclick = function () {
    	console.log(this);  // button
    }
</script>

数组方法中的this:

<script>
    let name = ['wc', 'nih', 'jll'];
    
    name.forEach(function () {
        console.log(this);  // window
    });
    
    name.forEach(function () {
        console.log(this);  // {name: '666'}
    }, { name: '666' });
</script>

3.6 优先级

显示绑定优先级高于隐式绑定

<script>
    let obj = {
        name: 'wc',
        fn: function () {
            console.log(this);
        }
    }
    let newObj = { name: 'xq' }
    // 显示绑定优先于隐式绑定
    obj.fn.call(newObj)   // this指向newObj
</script>

new绑定优先级高于隐式绑定

<script>
    let obj = {
        name: 'wc',
        fn: function () {
            console.log(this);
        }
    }
    let res = new obj.fn()  // fn {}
    console.log(res);      // fn {}
</script>

new绑定优先级高于bind绑定,注意bind返回是函数,所以可以new,call和apply返回的是函数执行结果,不能new。

<script>
    function fn() {
        console.log(this);
    }
    var gn = fn.bind({ name: 'wc' })
    let kn = new gn();   // fn  {}
</script>

3.7 特殊情况

3.7.1 忽略显示绑定

当显示绑定的参数为null和undefined的时候,忽略显示绑定

<script>
    function fn() {
        console.log(this);
    }
    fn.call({ name: 'wc' }) // { name: 'wc' }
    fn.call(null)        // window
    fn.call(undefined)   // window
</script>

3.7.2 间接函数引用

<script>
    var obj = {
        name: 'wc',
        fn: function () {
            console.log(this);
        }
    }
    var obj2 = {
        name: 'xq'
    };
    // obj2.gn = obj.fn;
    // obj.gn();     // obj2  这里是隐式绑定
    
    (obj2.gn = obj.fn)();    // 立即执行函数,这里this 表示window
</script>

3.8 箭头函数的this

<script>
    var fn = () => {
        // 箭头函数中的this需要向外找一级
        console.log(this);
    }
    var obj = { name: 'wc' };
    fn.call(obj)  // window
</script>
<script>
    var obj = {
        name: 'wc',
        fn: () => {
            console.log(this);
        }
    };
    obj.fn()  // window
</script>

3.9 练习题

<button>点击</button>
<script>
    let btn = document.querySelector('button');
    function f() {
        console.log(this); 
    }
    btn.onclick = f();  // window 这里f()是直接执行,无返回值,相当于undefined
</script>
<script>
    let wc = {
        name: 'wc',
        age: 100,
        eat: function () {
            console.log('eat...');
            console.log(this);
        }
    }
    let mm = wc.eat;
    mm();  // eat...   window
</script>
<script>
    var num = 10;
    var obj = { num: 20 }
    obj.fn = (function (num) {
        this.num = num * 3;
        num++;
        console.log(num);
        return function (n) {
            this.num += n;
            num++;
            console.log(num);
        }
    })(obj.num)  // IIFE,输出21
    var fn = obj.fn;
    fn(5);  // 这里是独立函数调用,所以this是window,输出22
    console.log(window.num);  // 65
    console.log(obj.num);     // 20
</script>

更改一下上面的代码就不是独立函数调用了

<script>
    var num = 10;
    var obj = { num: 20 }
    obj.fn = (function (num) {
        this.num = num * 3;
        num++;
        console.log(num);
        return function (n) {
            this.num += n;
            num++;
            console.log(num);
        }
    })(obj.num)  // IIFE,输出21


    obj.fn(10);  // 隐式调用,这里的this是obj
    // 但是num仍然是闭包的num,所以输出22
    console.log(num);  // 60
    console.log(obj.num);  // 30
</script>
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值