你不知道的JavaScript上卷笔记

前言

You don't know JavaScript是github上一个系列文章 
 
初看到这一标题的时候,感觉怎么老外也搞标题党,用这种冲突性比较强的题目吸引眼球,以致最初真没去看内容。直到出了中文版《你不知道的JavaScript》,一看评价大家都说好,买来一读,内容果然很好,很多地方,让我这个半路转行JavaScript的人豁然开朗。中文版现在出了上卷,中卷应该很快会推出,下卷就要等久一点了

作用域和闭包

作用域是什么

  1.现代JavaScript已经不再是解释执行的,而是编译执行的。但是与传统的编译语言不同,它不是提前编译,编译结果不能进行移植。编译过程中,同样会经过分词/词法分析,解析/语法分析,代码生成三个阶段。

  2.以var a = 2;语句为例,对这一程序语句对处理,需要经过引擎,编译器,作用域三者的配合。其中,引擎从头到尾负责整个javascript程序的编译和执行过程;编译器负责语法分析和代码生成;作用域负责收集并维护由所有声明的标识符组成的系列查询,并实施一套规则,确定当前执行的代码对这些标识符的访问权限。

  3.对于var a = 2;编译器首先查找作用域中是否已经有该名称的变量,然后引擎中执行编译器生成的代码时,会首先查找作用域。如果找到就执行赋值操作,否则就抛出异常

  4.引擎对变量的查找有两种:LHS查询RHS查询。当变量出现中赋值操作左侧时是LHS查询,出现中右侧是RHS查询

词法作用域

  1.词法作用域就是定义在词法阶段的作用域。词法作用域是由你在写代码时将变量和块作用域写在哪里决定的,词法处理器分析代码时会保持作用域不变

  1. function foo(a){
    var b = a * 2;
    function bar(c){
    console.log(a,b,c);
    }
    bar(b * 3);
    }
    foo(2);

    这个例子有三级嵌套的作用域 

  2. 作用域查找会在找到第一个匹配的标识符时停止
  3. eval和with可以欺骗词法作用域,不推荐使用

函数作用域和块作用域

  1. JavaScript具有基于函数的作用域,属于这个函数的变量都可以在整个函数的范围内使用及复用
  2. (function fun(){})() 
    函数表达式和函数声明的区别是看function关键字出现在声明中的位置。如果function是声明中的第一个词,那么就是一个函数声明,否则就是一个函数表达式
  3. with,try/catch具有块作用域,方便好用的实现块级作用域的是es6带来的let关键字

提升

  1.如下示例  

a=2;
var a;
console.log(a);

  上述代码输出的不是undefined,而是2。因为上述代码需要经过编译器的编译,编译过程中首先会进行变量声明,然后再由引擎进行变量赋值,所以,上述变量声明虽然写在第二行,但是声明过程是首先执行的

  1. console.log(a);
    var a = 2;

    上述代码不是抛ReferenceError异常, 而是输出undefined

  2. 只有声明会被提升,赋值及其他运行逻辑会留在原地
  3. foo();
    function foo(){
    console.log(a);//undefined
    var a = 2;
    }

    foo();//不是ReferenceError,是TypeError var foo = function bar(){}; foo被提升并分配给所在作用域,所以foo()不会导致ReferenceError,但是foo没有被赋值,对undefined进行函数调用,所以抛出TypeError

作用域闭包

  1. 将内部函数传递到所在词法作用域以外,它都会持有对原始定义作用域的饮用,无论中何处执行这个函数都会使用闭包
  2. 本质上,无论何时何地,如果将函数当作第一级的值类型并到处传递,就会看到闭包在这些函数中的应用。在定时器,事件监听器,ajax请求,web workers或者其他任何异步任务中,只要使用了回调函数,实际上就是在使用闭包
  3. 模块的封装利用了闭包,将内部变量隐藏,并返还一个公共api的对象,这一返回的对象对模块的私有变量形成闭包访问。

动态作用域

  1.词法作用域是一套引擎如何寻找变量以及会在何处找到变量的规则。词法作用域最重要的特征是它的定义过程发生中代码的书写阶段

  2.动态作用域让作用域作为一个在运行时就被动态确定的形式,而不是在写代码时进行静态确定的形式。

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

词法作用域让foo()中的a通过RHS引用到了全局作用域中的a,所以输出2;动态作用域不关心函数和作用域如何声明以及在何处声明,只关心从何处调用。换言之,作用域链是基于调用栈的,而不是代码中的作用域嵌套。如果以动态作用域来看,上面代码中执行时会输出3

  3.JavaScript不具备动态作用域,但是this机制中某种程度上很像动态作用域,this关注函数如何调用。

