├── pics ├── timg.jpg └── top.jpg ├── README.md ├── this └── README.md ├── proto └── README.MD └── call-apply └── README.MD /pics/timg.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TerryBeanX2/Dive-Into-JS/HEAD/pics/timg.jpg -------------------------------------------------------------------------------- /pics/top.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TerryBeanX2/Dive-Into-JS/HEAD/pics/top.jpg -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # 走心的一系列JS基础>进阶的大白话教程 2 | 3 | 4 | 5 | #### JS大法好,JS在手,天下我有,信JS,得永生。
6 | 想必每一个前端攻城狮都知道,区分能力的最重要的指标就是对JavaScript的掌握程度,
7 | 在热门框架满天飞,自动化越来越被推崇的今天,
8 | 好多开发者都失其本心,盲目去追求技术的广度而忽略本身羸弱的JS功底,
9 | 殊不知你若是对JS掌握到位,任何框架神马的新技术,都是信手拈来的。
10 | 11 | 通过长期的浸淫于网上的JS领域,我发现除了少数布道者能讲得通俗易懂(比如阮一峰老师、廖雪峰老师),
12 | 而其他大多数的进阶教程,看似美食但难以下咽,
13 | 原因就是很多教程都忽略了“马上要懂而又没懂就差那么一丢丢”的开发者的主观感受,
14 | 要么就是一股脑塞给你一堆知识点,要么就是有点艰涩,
15 | 导致学习这些教程后,知识粘度不够,马上就忘了,或者压根就懒得理解。
16 | 17 | 而我开这一解读栏的目的,就是在力所能及的知识范围内,
18 | 帮助那些“马上要懂而又没懂就差那么一丢丢”的开发者们,在某些个具体化的知识点上(仅仅是某些个),
19 | 用最简单的白话解读出来,包括我自己的理解小技巧。
20 | 当然这只是我的理想化,也许教程写出来很烂,甚至偏离了初衷,但只要帮助了哪怕只有一个人,这个教程就不白写。
21 | 22 | #### 本着对技术负责的态度,任何纠正/疑问,请在[issues](https://github.com/TerryBeanX2/Dive-Into-JS/issues)里提出,我会及时修正/回答。 23 | #### 一定要把每个例子代码都拷贝到你的运行环境中边看结果边理解,不然学习效果减半,或者没效果。 24 | 25 | [1、理解this指向的小技巧](https://github.com/TerryBeanX2/Dive-Into-JS/tree/master/this)
26 | [2、巧妙理解call、apply](https://github.com/TerryBeanX2/Dive-Into-JS/tree/master/call-apply)
27 | [3、不得不提的原型/原型链](https://github.com/TerryBeanX2/Dive-Into-JS/tree/master/proto)
28 | 4、占位,视情况填坑
29 | +、...
30 | 31 | #### 教程之间紧密联系,不懂得地方不要失去耐心,来回多看看。 32 | #### 如果帮到你,给我一个Star吧,我会继续努力写下去~ 33 | -------------------------------------------------------------------------------- /this/README.md: -------------------------------------------------------------------------------- 1 | # 理解JS中this指向的小技巧 2 | 3 | 在看他人写的js文件时,会看到许多this,对this不熟悉的人很容易蒙圈,这里就说明如何用最简单的方法去找this指向谁。 4 | 5 | #### 切记!这里说的找“点”大法中的“.”,都是在调用的语句里找,本教程的全局对象为window! 6 | 7 | ## 1、找“点”大法:你找不到“.”的函数调用,this指向一般是window: 8 | 9 | ###### 声明 10 | ```javascript 11 | function foo(){ 12 | console.log(this) 13 | } 14 | ``` 15 | ###### 调用 16 | ```javascript 17 | foo();   //自己去运行代码看this指向谁 18 | //脑补: 19 | window.foo();   //自己去运行代码看this指向谁 20 | ``` 21 | ###### 解读 22 | 23 | 不用怀疑,也不用犹豫,找不到任何“.”,this指向window。 24 | 以后见到直接调用的foo,自动脑补成window.foo(),因为在这种情况下,这两种写法是一样的。 25 | 26 | ##### ㈠当函数/匿名函数作为参数时,你是找不到“.”的,这种情况下,函数内部的this指向window。 27 | ###### 声明&调用 28 | ```javascript 29 | function foo(callback){ 30 |    callback(); //调用其实在这里,你是找不到“.”的 31 | } 32 | foo(function(){ 33 | console.log(this); //自己去运行代码看this指向谁 34 | }) 35 | ``` 36 | ###### 解读 37 | 38 | 这个例子就是,匿名函数内部打印了this,它作为参数,内部的this指向window。 39 | 40 | ## 2、找“点”大法:有“.”的函数调用,this指向一般是最后一个“.”左侧的那个对象: 41 | ##### 2-1、调用语句里只能找到一个“.”:
42 | 43 | ###### 声明 44 | ```javascript 45 | var bar = {name:'我是bar'}; 46 | bar.foo = function(){ 47 | console.log(this) 48 | }; 49 | ``` 50 | ###### 调用 51 | ```javascript 52 | bar.foo(); //自己去运行代码看this指向谁 53 | ``` 54 | ###### 解读 55 | 56 | 这个例子,我们找到了“.”的存在,“.”左侧是bar,指向是bar。 57 | 58 | ##### 2-2、调用语句里能找到多个“.”:
59 | 60 | ###### 声明 61 | ```javascript 62 | var obj = {name:'我是obj'}; 63 | obj.bar = {name:'我是bar'}; 64 | obj.bar.foo = function(){ 65 | console.log(this) 66 | }; 67 | 68 | ``` 69 | ###### 调用 70 | ```javascript 71 | obj.bar.foo(); //自己去运行代码看this指向谁 72 | ``` 73 | ###### 解读 74 | 75 | 这个例子,我们找到了俩“.”,最后一个“.”左侧的对象是bar,那么this指向就是bar。 76 | 77 | ##### ㈡如果发现你找到的“.”左侧是prototype,那么再往左找一个“.”,这个“.”左侧的对象是this指向。原理在[不得不提的原型/原型链](https://github.com/TerryBeanX2/Dive-Into-JS/tree/master/proto)中给出。 78 | 79 | 80 | ## 3、面向对象中的this: 81 | 对面向对象不够了解的同学,请尽量读懂[不得不提的原型/原型链](https://github.com/TerryBeanX2/Dive-Into-JS/tree/master/proto)
82 | 阅读本文,就先专注于找this指向吧! 83 | 84 | ###### 声明 85 | ```javascript 86 | function Foo(){ 87 | this.name = 'hahaha' 88 | console.log(this); 89 | } 90 | Foo.prototype.bar = function(){ 91 | console.log(this); 92 | } 93 | Foo.prototype.funcWithParam = function(fn){ 94 | fn(); 95 | } 96 | ``` 97 | ###### 调用 98 | ```javascript 99 | Foo(); //自己去运行代码看this指向谁 100 | 101 | Foo.prototype.bar(); //自己去运行代码看this指向谁 102 | 103 | var foo = new Foo(); //自己去运行代码看this指向谁 104 | 105 | foo.name = '我是foo'; 106 | 107 | foo.bar(); //自己去运行代码看this指向谁 108 | 109 | foo.funcWithParam(function(){ 110 | console.log(this); //自己去运行代码看this指向谁 111 | }); 112 | 113 | ``` 114 | ###### 解读 115 | 116 | 当Foo()时,Foo被当做[普通函数],那么遵循找“点”大法,Foo内部的this是指向window的; 117 | 118 | 当Foo.prototype.bar()时,Foo还是被当做[普通函数],遵循找“点”大法,按照2-2,发现找到了prototype,转而遵循㈡,再向左找,发现this指向Foo; 119 | 120 | 当new Foo()时,Foo作为[构造函数]被实例化,Foo内部的this指向实例化后的Foo,也就是我声明的foo; 121 | 122 | 当foo.bar时,遵循找“点”大法,按照2-1,发现this指向foo; 123 | 124 | 当foo.funcWithParam(匿名函数)时,匿名函数前没有“.”,匿名函数作为参数,所以遵循㈠,发现其内部this指向window; 125 | 126 | 127 | 128 | ## 4、call和apply会改变this指向,在[巧妙理解call、apply](https://github.com/TerryBeanX2/Dive-Into-JS/tree/master/call-apply)单独详解。 129 | 130 | 131 | 132 | ## 小结: 133 | 134 | * 找不到“.”的函数调用,其内部的this一般指向window象; 135 | * 找得到“.”的函数调用,其内部的this一般指向最后一个“.”左侧的那个对象,如果左侧是prototype,再向左找一个; 136 | * 明确区分函数是[构造函数]还是[普通函数],[构造函数]内的this指向实例化后的对象; 137 | * 函数作为参数传递,被调用时其内部的this一般指向window。 138 | * call和apply会改变this指向,参阅[巧妙理解call、apply](https://github.com/TerryBeanX2/Dive-Into-JS/tree/master/call-apply)。 139 | * ES6/7的箭头函数也会影响this指向,这个很简单,我就不多讲啦~ 140 | 141 | #### 一句话来说,就是“谁调的我(普通函数),我内部的this就指向谁;new我一下(构造函数),我内部的this就指向我的实例化” 142 | 143 | 144 | 欢迎转载,需要注明原址。如果帮到你,希望得到你的Star~
145 | PS:教程之间紧密联系,不懂的地方,请好好看下[目录](https://github.com/TerryBeanX2/Dive-Into-JS#提供给有一定js基础开发者进阶知识点大白话解读),有没有你不懂的那个关键字在里面。 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | -------------------------------------------------------------------------------- /proto/README.MD: -------------------------------------------------------------------------------- 1 | # 不得不说的原型与原型链:prototype与__proto__ 2 | 3 | ## 1、纸面意思 4 | 啥是原型,啥是原型链?
5 | 原型:一个属性,属性名叫prototype,只有构造函数有,比如Foo.prototype;
6 | 原型链:一个属性,属性名叫__proto__,万物皆有,链状相连,最后归宗到Object.prototype上,Object.prototype的__proto__值为null;
7 | 8 | ## 2、尝试理解一下这两个点,记住一定配合控制台去打印。 9 | * 访问一个实例的属性,JS会先在实例内部寻找,找不到的话,沿着原型链继续找下去。 10 | ```javascript 11 |    function Foo(){this.name='我是构造函数Foo'} //一个构造函数Foo 12 | 13 |    var foo = new Foo(); //通过new Foo(),得到实例化的foo 14 | 15 |    console.log(foo.bar); //访问foo的bar属性,控制台打印一下,得到undefined 16 | 17 |    Foo.prototype.bar = '我是bar属性,在Foo.prototype(Foo的原型)里'; //给Foo.prototype添加bar属性 18 | 19 |    console.log(foo.bar); //再次访问foo的bar属性,控制台打印一下看看。结果验证了"沿着原型链找下去"这句话。 20 | 21 |    Object.prototype.examAttr = '我是examAttr属性,在Object.prototype(Object的原型)里'; //给Object.prototype添加examAttr属性 22 | 23 |    console.log(foo.examAttr); //访问foo的examAttr属性,控制台打印一下看看。结果验证了"一直找到Object.prototype"这句话。 24 | ``` 25 | 26 |    配合之前写的纸面意思,回味一下上面的代码。 27 | * 每个构造函数都有一个原型,这个原型的constructor属性就是这个构造函数。 28 | ```javascript 29 |    function Foo(){this.name='我是构造函数Foo'} //一个构造函数Foo 30 | 31 |    console.log(Foo.prototype); //打印结果可以看到一个Object对象,即Foo的原型,里面有一个constructor属性,属性值即为Foo函数。 32 | 33 |    var foo = new Foo(); //实例化 34 | 35 |    console.log(foo.constructor); //foo中没有constructor属性,沿着原型链找到Foo的原型(即上面打印的结果),得到Foo原型的constructor属性值,即Foo函数。 36 | ``` 37 | 38 |    以上代码解释了为什么通过查看实例的constructor属性可以得到实例的构造函数。重点在于“沿着原型链找”。 39 | ## 3、从老生常谈的JS实现new运算符过程来剖析 40 | ```javascript 41 | //写一个构造函数,定义其prototype 42 | function Foo(name) { 43 | this.name = name; 44 | } 45 | Foo.prototype = { 46 |    constructor:Foo, //由于重新定义了prototype,咱们把constructor属性补上。 47 |    say: function () { 48 | console.log('My name is ' + this.name); 49 | } 50 | }; 51 | //JS实现new的方法generate 52 | function generate(Fun,arguments) { 53 |    var foo = {}; //新建一个空对象 54 |    Fun.apply(foo, arguments); //利用apply改变this指向,现在运行Fun时,内部this指向foo空对象,那么给this.name赋值就变成了给foo.name赋值。 55 |    foo.__proto__ = Fun.prototype; //把foo的__proto__属性指向Fun.prototype。 56 |    return foo; 57 | } 58 | //执行generate,模拟new 59 | var foo = generate(Foo,["Terry"]); //相当于 var foo = new Foo("Terry") 60 | //验证实例方法 61 | foo.say(); 62 | //查看foo的构造函数 63 | console.log(foo.constructor); 64 | ``` 65 | #### 上面的代码完全实现了new运算符的逻辑,所以说,new运算符就是上面这段代码的语法糖而已。 66 | 67 | 下面这张图想必很多人都很熟悉,我截取了小上半部分, 68 | 不要考虑看不见的导线,只关心f1、Foo、Foo.prototype三者的关系就够了。 69 | 配合下面这张图,再回头看一下JS实现new的过程: 70 | 71 | 72 | ###### 理不清没关系,我们来解析一下: 73 | 74 | 图中表示,f1由new Foo而来,而f1的__proto__连接着Foo.prototype, 75 | 这说明Foo的实例f1的__proto__(原型链)是指向Foo.prototype(原型)的, 76 | 你再回头去看我们用JS实现new所封装的方法generate,有这么一句: 77 | foo.__proto__ = Fun.prototype; 78 | 那不就是手动把foo(图中的f1)的原型链指向Fun(图中的Foo)的原型吗! 79 |     80 | ## 4、ES5面向对象中常用的混合模式 81 | 82 | 在封装代码/插件的时候,使用面向对象的混合模式来写,代码结构是这样的: 83 | 84 | ```javascript 85 | function MyPlugin(name){ 86 |    this.name = name; //每个实例都不一样的属性,写在构造函数里。 87 | } 88 | MyPlugin.prototype = { 89 | publicFun:function(){ 90 |        console.log('我是公共方法,所有实例共用'); //每个实例都调用一样逻辑的代码,封装成方法写进构造函数的原型里 91 |        console.log(this.name+'使用了插件'); 92 |    } 93 | } 94 | //使用插件 95 | var myPlugin = new MyPlugin('小明'); 96 | myPlugin.publicFun(); //实例并没有publicFun方法,但是JS从myPlugun.__proto__中找到了public。 97 | ``` 98 | 99 | 通过找“点”大法(前面教程有说过),可以发现publicFun内部的this指向myPlugin,
100 | 也就验证了为什么[1、理解this指向的小技巧](https://github.com/TerryBeanX2/Dive-Into-JS/tree/master/this)中小结里的第三点:
101 | “明确区分函数是[构造函数]还是[普通函数],[构造函数]内的this指向实例化后的对象;” 102 | ###### 这回知道为什么插件可以这么写,并且实例化后的插件可以直接调用写在prototype里的方法了吧? 103 | 104 | ## 小结 105 | * 关于原型与原型链,没有什么“一句话来说”,仔细通读这篇教程吧,尤其是那张图。 106 | 107 | 欢迎转载,需要注明原址。如果帮到你,希望得到你的Star~
108 | PS:教程之间紧密联系,不懂的地方,请好好看下[目录](https://github.com/TerryBeanX2/Dive-Into-JS#提供给有一定js基础开发者进阶知识点大白话解读),有没有你不懂的那个关键字在里面。 109 |     110 | -------------------------------------------------------------------------------- /call-apply/README.MD: -------------------------------------------------------------------------------- 1 | # 巧妙理解call和apply 2 | 想当年我还是个小白的时候,看到call和apply,那都是一脸懵逼啊!
3 | 再加上参数内部this,arguments什么的,虐的我不要不要的,一度产生厌学心理。
4 | 的确,这俩方法对初学者不够友好...
5 | 6 | 但是!作为半个老鸟,现在看到call啊什么apply啊什么的,也就微微一笑了。
7 | 想当初茅塞顿开的时候,那心里叫一个痛快,现在就把开窍的过程分享出来。
8 | 9 | ## 1、call和apply的区别 10 | 先说一下call和apply的区别,你在完全不懂俩函数是干嘛的情况下,你只要记住:
11 | call和apply的功能是完全一样的,只是第二个参数不一样;
12 | call可以接收无限多个参数,apply只接收俩参数,并且第二个参数只能是数组。
13 | “而它们同样的第一个参数,就是新的this指向!”你先不用管引号里的话说明了什么,脑子里默记下这句话就行。
14 | 好了,现在,不要多想,往下看。
15 | 16 | 17 | ## 2、call、apply会改变this指向 18 | 19 | 我在实际应用中,最常用的就是用call、apply去“借”另一个对象的方法来用,其实是call、apply改变了this指向。 20 | #### 上最简单的栗子 21 | 22 | 我写了个对象obj1,内部三个属性,两个数字numA、numB、还有个方法add,可以打印numA和numB之和: 23 | 24 | ```javascript 25 | var obj1 ={ 26 | numA:1, 27 | numB:2, 28 | add:function(){ 29 | console.log(this.numA + this.numB) 30 | } 31 | } 32 | obj1.add(); //打印出obj1.numA和obj1.numB的和,即3 33 | ``` 34 | 35 | 现在我写了个对象obj2,内部有只两个属性数字numA和数字numB,没有计算器,但也想求和,怎么办? 36 | 管obj1借啊!怎么借?call、apply啊! 37 | 上代码 38 | 39 | ```javascript 40 | var obj2 = { 41 | numA:3, 42 | numB:4 43 | } 44 | //用call借: 45 | obj1.add.call(obj2); //打印出obj2.numA和obj2.numB的和,即7; 46 | //用apply借: 47 | obj1.add.apply(obj2); //打印出obj2.numA和obj2.numB的和,即7; 48 | ``` 49 | 50 | 有意思吧?明明是obj1的add方法里出现了this,按照《理解JS中this指向的小技巧》中的思路, 51 | 找到的“.”左边是obj1,说明是obj1调用了add,add方法内部的this应该指向obj1啊!为啥算出来的结果都是obj2里的numA与numB之和呢? 52 | 因为用了call和apply啊!不是刚说完嘛,它们改变了this的指向啊,指向谁啊?第一个参数啊!第一个参数是谁啊?obj2啊! 53 | 所以你写obj1.add.call(obj2),add方法内部的this指向就变成了obj2,就打印出了obj2.numA和obj2.numB的和。 54 | 就起到了obj2向Obj1“借”了方法add的效果。 55 | #### 带参数的栗子 56 | 这个栗子是面向对象的栗子,对面向对象不够了解的同学,请尽量读懂[不得不提的原型/原型链](https://github.com/TerryBeanX2/Dive-Into-JS/tree/master/proto)
57 | 58 | 我写了个构造函数Obj1,内部三个属性,两个数字numA、numB、还有个方法add,可以打印numA和numB之和: 59 | 60 | ```javascript 61 | function Obj1(numA,numB){ 62 | this.numA = numA; 63 | this.numB = numB; 64 | } 65 | Obj1.prototype.add = function(){ 66 | console.log(this.numA + this.numB) 67 | } 68 | var obj1 = new Obj1(1,2); 69 | obj1.add(); //打印出obj1.numA和obj1.numB的和,即3 70 | ``` 71 | 72 | 现在我写了个构造函数Obj2,内部有只两个属性数字numA和数字numB,没有计算器,但也想求和,怎么办? 73 | 管obj1借啊!怎么借?call、apply啊! 74 | 上代码 75 | 76 | ```javascript 77 | function Obj2(numA,numB){ 78 | this.numA = numA; 79 | this.numB = numB; 80 | } 81 | var obj2 = new Obj2(3,4); 82 | //用call向实例obj1借: 83 | obj1.add.call(obj2,3,4); //打印出obj2.numA和obj2.numB的和,即7; 84 | //用apply向实例obj1借: 85 | obj1.add.apply(obj2,[3,4]); //打印出obj2.numA和obj2.numB的和,即7; 86 | //用call向构造函数Obj1借: 87 | Obj1.prototype.add.call(obj2, 3, 4); //打印出obj2.numA和obj2.numB的和,即7; 88 | //用apply向构造函数Obj1借: 89 | Obj1.prototype.add.apply(obj2, [3, 4]); //打印出obj2.numA和obj2.numB的和,即7; 90 | ``` 91 | 92 | 这个栗子恰好说明了带参数的情况怎么“借”另一个对象的方法,也把apply和call的不同解释明白了,就是个传参不同。 93 | 看这个 Obj1.prototype.add.call(obj2, 3, 4) ,眼熟吗? 94 | 像不像 Array.prototype.forEach.call(xxx) ?就是这么来的,xxx想借用Array.prototype的forEach方法完成遍历。 95 | ## 3、特殊栗:在第一个参数为this并且this指向window的情况下,apply的应用 96 | 比如有个需求,需要做到每次调用先前别人写好的方法时,先在前面运行我们添加的代码:
97 | 下面的代码不一定是最好的实现本需求的代码,但可以演示apply的应用。
98 | 生动的具体化一下: 99 | 100 | ###### 先前陈海写的的代码: 101 | 102 | ```javascript 103 | function foo(){ 104 |        console.log('我是陈海,我拍床戏去了'); 105 | } 106 | foo(); 107 | ``` 108 | 109 | 现在侯亮平接手的反贪局接管了代码, 110 | 需求是,不改变陈海写的代码的情况下,在每次调用陈海写的代码时先打印一些话。 111 | 112 | ###### 林华华自告奋勇,用一段代码帮侯局长完成了需求: 113 | 114 | ```javascript 115 |    function beforeFoo(num){ 116 |        console.log('侯亮平知道陈海有床戏,一共'+num+'场'); 117 | } 118 |    var fooOld = foo; 119 |    foo = function(num){ 120 |        beforeFoo(num); //这里将会被陆亦可修改 121 |        fooOld(); 122 |    } 123 |    foo(30); //运行一下看看效果 124 | ``` 125 | 126 | ###### 陆亦可觉得这个代码复用性太低,每次beforeFoo的参数个数有变化,还要一同修改下面的代码,于是改进了一下: 127 | 128 | ```javascript 129 |    function beforeFoo(num,text){ 130 |        console.log('侯亮平知道陈海有床戏,一共'+num+'场,',text); 131 | } 132 |    var fooOld = foo; 133 |    foo = function(){ 134 |        beforeFoo.apply(this,arguments); //陆亦可修改了这里 135 |        fooOld(); 136 |    } 137 |    foo(30,'醒不过来'); //运行一下看看效果 138 | ``` 139 | 140 | 刹车!陆亦可在她的代码里用到了apply! 141 | 我们来分析一下她干了啥,完成了啥功能: 142 | 修改:把beforeFoo(num)改成beforeFoo.apply(this,arguments); 143 | 完成功能:beforeFoo可以任意修改参数个数,不必再修改后续代码。 144 | 145 | ##### 是不是挺神奇,我们来分析一下:? 146 | 147 | 首先来看看beforeFoo.apply(this,arguments)中的this: 148 | 1、this出现在新foo的内部; 149 | 2、foo的调用语句是foo(30,'醒不过来'),是全局直接调用,找不到“.”; 150 | 根据我上一篇this教程,通过这两点,不难发现this指向window; 151 | 152 | 那么,根据本片文章前面提到过的,apply即“借”,beforeFoo.apply(this,arguments), 153 | 也就是this借用了beforeFoo方法,向谁借的?beforeFoo左边没有“.”,是全局调用,原来是向window借的! 154 | 而刚刚说过,此this指向window,这就好玩了:window向window借用了beforeFoo方法! 155 | 156 | 你说,那不就是beforeFoo直接调用吗,绕一圈干嘛?别忘了还有arguments参数呢! 157 | 这么绕了一圈,在绕圈调用的过程中,JS会解析arguments参数,自动用“,”帮你把参数分开传入beforeFoo方法, 158 | 以后无论你如何修改beforeFoo方法的参数个数,都不用再改剩余的代码了。 159 | 陆亦可利用这一点,巧妙的借助apply完成了代码的可用性提高。 160 | 161 | PS:ES6新出的拓展符可以完成一样的效果:before.apply(this,arguments)可以写成before(...arguments); 162 | 请细细品味,发现道理都是想通的,有趣吧。 163 | 164 | 最后,侯亮平风骚的封装了代码,以后陈海再也不怕不知道自己会演多少场床戏了。 165 |     166 | ## 小结 167 | * 看到call、apply出现,遵循着“借”的思想,再配合“改变this指向”,
168 | * XX.call(YY),那么这个“XX”就是被借的方法;
169 | * YY就是借方法的那个对象,this指向它;
170 | * XX是谁的?谁调用就是谁的,XX左边没有“.”,说明是全局调用,那就是window的。
171 | * 一定要做到“不找出到底是向谁借的就不罢休”。
172 | 173 | #### 当你终于找到物主(到底是“借”的谁的方法),接着理清this指向,你也就透彻的明白call和apply了。 174 | 175 | 欢迎转载,需要注明原址。如果帮到你,希望得到你的Star~
176 | PS:教程之间紧密联系,不懂的地方,请好好看下[目录](https://github.com/TerryBeanX2/Dive-Into-JS#提供给有一定js基础开发者进阶知识点大白话解读),有没有你不懂的那个关键字在里面。 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | --------------------------------------------------------------------------------