深入理解js原型和闭包笔记:

1.“一切皆是对象”,对象是属性的集合。

    丨 函数也是对象,但是使用typeof时为什么函数返回function而

    丨  不是object呢,js为何要对函数做这样的区分?函数和对象到底什么关系呢?

2.函数和对象的关系(对象是函数创建的,但同时函数又是一种对象)

    丨 对象是通过函数创建的,那它的属性是如何通过函数构造的,又为什么说函数自身也是一种

    丨对象呢,函数有什么对象的特征(对象的特质是属性的集合),难道函数也是属性的集合?它

    丨有什么属性呢?

3.函数的属性:prototype原型(函数也是对象,都有一个叫做prototype原型的属性,这个属性的属性值也是一个对象,该对象中又默认包含一个constructor的属性,指向函数本身。函数所创建的对象所具有的属性定义来源于‘Fn.prototype.对象属性’)

    丨但是我们在使用对象的属性时都是‘对象.属性名’这种方式,为什么不是 ‘对象.prototype.属性名’呢,

    丨明明属性名是定义在prototype下的,原来对象都有一个隐藏原型 _proto_,‘对象._proto_’=== Fn.prototype 。

4.隐藏原型(每一个对象都有一个隐藏原型,指向创建该对象的函数的prototype ---别忘了每一个函数都有一个prototype属性哦)

    丨那么问题来了,上面说函数的prototype属性值也是对象,那它的_proto_指向哪,prototype属性值对象是被Object函数创建的,

    丨它的_proto_指向Object函数的prototype,那Object函数的prototype属性值的_proto_指向哪呢,Object函数的prototype

    丨属性值的_proto_指向null。还有一个问题,上面函数也是对象,那函数的_proto_指向哪呢,函数是由Function函数创建来的,

    丨所以函数的_proto_指向Function函数的prototype。那Function函数的_proto_指向哪呢,答案是指向Function自身的prototype,

    丨因为Function被自身所创建,这也形成了一个环形引用。(只需要记住一个准则,对象的_proto_指向创建它的函数的prototype)。

    丨是不是很乱,吼吼,一点也不乱。要是你和我一样都喜欢整洁干净感觉还乱,那么接下来我们借助instanceof来帮助我们理清

    丨一下js内部“混乱的关系”。(下图为普通函数、Function及Object之间的关系图,这张图就是js原型链继承关系核心了,我们1~7

    丨其实就是在讲解理清这张关系图)。

5.instanceof(A instanceof B的判断规则是:沿着A的_proto_这条线来找,同时沿着B的prototype的这条线来找,如果这两条线能找到同一个引用,即同一个对象,那么就返回true,如果找到终点还未重合,则返回false。Instanceof表示的是一种继承关系,或者原型链的结构。这时再对着图理一理是不是更加清楚了,原来他们指来指去就是在构造这样的继承关系)。

    丨Instanceof这样设计,是想表达什么,是想表达我们接下来介绍的东东——继承——原型链。

6.原型链和继承(访问一个对象的属性时,先在基本属性中找,如果没有,在沿着_proto_这条链向上找,这就是原型链,而这种获取上级属性的方式就是继承)。

     | 上面说了这么多函数、对象、原型、隐藏原型,以及之间如何相互指向构成js的继承和原型链的,那么我们也说一下这种原型的优

    丨势——灵活性。

7.原型的灵活性(对象属性可以随时改动随时添加)如果你要添加内置方法的原型属性,最好做一步判断,如果该属性不存在则添加。如果本来就存在,就没必要添加了。

-----------------------------------------------------------------------------------------------------------------------------------

呵呵呵呵,终于看到分割线了,没错上面结束了。1~7介绍的就是js中的原型,从函数与对象的关系说起,介绍了js是如何通过函数和对象的原型、隐藏原型建立js内部的原型链和继承机制的。