this词法

  1. es6通过箭头函数,将this同词法作用域联系起来了。
  2. 之前如果会遇到this丢失,常见方法时使用本地变量替换this引用 
    var obj = {
    msg : 'awesome',
    cool:function(){
    setTimeout(function timer(){
    console.log(this.msg);
    },100);
    }
    };
    var msg = 'not awesome';
    obj.cool(); //not awesome var obj = {
    msg : 'awesome',
    cool:function(){
    var self = this; setTimeout(function timer(
    console.log(self.msg);
    },100);
    }
    };
    var msg = 'not awesome';
    obj.cool(); //awesome var obj = {
    msg : 'awesome',
    cool:function(){ setTimeout(() => {
    console.log(this.msg);
    },100);
    }
    };
    var msg = 'not awesome';
    obj.cool(); //awesome var obj = {
    msg : 'awesome',
    cool:function(){
    setTimeout(function timer() {
    console.log(this.msg); }.bind(this),100);
    }
    };
    var msg = 'not awesome';
    obj.cool(); //awesome

this和对象原型

this全面解析

  1. 默认绑定。

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

    上述示例中,函数调用应用了默认绑定,this指向全局对象

  2. 隐式绑定。调用位置是否有上下文对象,或者说是否被某个对象拥有或者包含。 
    function foo(){
    console.log(this.a);
    }
    var obj={
    a:2,
    foo:foo
    };
    obj.foo();//2

    foo()被调用时,落脚点指向obj对象。当函数引用有上下文对象时,隐式对象将函数调用中的this绑定到上下文对象。

  3. 显示绑定。使用apply,call或者bind显示绑定
  4. new绑定。
    • JavaScript中的构造函数只是一些使用new操作符时被调用的函数。它们并不会属于某个类,也不会实例化一个类。实际上,它们甚至不能说是一种特殊的函数类型,它们只是被new操作符调用的普通函数。
    • 使用new来调用函数,或者说发生构造函数调用,会自动执行下面操作:a)创建一个全新的对象 b)这个新对象会被执行[[原型]]连接 c)这个新对象会绑定到函数调用的this d)如果函数没有返回其他对象,那么new表达式中的函数调用会自动返回这个新对象
  5. 优先级。new绑定 > 显示绑定 > 隐式绑定 > 默认绑定

对象

  1. 属性描述符

    var obj = {};
    Object.defineProperty(
    obj,
    "a",
    {
    value:2,
    writable:true,
    configurable:true,
    enumerable:true
    }
    );
    obj.a;//2
    • writable决定是否可以修改属性的值,writable为false时,对obj.a的修改会静默失败。
    • configurable表示属性是否可以配置,如果为false,再对obj调用defineProperty来修改设置,会抛出TypeError
    • enumerable表示属性是否会出现在对象枚举属性中,如果为false,就不会出现在for...in循环中
  2. 对象常量。结合使用writable:false和configurable:false可以创建一个真正的常量属性(不可修改,不可重定义,不可删除)
  3. 禁止扩展。如果想禁止对一个对象添加新属性并且保留已有属性,可以使用Object.preventExtensions()方法
  4. 密封。Object.seal()会创建一个密封的对象,这个方法实际上会在一个现有对象上调用Object.preventExtensions()方法,并且把所有属性标记为configurable:false
  5. 冻结。Object.freeze()会创建一个冻结对象,这个方法会在现有对象上调用Object.seal()方法,并把所有数据访问的属性标记为writable:false
  6. [[get]],[[put]]。
    • var obj = {
      this._a_ = 2;
      get a(){ return this._a_; },
      set a(val){ this._a_ = val * 2; }
      };
      Object.defineProperty(
      obj,
      "b",
      {
      get:function(){return this._a_ * 2},
      enumerable:true
      }
      )

原型

本节为觉得书中写的有点绕,不清晰。推荐阅读

  1. constructor, prototype, proto 详解
  2. JavaScript中proto与prototype的关系
  3. How does proto differ from constructor.prototype?
  4. 理解JavaScript面向对象的思路

行为委托

  1. [[prototype]]机制是对象中一个内部链接引用另一个对象 如果中第一个对象上没找到需要的属性或者方法引用,引擎就会继续在[[prototyoe]]关联的对象上进行查找。同理,如果后者中也没找到需要的引用,就会继续查找它的[[prototype]],以此类推,这一系列对象的链接称为原型链。换言之,这个机制就是对象之间的关联关系。
  2. [[prototype]]是一种不同于类的设计模式,它是一种委托行为的设计模式。
 
 

