JS中的this、apply、call

JS中的this总是指向一个对象,而具体指向哪个对象,是在运行时,基于函数的运行环境动态绑定的,而非函数被声明时的环境。

具体说说this的指向:
1.当函数作为对象的方法被调用时,this指向该对象

    var obj = {
        a: 1,
        getA: function(){
            alert(this === obj); // true
            alert(this.a); // 1
        }
    };
    obj.getA();

好像没有什么难理解的地方,待会再参考其他的书籍有没有补充的地方

2.作为普通函数调用
前面的一种形式是函数作对象的属性来调用,那么当函数不作为对象属性被调用时,此时的this总是指向全局对象,在浏览器里是window对象是全局对象,那么不在浏览器里全局对象是什么呢?

    window.name = "Stan";
    var getName = function(){
        alert(this.name); // Stan
    };
    getName();

这里把this.name直接写成name,没有区别,为什么?
另外把一个函数的引用赋值给一个变量,再去调用,结果和上面是一样的。像下面这样

    window.name = "Stan";
    var obj = {
        name: "Stanford",
        getName: function(){
            alert(this.name);
        }
    };
    var pointer = obj.getName;
    pointer(); // Stan

这里如果把this.name直接换成name,结果也是一样的。上面的为什么解决掉之后,在这里是一样的。

    window.name = "Stan";
    var obj = {
        name: "Stanford",
        getName: function(){
            alert(this.name);
        }
    };
    var pointer = obj.getName;
    pointer(); // Stan
    var obj2 ={
        name: "Dance",
        getName2: pointer
    };
    obj2.getName2(); // Dance

在前一个demo的基础上,把pointer赋值给了getName2,然后作为obj2对象的属性来调用getName2,此时结果是Dance,这里没有什么不好理解的,但是有意思的地方是,当把this.name换成name时,结果就是Stan.这里就可以看到加不加this前后的区别,但是为什么会这样,现在不知道。

在《JavaScript 编程全解》这本书中是这么解释的:

在Java中常常可以省略this,不用明确地写出。因为在查找方法内的名称时总是会在同一个类的
域名与方法名中搜索。而在JavaScript中就不能像这样省略this了。如果在上面的例子中将
this.name改写成name,它的含义将会变为全局变量name.

另外,如果作为普通函数来调用,结果又不一样的。像下面这样改动上面的代码:

    window.name = "Stan";
    var obj = {
        name: "Stanford",
        getName: function(){
            alert(this.name);
        }
    };
    var pointer = obj.getName;
    pointer(); // Stan
    var obj2 ={
        name: "Dance",
        getName2: pointer
    };
    var pointer2 = obj2.getName2;
    pointer2(); // Stan

无论是加不加this,此时的结果都是Stan,想想这是为什么?

现在总结一下:
如果是函数作为普通函数调用时,加与不加this的属性指向的都是全局对象中的属性;
如果函数作为对象的属性调用时,加与不加this的属性指向的结果是不一样的,加this的属性,此时的this指向调用该函数的对象,不加this的属性,此时this指向的是全局对象中的属性。

那么对于用this调用函数是一样的,在方法内部调用方法时,不加this时,则会在全局函数中搜索

    function func2(){
        alert("global function");
    }
    var obj = {
        name: "Stan",
        func1: function(){
            this.func2();
        },
        func2: function(){
            alert(this.name);
        }
    };
    obj.func1(); // Stan

若去掉this,结果会是global function。

3.在构造器中使用的this
当用new运算符调用函数时,该函数总会返回一个对象,在通常情况下,构造器里的this就指向返回的这个对象

        var myClass = function(){
            this.name = "Stan";
        };
        var obj = new myClass();
        alert(obj.name); // Stan

但是如果构造器显式的返回一个对象,那么此次返回的就是该对象,而不是我们期待的this.

        var myClass = function(){
            this.name = "Stan";
            return {
                name: "Dance"
            }
        };
        var obj = new myClass();
        alert(obj.name); // Dance

但是如果构造器不显式地返回任何数据,或者是返回一个非对象类型的数据,就不会造成上面的问题,如return “Dance”,结果还是Stan,而不是Dance.

4.apply 与 call 中的this引用
每个函数都包含两个非继承而来的方法:apply()和call(),这两个方法的用途都是在特定的作用域中调用函数

        window.color = "red";
        var col ={color : "blue"};
        function getCol(){
            alert(this.color);
        }
        getCol.call(this); // red
        getCol.call(window); // red
        getCol.call(col); // blue

可以看到使用call 后,函数赖以运行的作用域被扩充了。再看下面这个问题

        <body>中:
        <div id = "list">list</div>
        <js>中:
        document.getElementById('list').onclick = function(){
            alert(this.id); // list
            var func = function(){
                alert(this.id); // undefined
            };
            func();
        };

怎么办,用call 来修正函数内的this

        document.getElementById('list').onclick = function(){
            alert(this.id); // list
            var func = function(){
                alert(this.id); // undefined
            };
            func.call(this);
        };

func.call()就好比前面的obj.getName(),作为函数的属性来调用,而不是作为普通函数来调用,此时的this就是指向了内部的id,而不再是全局的id。

另外,apply与call的作用效果是一样的,区别仅在于接收的第二个参数不同,前者是接收一个参数数组,可以是Array的实例,也可以是arguments对象。而二者的第一个参数都是在其中运行函数的作用域。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值