8.【执行上下文环境】上(在执行代码之前,要把用到的所有变量先拿出来,有的直接赋值,有的先用undefined占个空)。先来介绍全局作用域的上下文都有哪些内容。

  a.变量和函数表达式——变量声明,但是不赋值,先用undefined占空;

  b.this——赋值;

  c.函数声明——赋值,赋值函数体的内容;

    丨那么函数体中的执行上下文环境有哪些呢?走起

9.【执行上下文环境】下(函数每被调用一次,都会产生一个新的执行上下文环境,那么产生的上下文环境都有什么呢,看下面)。

  a.参数——赋值

  b.arguments——赋值

  c.自由变量的取值作用域——赋值(函数在定义的时候不是在调用的时候就已经确定了函数体内自由变量的作用域了)。至于“自有变量”和“作用域”,后面专门会讲。

    丨那么我们又有了新的问题,在js执行的时候,会有数不清的函数调用,会产生很多个函数上下文环境,这么多上下文环境

    丨该如何管理,以及如何销毁这些内存呢,我们接下来讲解“执行上下文栈”。不过在讲解“执行上下文栈”之前,我们先讲解一下this,

    丨this还是挺重要的。

10.this(this到底取何值呢,this的取值是在函数真正被调用执行的时候确定的,函数定义的时候确定不了。(而blog中仅仅是使用例子介绍了this取值的四种情况,难道又要死记硬背吗?具体原因却讲解的不够清楚,这完全不符合我们的宗旨。我的另一篇blog详细介绍了this取值的前因后果,说白了就是指向调用它的对象,但是这样说不是很精确,具体参考blog:https://www.cnblogs.com/lauzhishuai/p/9494196.html。在此我将这篇文章的精髓整理一下,让你彻底知道同时又理解this到底是如何取值的)。

一:

一句话:this的指向在定义时是确定不了的,只有在执行的时候才能确定this的指向,this指向最终调用它的对象(在被多个对象一层层调用出来时,this指向他上一级的对象,而不是最外层对象)。

这句话可以拆分成四句通俗易懂的话:a.首先如果调用this时没有什么东西"."出他来,this指向Window,指Window.

                 b.如果只有一个对象“.”出他来,this指向这个对象。(A.this)

                 c.如果通过多层对象一步步“.”出this(A.B.),那么this指向紧邻的上一级,此处即为B

                 d.注意一定是最终,即最后“.”出this的那一行代码中去找上面三种情况。

另外还有两种特殊情况:

二:

一种是函数使用apply、call、bind方法自行改变this的指向。

三:

另一种特殊情况:在碰到retrun时,如果返回的是一个对象,那么this指向的就是这个对象,如果返回的不是一个对象,那么this指向函数的实例。(注意在返回null时,虽然null是对象,但是此时this指向函数的实例)。

-----补充知识点:undefined是基本数据类型,表示未定义。null是一个对象表示空对象。

好了this就这么多,是不是一目了然了,this搞清出了让我们继续撤回我们本系列的主题,继续开始我们的闭包之旅。

11.执行上下文栈(就是一个压栈出栈的过程,保持活跃的只有一个执行上下文环境)

    丨理想的执行上下文栈很简单,但是有一种很常见的情况并不能做到如此完美的压栈出栈,说销毁就销毁,这就是我们接下来要讲的——闭包,

    丨但是在讲之前我们还要从“自由变量”和“作用域”说起。

12.作用域(学过编程的都知道作用域,这里需要注意几点就行了:a.js中没有块级作用域,同时js除了全局作用域外只有函数可以创建作用域。那么我们在编程的时候,定义变量时最好只在全局代码前端和函数开头定义,以免产生混淆;b.作用域之间存在父级关系,这是下面的作用域链了,也没什么;c.作用域最大的作用就是隔离变量)

    丨好了,这节没有什么可讲,我们继续,下面我们将作用域和执行上下文环境结合起来讲。

13.作用域和执行上下文环境(作用域只是一个“地盘”,是抽象的概念,没有变量,要通过作用域对应的执行上下文环境才能找到变量的取值,作用域在定义的时候已经确定了,而执行上下文只有在具体执行时才产生确定)。

    |好了上面是作用域和执行上下文之间简单的关系,其实都理解,下面再讲讲跨作用域取值——即“自由变量”和作用域链

14.自由变量和作用域链(自由变量:在A作用域中使用的变量x,却没有在A作用域中声明(即在其他作用域中声明的),对于A作用域来说,x就是一个自由变量。而如果在当前作用域中找不到自由变量的取值,那么就到定义该函数的上一级作用域中找,注意这里是定义而不是调用——其实这就是所谓的静态作用域。而如果在找不到则继续到它的上上创建父级作用域找,而这个寻找过程就产生了所谓的作用域链)。

    丨好了,我们的一切知识都已储备好,终于轮到我们的“闭包”出场了,其实8~14讲的执行上下文环境、执行上下文栈、作用域、自由变量对于

    丨学过编程的人来讲基本上都是知道的,它就是你理解的那样,可能js中有几点特殊需要注意罢了,所以没有必要觉得“闭包”多厉害,因为基础

    丨东西你早就懂了。

15.闭包(这篇系列的文章闭包讲的有点啰嗦,他结合上面的作用域链和执行上下文栈讲解了闭包,确实是这样,不过上面说的是原因,我们其实只需要一句话就可以知道闭包是什么,其中的变量如何取值:闭包就类似于一个背包,当函数作为返回值或者函数参数时,函数中包含的变量取值也会带过去,就像一个背包一样带着他们,它们的取值要到函数原来对应的作用域链中找)。

-----------------------------------------------------------------------------------------------------------------

好了,终于讲完了,js中的原型、闭包、this是不是现在理解的很透彻了。看完这篇总结,本系列文章中后面两篇的补充就没必要看了,在总结中早就含括在内了。这些知识是不是很简单,并没有你想想中的那么难,网上的很多资料杂七杂八,讲解的时候要不就是讲解的思路不清晰,要么就是只讲片面的知识点,本系列文章“小步快跑”,环环紧扣,很有逻辑和黏性的把所有的东西都讲解透了,对于不理解相关知识的人还是很值得看的。溜了溜了~~

【学习笔记】深入理解js原型和闭包系列学习笔记——精华的更多相关文章

  1. 【学习笔记】深入理解js原型和闭包(0)——目录

    文章转载:https://www.cnblogs.com/wangfupeng1988/p/4001284.html 说明: 本篇文章一共16篇章,外加两篇后补的和一篇自己后来添加的学习笔记,一共19 ...

  2. 【学习笔记】深入理解js原型和闭包(16)——完结

    之前一共用15篇文章,把javascript的原型和闭包讲解了一下. 首先,javascript本来就“不容易学”.不是说它有多难,而是学习它的人,往往都是在学会了其他语言之后,又学javascrip ...

  3. 【学习笔记】深入理解js原型和闭包(18)——补充:上下文环境和作用域的关系

    本系列用了大量的篇幅讲解了上下文环境和作用域,有些人反映这两个是一回儿事.本文就用一个小例子来说明一下,作用域和上下文环境绝对不是一回事儿. 再说明之前,咱们先用简单的语言来概括一下这两个的区别. 0 ...

  4. 【学习笔记】深入理解js原型和闭包(17)——补this

    本文对<深入理解js原型和闭包(10)——this>一篇进行补充,原文链接:https://www.cnblogs.com/lauzhishuai/p/10078307.html 原文中, ...

  5. 【学习笔记】深入理解js原型和闭包(15)——闭包

    前面提到的上下文环境和作用域的知识,除了了解这些知识之外,还是理解闭包的基础. 至于“闭包”这个词的概念的文字描述,确实不好解释,我看过很多遍,但是现在还是记不住. 但是你只需要知道应用的两种情况即可 ...

  6. 【学习笔记】深入理解js原型和闭包(14)——从【自由变量】到【作用域链】

    先解释一下什么是“自由变量”. 在A作用域中使用的变量x,却没有在A作用域中声明(即在其他作用域中声明的),对于A作用域来说,x就是一个自由变量.如下图 如上程序中,在调用fn()函数时,函数体中第6 ...

  7. 【学习笔记】深入理解js原型和闭包(13)——【作用域】和【上下文环境】

    上文简单介绍了作用域,本文把作用域和上下文环境结合起来说一下,会理解的更深一些. 如上图,我们在上文中已经介绍了,除了全局作用域之外,每个函数都会创建自己的作用域,作用域在函数定义时就已经确定了.而不 ...

  8. 【学习笔记】深入理解js原型和闭包(12)——简介【作用域】

    提到作用域,有一句话大家(有js开发经验者)可能比较熟悉:“javascript没有块级作用域”.所谓“块”,就是大括号“{}”中间的语句.例如if语句: 再比如for语句: 所以,我们在编写代码的时 ...

  9. 【学习笔记】深入理解js原型和闭包(11)——执行上下文栈

    继续上文的内容. 执行全局代码时,会产生一个执行上下文环境,每次调用函数都又会产生执行上下文环境.当函数调用完成时,这个上下文环境以及其中的数据都会被消除,再重新回到全局上下文环境.处于活动状态的执行 ...

随机推荐

  1. Codeforces Round #326 (Div. 2)

    B. Duff in Love time limit per test 2 seconds memory limit per test 256 megabytes input standard inp ...

  2. kbmMW 5.0.1发布了(跨全平台,包括Linux,可使用Win的高性能HTTPSys传输层,等等)

    kbmMW5如期发布,作者增加了很多重磅功能,以下翻译作者的发布文件:1.支持Delphi 10.2 Tokyo,包括Linux支持(测试版)2.大量的新功能与改进3.新的智能服务(Smart ser ...

  3. SVN命令使用详解【转】

    本文转载自:http://blog.sina.com.cn/s/blog_963453200101eiuq.html 1.检出svn  co  http://路径(目录或文件的全路径) [本地目录全路 ...

  4. [arm驱动]Linux内核开发之阻塞非阻塞IO----轮询操作【转】

    本文转载自:http://7071976.blog.51cto.com/7061976/1392082 <[arm驱动]Linux内核开发之阻塞非阻塞IO----轮询操作>涉及内核驱动函数 ...

  5. HDU4280 Island Transport —— 最大流 ISAP算法

    题目链接:https://vjudge.net/problem/HDU-4280 Island Transport Time Limit: 20000/10000 MS (Java/Others)   ...

  6. 栏目抓取网站日kafka

    #!/usr/bin/python3#-*- coding:utf-8 -*-"""create 2018-02-27author zldesc: https://ind ...

  7. 深度解密Go语言之 map

    目录 什么是 map 为什么要用 map map 的底层如何实现 map 内存模型 创建 map 哈希函数 key 定位过程 map 的两种 get 操作 如何进行扩容 map 的遍历 map 的赋值 ...

  8. 51nod 1138 【数学-等差数列】

    思路: 很显然每个连续的序列都是等差数列, 那么我们利用等差数列求和公式. S=(a1+a1+k-1)k/2=(2·a1+k-1)*k/2;a1是首项,k是个数. 枚举k,首项最小为1,k最大,具体不 ...

  9. 51nod1127【尺取】

    思路: 尺取,写挫了,debug了半天. #include <bits/stdc++.h> using namespace std; typedef long long LL; const ...

  10. POJ2367【拓扑排序】

    很裸的拓扑排序~ //#include <bits/stdc++.h> #include<iostream> #include<string.h> #include ...