Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

你不知道的JavaScript(上卷)--读书笔记 #6

Open
zoro-web opened this issue Jul 20, 2019 · 0 comments
Open

你不知道的JavaScript(上卷)--读书笔记 #6

zoro-web opened this issue Jul 20, 2019 · 0 comments

Comments

@zoro-web
Copy link
Owner

zoro-web commented Jul 20, 2019

前言

本文主要是记录一些我自己觉得重要的知识,防止自己过后忘记,方便自己回顾。自己发现,读了一本书之后,过了一段时间后,看书回顾知识点,发现太久没看就忘记了,而自己在看书期间是已经弄懂的了,所以强迫自己养成看一本书写一篇笔记文的习惯。

作用域是什么

编译原理

编译:在传统编译语言中,程序中的一段源代码在执行之前会经历几个步骤,此过程称为“编译”
步骤:

  1. 分词/语法分析--这个过程会将由字符组成的字符串分解成有意义的代码块(词法单元),比如将程序var a = 2分解成var、a、=、2(词法单元)
  2. 解析/语法分析--这个过程是将词法单元流(数组)转成成一个由元素逐渐嵌套所组成的代表了程序语法结构的树(抽象语法树AST)
  3. 代码生成--将AST转换为可执行代码的过程
    JavaScript与其他语言不同,JavaScript的编译过程不是发生在构建之前,因此JavaScript引擎在执行代码前都要进行编译

作用域

作用域:它是一套规则,用于确定在何处以及如何查找变量(标识符)
查找变量:如果是对变量进行赋值,就用LHS查询,如果是获取变量的值,就使用RHS查询
引用错误:不成功的RHS引用会抛出ReferenceError异常,比如:引用一个未声明的变量,而不成功的LHS引用(找不到该变量)会导致自动隐式地创建一个全局变量(非严格模式下),严格模式抛出ReferenceError

作用域

词法作用域:它意味着作用域是由书写代码时函数声明的位置来决定的。编译的词法分析阶段基本能够知道全部标识符在哪里以及是如何声明的,从而能够预测在执行过程中如何对它们进行查找,从而提高引擎的运行速度,保证性能最佳。
JavaScript中有两个机制可以"欺骗"语法作用域:eval和with,他们都可以在运行时修改或创建一个作用域,所以引擎无法在编译时对作用域的查找进行优化,尽量不要使用它们
动态作用域:在运行时确定的,比如this(在函数被调用时发生的绑定,它的指向取决于函数在哪里被调用)
函数作用域:声明在一个函数内部的变量或函数会在所处的作用域中”隐藏“起来
块作用域:ES3中的try/catch结构在catch分句中具有块作用域,ES6中的let可以声明块作用域
提升:var a = 2在JavaScript引擎看来,它分为两个阶段,var a(编译时)和 a = 2(运行时),代码本身被执行前首先进行处理,这个过程可以形象地想象成所有的声明(变量和函数)都会被移动到各自作用域的最顶端,这个过程被称为提升

作用域闭包

当函数可以记住并访问所在的词法作用域,即使函数实在当前词法作用域之外执行,这时就产生了闭包。
闭包是一个非常强大的工具:可以用多种形式实现”模块“

关于this

如果要判断一个运行中函数的this绑定,就需要找到这个函数的直接调用位置。找到之后就可以顺序应用下面这四条规则来判断this的绑定对象。

  1. 由new调用?绑定到新创建的对象
  2. 由call或apply(或者bind)调用?绑定到指定的对象
  3. 由上下文对象调用?绑定到那个上下文对象
  4. 默认:在严格模式下绑定到undefined,否则绑定到全局对象

var % = Object.create(null)会创建一个空对象,但不会创建Object.prototype这个委托,它的this是空,可以”更安全“地忽略this的绑定,使用foo.apply(%, [参数])不会使用默认绑定规则

new发生构造函数调用时,会自动执行下面的操作。

  1. 构造一个全新的对象
  2. 这个新对象会被执行[[Prototype]]连接
  3. 这个新对象会绑定到函数调用的this
  4. 如果函数没有返回其他对象,那么new表达式中的函数调用会自动返回这个新对象。

对象

基本类型:string、number、boolean、null、undefined、object、symbol
内置对象:String、Number、Boolean、Object、Function、Array、Date、RegExp、Error
属性描述符:有4个特性

  1. value--属性的值
  2. writable--决定是否可以修改属性的值
  3. configurable--决定属性是否可配置的,如果是可配置的,就可以使用defineProperty()方法来修改属性描述符,反之,无法修改(而且configurable一旦设为false,则是单向操作,无法撤销)
  4. enumrable--控制属性是否会出现在对象的属性枚举中,决定它们是否会出现在for..in循环中
    属性的特性可以通过属性描述符来控制,比如writable和configrable。此外,还可以使用
    Object.preventExtensions()--让一个对象变的不可扩展,也就是永远不能再添加新的属性.
    Object.seal()--封闭一个对象,阻止添加新属性并将所有现有属性标记为不可配置。当前属性的值只要可写就可以改变.
    Object.freeze()--冻结一个对象。一个被冻结的对象再也不能被修改;冻结了一个对象则不能向这个对象添加新的属性,不能删除已有属性,不能修改该对象已有属性的可枚举性、可配置性、可写性,以及不能修改已有属性的值。此外,冻结一个对象后该对象的原型也不能被修改.

混合对象”类“和原型

传统面向对象语言都有几大特性:多态、继承、抽象、封装,像Java有基于类面向对象的概念
JavaScript是没有类的,但为了抽象,有很多种模式用来模拟类的行为。而JavaScript是否真的需要模拟类,业界上也是争论激烈,我看了好多文章,也没有一个确定的答案,如果大家有什么其他想法,欢迎评论给我解疑。我自己的观点是,其实大家的出发点都是为了解决对象的抽象行为,而一些后端开发者习惯基于类的编写,才会出现模拟类的行为,而一些认为不需要类的人,应该是觉得可以用更简单的方式去抽象,模拟类会把问题搞复杂,而不用刻意去基于类。正式由于JavaScript的灵活性,才兴起了不同的观点,而我认为只需选择合适的方式即可。
JavaScript是基于原型面向对象的,基于原型链的继承是不会有复制行为的,对象之间是通过”委托“方式进行关联。
在书本的165-173页讲解”类“和”委托“两种设计模式的理论区别和思维模型方面的区别,我觉得是相当好的一个知识面,在这里我就不贴出来了,有兴趣的非常值得观看,绝对可以学到东西。

@zoro-web zoro-web changed the title 你不知道的JavaScript(上卷)----读书笔记 你不知道的JavaScript(上卷)--读书笔记 Jul 20, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant