你不知道的javaScript笔记(2)

this和对象原型

this是一个很特别的关键字,被自动定义在所有函数的作用域中

// foo.count 0,字面理解是错误的

          function foo(num) {
              console.log("foo:"+ num);
              this.count++;
          }
          foo.count = 0;
          var i;
          for(i=0;i<10;i++){
              if(i>5){
                  foo(i)
              }
          }
          console.log(foo.count)  //0

 // 使用词法作用域解决问题

        function foo(num) {
            console.log("foo:"+ num);
            data.count++;
        }    

        var data = {
              count:0
        };
        var i;
        for(i=0;i<10;i++){
            if(i>5){
                foo(i)
            }
        }
        console.log(data.count);  // 4

// foo标识符来替代this来引用函数对象,回避了this 的问题,完全依赖于变量foo的词法作用域。

        function foo(num) {
            console.log("foo:"+ num);
            foo.count++;
        }
        foo.count = 0
        var i;
        for(i=0;i<10;i++){
            if(i>5){
                foo(i)
            }
        }
        console.log(foo.count) //4

    //强制this 指向foo函数对象

        function foo(num) {
              console.log("foo:"+num);
              this.count++
         }
         foo.count = 0;
         var i;
         for(i=0; i< 10; i++){
              if(i>5){
                  foo.call(foo,i);
              }
         }
        console.log(foo.count)  //4

 

this是在运行是 绑定的,并不是在编写时绑定的,它的上下文取决于函数调用时的各种条件,this的绑定和和函数声明的位置没有任何关系,只取决于函数调用的方式。

this全面解析

调用栈与调用位置

        function baz(){
            //当前调用栈是:baz
            // 因此,当前的调用中位置是全局作用域
            console.log("baz");
            bar(); // <--bar的调用位置
        }
        function bar(){
          //当前的调用栈是: baz-> bar
          // 因此,当前调用位置在baz
          console.log("bar);
          foo(); // <-- foo 的调用位置
        }

        function foo(){
          //当前的调用栈是: baz-> bar->foo
          // 因此,当前调用位置在bar
          console.log("foo");
        }
        baz(); // <-- baz 的调用位置

只有运行在非strict mode 下,默认绑定才能绑定到全局对象。

对象属性引用链中只有最顶层或者说最后一层灰影响调用位置。

        function foo() {
          console.log(this.a);

        }

        var obj2 = {
            a: 42,
            foo:foo
        };

        var obj1 = {
            a:2,
            obj2: obj2
        };

        obj1.obj2.foo(); // 42

 

硬绑定的典型应用场景就是创建一个包裹函数,传入所有的函数并返回接收到的所有的值。

          function foo(something){
              console.log(this.a,something);
              return this.a + something;
          };

          var obj = {
              a:2
          };

          var bar = function() {
            return foo.apply(obj,arguments);
          };

          var b = bar(3) ; // 2 3
          console.log(b)  // 5

另一种方法是创建一个i可以重复使用的辅助函数

          function foo(something){
              console.log(this.a, something);
              return this.a + something;
          }

          // 简单的辅助绑定函数
          function bind(fn,obj){
            return function(){
              return fn.apply(obj,arguments);
            };
          }

          var obj = {
             a:2
          }

          var bar = bind(foo,obj);
          var b = bar(3); // 2 3
          console.log(b) // 5

ES5 中提供了内置的方法 Function.prototype.bind,  bind(..) 会返回一个硬编码的新函数,它会

 

把参数设置为this的上下文并调用原始函数。

        function foo(something){
          console.log(this.a, something);
          return this.a + something;
        }
        var obj = {
            a:2
        }

        var bar = foo.bind(obj);
        var b = bar(3); // 3 5
        console.log(b) // 5

API 调用的 上下文

        function foo(el){
          console.log(el,this.id);
       }
       var obj = {  
          id: "awesome'
       }

      // 调用 foo(..)时把this 绑定到obj
      [1,2,3].forEach(foo,obj);
      // 1 awesome 2 awesome 3 awesome

 

new可以影响函数调用时this 绑定行为的方法。

        function foo(a){
            this.a = a;
         }
       var  bar = new foo(2);
       console.log(bar.a); // 2

判断this

1.函数是否在new 中调用(new 绑定)? 如果是的话this 绑定的是新创建的对象。

var bar = new foo();

2.函数是否通过call , apply (显示绑定) 或者硬绑定调用? 如果是的话,this的绑定时指定的对象。

va bar = foo.call(obj2)

3.函数是否在某个上下文对象中调用(隐式绑定) ? 如果是的话,this 的绑定时在那个上下文。

var bar = obj1.foo()

4.如果都不是的话,使用默认绑定。如果在严格模式下,就绑定到undefined,否则绑定到全局对象上。  

var bar = foo();

软绑定

        function foo(){
          console.log("name:" + this.name);
        }

        var obj = {name: "obj"},
        obj2 = {name: "obj2"},
        obj3 = {name: "obj3"},
        obj3 = {name: "obj3"};

        var foo0BJ = foo.softBind(obj);
        foo0BJ();  // name:obj
        obj2.foo = foo.softBind(obj);

        obj2.foo(); // name:obj3 <--看!
        setTimeout(obj2.foo,10);
        // name:obj <--- 应用了软绑定

 

 

posted @ 2017-06-28 17:12  柠檬先生  阅读(286)  评论(0编辑  收藏  举报