你不知道的javascript(上卷)----读书笔记

<!DOCTYPE html>
<html>

<head>
    <meta charset="utf-8">
    <title>你不知道的javascript(上卷)</title>
</head>

<body>
    <script type="text/javascript">

    /*
     //9、this 的全面解析
     this的绑定和函数声明位置没有任何关系,之取决于函数的调用方式
     在理解this的绑定过程之前,首先理解调用位置:调用位置就是在代码中被调用的位置(问不是声明位置,)。只有仔细分析调用位置才能回答这个问题:这个this到底引用的是什么

     通常来说,寻找调用位置就是寻找“函数被调用的位置”

     2.1、函数调用位置
    function baz(){
      console.log("baz");  
      bar();  //bar的调用位置
    }

    function bar(){
       console.log("bar");
       foo();//foo的调用位置
    }
    function foo(){
      console.log("foo");
    }

    baz();//baz的调用位置

     b、函数调用位置2
    function foo(){
      console.log(this.a);
    }
    var a = 2;//2
    foo();
    function foo(){
      "use strict";
      console.log(this.a);  //报错,严格模式下,this不会默认绑定给window
    }

    var a = 2;

    foo();

    function foo(){
      console.log(this.a);
    }
    var a = 2;
    (function(){
       "use strict";
       foo(); //2
    })();

    //三种情况下,只要函数执行不是执行在严格模式下,默认绑定才会绑定到全局上
    2.2、绑定规则

    2.2.1默认绑定
    function foo(){
       console.log(this.a);
    }
    var a = 2;
    foo();//2
    //非严格模式下,this默认绑定在window下
     
     function foo(){
      "use strict";
       console.log(this.a);
    }
    var a = 2;
    foo();// this is not defined;
    //严格模式下不能将全局对象默认绑定,因此this会绑定到undefined上

    function foo(){
        console.log(this.a);
    }
    var  a = 2;
    (function(){
      "use strict";
      foo();//2 
    })()

    //严格模式下的调用不影响默认绑定

    2.2.2隐式绑定
    function foo(){
        console.log(this.a);
    }
    var obj = {
         a : 2,
         foo : foo
    }

    obj.foo();

    //无论是直接在obj中定义还是先定义在添加为引用属性,这个函数严格来说不属于obj对象,
    //调用位置会使得obj上下文来引用函数,因此你可以说函数被调用时obj对象“拥有”或者“包含”函数

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

    var obj2 = {
        a : 42,
        foo : foo
    }
    var obj1 = {
         a : 2,
         obj2 : obj2
    }

    obj1.obj2.foo();//42
    //对象属性引用链中只有上一层或者说最后一层在调用位置中起作用。

    //隐式丢失
    function foo(){
      console.log(this.a);
    }
    var obj = {
       a : 2,
       foo : foo
    }
    var bar = obj.foo;//函数别名
    var a = "oops,global";
    bar();//"oops,global";
    

    2.2.3显示绑定

    function foo(){
        console.log(this.a);
    }
    var obj = {
      a : 2,
    }
    foo.call(obj);//2
    //通过foo.call(..),我们可以调用foo时强制把他的this绑定到obj上

    //硬绑定 
    function foo(){
        console.log(this.a);
    }
    var obj = {
         a : 2,
    }
    
    var bar = function(){
           foo.call(obj);
    }

    bar();//2
    setTimeout(bar,1000);//2
    bar.call(window);//2
    //硬绑定的bar不可能在修改他的this
    //创建函数bar(),并且在内部手动调用foo.call(obj),
    //因此强制把foo的this绑定到obj,无论后面我们如何调用到bar(),
    //他总会手动在obj上调用foo,这种绑定是一种显性绑定,因此我们称之为硬绑定
   

   //API调用的‘上下文’



    
   function foo(el){
       console.log(el,this.id); //1 awesome 2 awesome 3 awesome
   }
   var obj = {
       id : "awesome",
   }
   //调用foo()时把this绑定到obj
   var arr = [1,2,3].forEach(foo,obj);
   //console.log(arr);
    

    new 绑定
    使用new调用函数,会执行以下操作
    1、创建(或者说构造)一个全新的对象
    2、这个新对象会被执行[[Protoptye]]连接
    3、这个新的对象会绑定到函数调用的this
    4、如果函数没有返回其他对象,那么new表达式中的函数调用会自动返回这个新的对象

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

    2.3优先级
    默认绑定 < 隐式绑定 < 显式绑定 < new 
    .
    .
    .
    .

   2.4被忽略的this
   function foo(){
     console.log(this.a);
   }
   var a = 2;
   foo.call(null);//2
   //call 参数为null或者undefined的时候会默认是全局this

    柯里化。。。。



    */




    /*
      8、this词法 
	    var foo = a =>{  
	    	console.log(a);
	    }
	    foo(2); //2

     //箭头函数,是根据为层(函数或者全局)作用域来决定this


	    var foo1 = function(a){
	    	console.log(a);
	    }
	    foo1(2);
	    // 两种声明是等效的


	    var obj = {
	    	id : "awesome",
	    	cool:function coolFn(){
	    		console.log(this.id)
	    	}
	    };
	    var id = "not awesome";

	    obj.cool(); //awesome

	    setTimeout(obj.cool,100); // not awesome 
	    // setTimeout 导致 cool()函数丢失了同this之间的绑定

	    //解决方案
	    var obj = {
	    	count : 0,
	    	cool: function coolFn(){
	    		var self = this;
	    		if(self.count<1){
	    			setTimeout(function timer(){
	    				self.count++;
	    				console.log("awesome");
	    			},100);
	    		}
	    	}
	    }
	    obj.cool(); // awesome
    */

    /*


     //7、动态作用域
    function foo(){
    	console.log(a);
    }
    function bar(){
    	var a = 3;
    	foo();
    }
    var a = 2;
    bar();  //2  输出结果是2,词法作用域让foo()中的a通过RHS引用到了全局
            //作用域中的a,因此会输出2
   function foo(){
    	console.log(a); //a is not defined
    }
    function bar(){
    	var a = 3;
    	foo();
    }
    bar();


    function foo(){
    	var a  = 3;
    	console.log(a); //引用的是局部变量a的值
    }

    var a = 1;
    foo();// 3
    */





    /*
     //5、闭包作用域
     function foo(){
    	var a = 2;
    	function bar(){
    		console.log(a);
    	}
    	return bar;
    }

    var baz = foo();
    baz(); //2 foo() 的返回值是bar()函数,所以通过baz()可以执行这个函数
   function foo(){
   	var a = 2;
   	function baz(){
   		console.log(a);
   	}
   	bar(baz);
   } 

   function bar(fn){
      	fn();  
   }

   foo();//2  foo
    for(var i = 0;i<=5;i++){
    	(function(){
    		var j = i;
    		setTimeout(function time(){
    			console.log(j);  // 每100毫秒输出一个数,分别输出0,1,2,3,4
    		},j*100);
    	})()
    }
    
    for(var i = 0;i<=5;i++){
    	(function(j){
    		setTimeout(function time(){
    			console.log(j); // 每100毫秒输出一个数,分别输出0,1,2,3,4
    		},j*100);
    	})(i)
    }
     for(var i = 1;i<=5;i++){
    	(function(){
    		setTimeout(function time(){
    			console.log(i); // 每100毫秒输出一个数,分别输出6,6,6,6,6
    		},i*100);
    	})()
    }
    */

   /*
   //4、提升 --先编译在执行
    a = 2;
    var a;
    console.log(a);//a  因为var声明的变量存在提升

    console.log(b); //undefined var声明存在提升,赋值不存在提升,所以b存在但是没赋值
    var b = 2;
    foo();  //函数竟然可以执行,说明函数声明也提升了
    function foo(){
    	console.log(a); //undefined , 声明提升了,不存在赋值提升
    	var a = 2;
    }
    foo(); //1  
    var foo;
    function foo(){
    	console.log(1);
    }
    foo = function(){
    	console.log(2)
    }
     
     //引擎编译如下
    function foo(){
    	console.log(1);
    }
     foo(); //1  
    var foo = function(){
    	console.log(2)
    }
    foo(); //3
    //var foo 尽管出现在在function之前,但是由于是重复声明,所以被忽略掉
    //函数声明会被提升到普通变量之前
    function foo(){
    	console.log(1);
    }
    var foo = function(){
    	console.log(2);
    }

    function foo(){
    	console.log(3);
    }
    foo();  // foo is not a function
    var a = true;
    if(a){
    	function foo(){
    		console.log("A");
    	}
    }
    else{
    	function foo(){
    		console.log("B");
    	}
    }
    */
     


     /*
     //3.4.3、let和var的区别
     for(var i = 0;i<10;i++){
     }
     console.log(i);// 10

     for(let j=0;j<10;j++){
     }
     console.log(j);// j is not defined
     //for循环结束后i并没有被销毁,导致全局污染
     */


     /*
    //3.3.2、立即执行函数:抱在一对括号内
    var a = 2;
    (function foo(){
    	var a = 3;
    	console.log(a); //3
    })();

    console.log(a);// 2
     */



      /*
       //块级作用域,函数作用域
       //3.2、规避冲突
      */
      /*
      function foo(){
      	function bar(a){
      		i = 3;
      		console.log(a+i);
      	}
      	for(var i = 0;i<10;i++){
      		bar(i*2);
      	}
      }

      foo();//死循环,bar中的i覆盖了for循环中的i导致死循环
      */


       /*
       //2.2.1、eval
       function foo(str,a){ 
             eval(str);
             console.log(a,b); //4
       }
       var b = 2;
       var result = foo("var b = 3;",1);
       console.log("result:",result); //undefined???默认严格模式?
       //书上的结果是1,3因为eval(str)== var  b = 3; 读取的是局部变量3
       function foo(str){
         "use strict";
         eval(str);
         console.log(a);
       }

       foo("var a = 2");//a si not defined
       */


    </script>
</body>

</html>

  

原文地址:https://www.cnblogs.com/SunlikeLWL/p/7376458.html