不知道的JavaScript的更多相关文章

  1. js值----你所不知道的JavaScript系列(6)

    1.数组 在 JavaScript 中,数组可以容纳任何类型的值,可以是字符串.数字.对象(object),甚至是其他数组(多维数组就是通过这种方式来实现的) .----<你所不知道的JavaS ...

  2. js类型----你所不知道的JavaScript系列(5)

    ECMAScirpt 变量有两种不同的数据类型:基本类型,引用类型.也有其他的叫法,比如原始类型和对象类型等. 1.内置类型 JavaScript 有七种内置类型: • 空值(null) • 未定义( ...

  3. 闭包----你所不知道的JavaScript系列(4)

    一.闭包是什么? · 闭包就是可以使得函数外部的对象能够获取函数内部的信息. · 闭包是一个拥有许多变量和绑定了这些变量的环境的表达式(通常是一个函数),因而这些变量也是该表达式的一部分. · 闭包就 ...

  4. let和const----你所不知道的JavaScript系列(2)

    let 众所周知,在ES6之前,声明变量的关键字就只有var.var 声明变量要么是全局的,要么是函数级的,而无法是块级的. var a=1; console.log(a); console.log( ...

  5. LHS 和 RHS----你所不知道的JavaScript系列(1)

      变量的赋值操作会执行两个动作, 首先编译器会在当前作用域中声明一个变量(如果之前没有声明过), 然后在运行时引擎会在作用域中查找该变量, 如果能够找到就会对它赋值.----<你所不知道的Ja ...

  6. Lodash 严重安全漏洞背后 你不得不知道的 JavaScript 知识

    摘要: 详解原型污染. 原文:Lodash 严重安全漏洞背后 你不得不知道的 JavaScript 知识 作者:Lucas HC Fundebug经授权转载,版权归原作者所有. 可能有信息敏感的同学已 ...

  7. 【转载】14个你可能不知道的 JavaScript 调试技巧

    了解你的工具可以极大的帮助你完成任务.尽管 JavaScript 的调试非常麻烦,但在掌握了技巧 (tricks) 的情况下,你依然可以用尽量少的的时间解决这些错误 (errors) 和问题 (bug ...

  8. 14 个你可能不知道的 JavaScript 调试技巧

    了解你的工具可以极大的帮助你完成任务.尽管 JavaScript 的调试非常麻烦,但在掌握了技巧 (tricks) 的情况下,你依然可以用尽量少的的时间解决这些错误 (errors) 和问题 (bug ...

  9. 你所不知道的JavaScript数组

    相信每一个 javascript 学习者,都会去了解 JS 的各种基本数据类型,数组就是数据的组合,这是一个很基本也十分简单的概念,他的内容没多少,学好它也不是件难事情.但是本文着重要介绍的并不是我们 ...

  10. 10个你可能不知道的JavaScript小技巧

    1.变量转换 看起来很简单,但据我所看到的,使用构造函数,像Array()或者Number()来进行变量转换是常用的做法.始终使用原始数据类型(有时也称为字面量)来转换变量,这种没有任何额外的影响的做 ...

随机推荐

  1. [置顶] Objective-C ,ios,iphone开发基础:UIAlertView使用详解

    UIAlertView使用详解 Ios中为我们提供了一个用来弹出提示框的类 UIAlertView,他类似于javascript中的alert 和c#中的MessageBox(); UIAlertVi ...

  2. 浅谈IM软件业务知识——非对称加密,RSA算法,数字签名,公钥,私钥

    概述 首先了解一下相关概念:RSA算法:1977年由Ron Rivest.Adi Shamirh和LenAdleman发明的.RSA就是取自他们三个人的名字. 算法基于一个数论:将两个大素数相乘很ea ...

  3. Java中int类型和tyte[]之间转换及byte[]合并

    JAVA基于位移的 int类型和tyte[]之间转换 [java] view plaincopy /** * 基于位移的int转化成byte[] * @param int number * @retu ...

  4. 重操JS旧业第十弹:闭包

    闭包是js最难理解,也是最蛋疼的一个名词,仿佛只可意会不可言传一样,有人说闭包说白了就是函数嵌套,也有人说闭包就是函数能够访问函数外部的变量,而内部的外部访问不了: 貌似都非常有道理,其实仔细想来只不 ...

  5. Silverlight技术调查(4)——完成的调查结果

    原文 Silverlight技术调查(4)——完成的调查结果 客户端使用Silverlight+DXperience,可以在线编辑各种常见文本及富文本文档(doc.docx.rtf.txt.html… ...

  6. Fedora 17 下安装codeblocks

    Fedora 17 下安装codeblocks:        1.直接从yum源安装:        sudo yum install codeblocks        2.源码安装        ...

  7. hdu4726贪心

    Kia's Calculation Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others ...

  8. 不容错过的UI设计素材大合集

    免费PSD素材 TETHR by InVision 这是出自InVision的8款PSD文件,其中包含了100个模板和超过500个UI控件.来自InVision和UI8的设计师一同协作完成了这套UI ...

  9. EasyUI - 要引入的JS文件

    引入的JS: 使用时候修改路径. <script src="../Quote/EasyUI/locale/easyui-lang-zh_CN.js"></scri ...

  10. TWinControl.DefaultHandler处理WM_CTLCOLORMSGBOX..WM_CTLCOLORSTATIC消息的两个参数很有意思,两个都是传递句柄

    procedure TWinControl.DefaultHandler(var Message); begin then begin with TMessage(Message) do begin ...