<!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、函数调用位置2function foo(){console.log(this.a);}var a = 2;//2foo();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();//2setTimeout(bar,1000);//2bar.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绑定到objvar arr = [1,2,3].forEach(foo,obj);//console.log(arr);new 绑定使用new调用函数,会执行以下操作1、创建(或者说构造)一个全新的对象2、这个新对象会被执行[[Protoptye]]连接3、这个新的对象会绑定到函数调用的this4、如果函数没有返回其他对象,那么new表达式中的函数调用会自动返回这个新的对象function foo(a){this.a = a;}var bar = new foo(2);console.log(bar.a);2.3优先级默认绑定 < 隐式绑定 < 显式绑定 < new ....2.4被忽略的thisfunction 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//箭头函数,是根据为层(函数或者全局)作用域来决定thisvar 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(); //awesomesetTimeout(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,因此会输出2function 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 foofor(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 functionvar 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);// 10for(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、evalfunction 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; 读取的是局部变量3function foo(str){"use strict";eval(str);console.log(a);}foo("var a = 2");//a si not defined*/</script>
</body></html>