<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>函数--this使用详情</title>
</head>
<body>
    <script>
        /*
            javascript函数--this使用详情:
                面向对象语言中 this 表示当前对象的一个引用。
                    但在 JavaScript 中 this 不是固定不变的,它会随着执行环境的改变而改变。
                    在方法中,this 表示该方法所属的对象。
                    如果单独使用,this 表示全局对象。
                    在函数中,this 表示全局对象。
                    在函数中,在严格模式下,this 是未定义的(undefined)。
                    在事件中,this 表示接收事件的元素。
                类似 call() 和 apply() 方法可以将 this 引用到任何对象。
                在绝大多数情况下,函数的调用方式决定了 this 的值(运行时绑定)。
                ES2015 引入了箭头函数,箭头函数不提供自身的 this 绑定(this 的值将保持为闭合词法上下文的值)。
        */
        /*
            1.this指向全局对象
            2.this指向所属对象
            3.this.指向对象实例
            4.this指向call()函数、apply()、bind()函数调用后重新绑定的对象。
            5.箭头函数
        */

        //1.this指向全局对象或undefined
            /*
                当函数没有所属对象而直接调用时,this指向的是全局对象。

                在函数中,在严格模式下,this 是未定义的(undefined)。
            */
           var value=10;
           var obj ={
               value:100,
               method:function(){
                   var foo=function(){
                       console.log(this.value);//10
                       console.log(this);//Window对象
                   };
                   foo();
                   return this.value;
               }
           };
           obj.method();

           //严格模式
           var obj1 ={
               method:function(){
                   var foo=function(){
                    "use strict"; // 这里是严格模式
                       console.log(this);//undefined
                   };
                   foo();
                   return this.value;
               }
           };
           obj1.method();
           

        //2.this指向所属对象
           /*
                this指向调用对象
           */
          //沿用上函数
          /*obj.method()的返回值是this.value,method()的调用体为obj此时this指向obj,输出obj.value,输出100*/

          console.log(obj.method());//100

        //3.this.指向对象实例
           /*
                当通过new操作符调用构造函数生成对象的实例时,this指向该实例。
           */

          //全局变量
          var number=10;
          function Person(){
              //复写全局变量
              number=20;
              //实例变量
              this.number=30;
          }
          //原型函数
          Person.prototype.getNumber=function(){
              return this.number;
          };
          //通过new操作符获取对象的实例
          var p=new Person();
          console.log(p.getNumber());//30


        //4.this指向call()函数、apply()、bind()函数调用后重新绑定的对象。(后有详解)
          //4.1 call、apply()

          function add(c, d) {
            return this.a + this.b + c + d;
            }

            var o = {a: 1, b: 3};

            // 第一个参数是用作“this”的对象
            // 其余参数用作函数的参数
            add.call(o, 5, 7); // 16

            // 第一个参数是用作“this”的对象
            // 第二个参数是一个数组,数组中的两个成员用作函数参数
            add.apply(o, [10, 20]); // 34

          //4.2 bind
            /*
                ECMAScript 5 引入了 Function.prototype.bind()。
                调用f.bind(someObject)会创建一个与f具有相同函数体和作用域的函数,
                但是在这个新函数中,this将永久地被绑定到了bind的第一个参数,无论这个函数是如何被调用的。
            */
            function f(){
            return this.a;
            }

            var g = f.bind({a:"azerty"});
            console.log(g()); // azerty

            var h = g.bind({a:'yoo'}); // bind只生效一次!
            console.log(h()); // azerty

            var o = {a:37, f:f, g:g, h:h};
            console.log(o.a, o.f(), o.g(), o.h()); // 37, 37, azerty, azerty

        //5.箭头函数
            /*
                在箭头函数中,this与封闭词法环境的this保持一致。
                在全局代码中,它将被设置为全局对象
            */
            var globalObject = this;
            var foo = (() => this);
            console.log(foo() === globalObject); // true

    </script>
</body>
</html>