学编程,来源栈;先学习,再交钱
当前系列: ES进阶 修改讲义
百变this

绝大多数情况下,函数的调用方式决定了this的值。


全局环境(在任何函数体外部)

console.log(this === window); // true
但是,module除外:module中全局环境里的this为undefined


函数中

取决于函数被谁调用,被如何调用……

  • 普通调用
            //'use strict';
            function hello() {
                console.log(this === window);
            }
            hello();
    非严格(window) v.s 严格(undefined)
  • 对象构造函数里的this:对象本身
  • 对象方法中(包括原型链上添加的,还包括getter/setter):指代对象
            var o = {
                hello: function () {
                    console.log(this === o);
                }
            }
            o.hello();
    注意:this只受“运行时”影响,不受定义时影响(和“文本作用域”区别)。这样的写法也是一样的:
            var o = {};
            o.hello = function () {
                console.log(this === o);
            };
            o.hello();
  • 事件处理函数:触发事件的DOM元素(复习:冒泡/捕获,target/currentTarget)。
    然而,注意“内联”事件处理函数。这样写是可以的:
        <button onclick="alert(this.tagName.toLowerCase())">
            Show this
        </button>
    但这样是不行的:
        <button onclick="show()">
            Show this
        </button>
        <script>
            function show() {
                //alert(this === window);
                alert(this.tagName.toLowerCase());
            }
        </script>
    需要改成:
        <button onclick="show(this)">
            Show this
        </button>
        <script>
            function show(that) {
                alert(that.tagName.toLowerCase());
            }
        </script>

同一个function,因为不同的调(使)用方式,就会导致不同的结果,这是非常“荒谬”的一件事情。

复杂多变的this会带来很多不便,比如:

        function Student() {
            this.age = 0;
            setInterval(function () {
                this.age++;
            }, 1000);
        }
        var wf = new Student();

@想一想@:为什么age没有增加?

之前的hack办法:

        function Student() {
            var that = this;
            this.age = 0;
            setInterval(function () {
                that.age++;
            }, 1000);
        }


箭头函数(=>)可以完美的解决这个问题。


箭头函数:=>

使用匿名函数的地方,就可以使用箭头函数(C#中Lambda表达式
function (x) {
    return x * x;
}
//等同于:
x => x * x;

传入参数:

  • 多个参数用()包裹,用,分隔
    (x, y) => {return x * y;}
  • 单个参数可以不加括号
    x => {return x * x;}
  • 没有参数使用空()
    () => { console.log('源栈欢迎您'); }

方法体:

  • 多行代码需要{}包裹
  • 单行代码不使用{}时,默认加一个返回(return),即:
    x => {return x * x;};
    等于:
    x => x * x;

注意:因为箭头函数中会生成this,即:箭头函数中的this只会被当做一个普通变量,所以this只会按作用域链向上继续寻找。

总体而言,箭头函数适用于方法(面向对象)。


Apply和Call

使用Function对象(function名称)的apply()和call(),可以直接调用方法。第一个参数即方法体内的this,其他参数就是Function对象的参数。

区别:

  • call(this, para1, para2, ...):参数列表
  • apply(this, [para1, para2, ...]):参数数组
        function hello(sname) {
            console.log(sname + this.age);
        }
        hello.call({ age: 37 }, '飞哥');



Bind

使用Function对象(function名称)的bind()方法,创建一个新的函数,在 bind() 被调用时,这个新函数的 this 被指定为 bind() 的第一个参数,而其余参数将作为新函数的参数,供调用时使用。

        let greet = hello.bind({ age: 37 }, '飞哥');


注意:如果第一参数不是object,就会被默认使用ToObject()转换成object,比如:7 => new Object(7)

7.toString()
new Object(7).toString()


作业

  1. 判断并证明事件处理函数中的this,等于target还是currentTarget
  2. 已有如下代码:
            var sname = "飞哥";
            var a = {
                sname: '老程',
                fn: function () {
                    console.log(this.sname);  
                }
            }
    请用不同的方式调用fn()函数,能分别打印出‘飞哥’和‘老程’
  3. 不改变上述代码,分别使用call()和apply(),打印出‘文轩’和‘两开花’
  4. 将fn()永久拷贝到showName(),始终打印‘源栈最棒!^_^’
学习笔记
源栈学历
今天学习不努力,明天努力找工作

作业

觉得很 ,不要忘记分享哟!

任何问题,都可以直接加 QQ群:273534701

在当前系列 ES进阶 中继续学习:

上一课: JavaScript:module

多快好省!前端后端,线上线下,名师精讲

  • 先学习,后付费;
  • 不满意,不要钱。
  • 编程培训班,我就选源栈

更多了解 加:

QQ群:273534701

答疑解惑,远程debug……

B站 源栈-小九 的直播间

写代码要保持微笑 (๑•̀ㅂ•́)و✧

公众号:源栈一起帮

二维码