Giter Site home page Giter Site logo

god-of-js's People

Stargazers

 avatar  avatar

Watchers

 avatar  avatar

god-of-js's Issues

引擎如何对作用域查询的?

编译器在编译过程的第二步生成了代码,引擎执行它的时候,会通过查找变量 a 来判断它是否已声明过。查找的过程由作用域协助。

引擎的查找分为 LHSRHSLR分别代表左侧和右侧,换句话说,当变量出现在赋值操作的左侧的时候进行LHS,出现在右侧的时候进行RHS

更准确点,RHS查询与简单地查找某一个变量的值一样,而LHS查询则是试图找到变量的容器本身,从而可以对它赋值。

例如

console.log(a)

这里对 a 的引用是一个 RHS,因为这里 a 并没有赋值操作,只需要找到 a的值

a = 2

则是一个 LHS的引用,这里只想 为= 2 这个赋值操作找到一个目标

小测验1

function foo( a ) {
    console.log( a )
}
foo( 2 )

这里面的 RHS

  • 对 foo 进行 RHS 引用
  • 隐式赋值 a = 2,是一个 LHS查询
  • 然后 对 a 的RHS 引用
  • 对 console 对象进行 RHS 查询

小测验2

这里面有几个 LHS(3处),有几个RHS(四处)

function foo( a ){
    var b = a;
    return a + b
}
var c = foo( 2 )

总的理解下来,感觉 RHS 类似 getterLHS 类似 setter

作用域就是一套规则,用于确定在何处以及如何查找变量(标识符)。如果找到的目的是对变量进行赋值,那么就会进行 LHS;如果目的是获取变量的值,就会使用 RHS 查询

JS 内置类型

JavaScript 有七种内置类型

  • null
  • undefined
  • boolean
  • number
  • string
  • object
  • symbol

用 typeof 查看值的类型

typeof undefined  === "undefined"  // true
typeof true  === "boolean"               // true
typeof 42  === "number"                  // true
typeof 42  === "number"                 // true
typeof "42" === "string"                   // true
typeof  {}  ===  "object"                   // true
typeof  Symbol()  ===  "symbol"    // true
typeof null  === "object"                // true
typeof function a(){} ===  "function"  // true  
typeof [1,2,3]  === "object"  // true

function 是 object 的子类型,它有一个内部属性[[ call ]],使得它可以被调用
数组也是 object 的子类型

this 的四种绑定方式

  • 默认绑定
  • 显示绑定
  • 隐式绑定
  • new 绑定

其他非正式的绑定

  • 硬绑定/软绑定
  • 箭头绑定

默认绑定

函数不带任何修饰的函数引用(上下文)进行调用的。

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

但是如果使用严格模式,则不能将全局对象用于默认绑定,因此 this 会绑定到 undefined

function foo {
    "use strict"
    console.log(this.a)
}
var a = 2;
foo() //  TypeError: this is undefined

兼容

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

(function {
    "use strict";
    foo()  // 2
})()

隐式绑定

这一条考虑的是调用位置是否有上线对象

function foo(){
    console.log(this.a)
}

var obj2 = {
    a: 10,
    foo: foo
}

var obj1 = {
    a: 20,
    foo: foo
}

obj1.obj2.foo(); // 10

如果这么思考的话,可以认为默认绑定的上下文是window

function foo {
    console.log(this.a)
}
var a = 2;
foo() // 上下文是 window,这里可以看做  window.foo()

在全局作用域中声明 foo,实际上等于 声明window.foo

隐式丢失

function foo(){
    console.log(this.a)
}

var obj = {
    a: 10,
    foo: foo
}

var bar = obj.foo;
var a = "oops, global";
bar(); // "oops, global"

此时的bar(),实际上是不带任何修饰函数调用,因此使用默认绑定

显示绑定

call, apply 等绑定

this 绑定

首先重新定义 JavaScript中的构造函数。

在JavaScript中,构造函数指的是一些使用 new 操作符时被调用的函数。他们并不属于某个类,也不会实例化一个类。实际上,他们甚至不能说是一种特殊的函数类型,他们只是被 new 操作符调用的普通函数

使用new来调用函数,或者说发生构造函数调用时候,会自动执行下面的操作

  • 创建(或者说构造)一个全新的对象
  • 这个新对象会被执行[[ Prototype ]] 连接
  • 这个新对象会被绑定到函数调用的this
  • 如果函数没有返回其他对象,那么 new 表达式的函数调用会自动返回这个新对象

优先级

  1. new 绑定
  2. 显示绑定
  3. 隐式绑定
  4. 默认绑定

作用域有几种?

作用域有如下几种

  • 函数作用域
  • 块作用域(with/ try-catch/ let / const )
  • 隐式/显式 作用域
  • 动态作用域
  • 模块作用域

如何在疲劳的JS世界中持续学习?

关注业界前端大牛

  • 关注大牛及其github作品等等,微博,twitter等等。阮一峰老师,justjavac,狼叔,四月,月影,尤雨溪等等
  • 经常follow他们,还有JavaScript社区的领袖们,CNode的狼叔了解下
  • 经常关注github,关注业界顶级的项目

持续关注和探索页面的项目

  • Github的Explore,里面有很多Topics、Resource、Trending repositories

看最好的资讯

源码源码源码

源码源码,拒绝无耻搬砖,当伸手党

参考

简单理解 JavaScript 作用域

用一个简单粗俗的例子来理解 JavaScript 的作用域

角色

  • 引擎:从头到尾负责整个 JavaScript 程序的编译及执行过程
  • 编译器:引擎的好朋友之一,负责语法分析及代码生成等脏活累活
  • 作用域:引擎的另外一位好朋友,负责收集并维护有所有声明的标识符(变量)组成的一系列查询,并实施一套非常严格的规则,确定当前执行的代码对这些标识符的访问权限

例子

var a = 2 为例,分解步骤为

  • 编译器首先会将这段程序分解成词法单元,然后将词法单元解析成一个树结构。
  • 代码生成分为两步
    • 首先,编译器遇到了 var a,编译器会询问作用域是否已经有一个该名称的变量存在于同一个作用域的集合中。如果是,编译器会忽略该声明,继续进行编译;否则它会要求作用域在当前作用域的集合中声明一个新的变量,并命名为 a
    • 接下来,编译器会为引擎开始生成运行时需要的代码,这些代码被用来处理 a = 2 这个赋值操作,引擎运行时会首先询问作用域,在当前的作用域集合中是否存在一个叫做 a 的变量,如果是,引擎使用这个变量;如果否,引擎继续查找该变量,如果最终找到了 a 变量,就会将 2 赋值给它。否则引擎随手啪给你扔一个异常

总之就是,变量的赋值操作会执行两个动作,首先编译器会在当前作用域中声明一个变量(如果之前没有声明过),然后在运行时引擎会在作用域中查找该变量,如果能找到就对它赋值。

查询作用域导致的异常

不成功的 RHS 引用会导致抛出 ReferenceError异常,不成功的LHS引用会导致自动隐式地创建一个全局变量(非严格模式下),该变量使用LHS引用的目标作为标识符,或者抛出ReferenceError(严格模式下)

如果 RHS 查询找到了一个变量,但是尝试对这个变量进行不合理的操作,比如试图对一个非函数类型的值进行函数调用,或者引用 null or undefined 类型的值中的属性,那么引擎会抛出另外一种类型的异常,叫做TypeError

ReferenceError 同作用域判别失败相关
TypeError 代表作用域判别成功了,但是对结果的操作是非法或者不合理的

tips
严格模式下禁止自动或隐式地创建全局变量

JavaScript 编译原理

程序执行一段源代码之前会经历三个步骤

分词/词法分析

例如 var a = 2,会被分解成 var、a、=、2

解析/语法分析

这个过程是将词法单元流(数组)转换成由一个元素逐级嵌套所组成的代表了程序语法结构的树,称为抽象语法树(Abstract Syntax Tree, AST)

例如 var a = 2 的抽象语法树有一个叫做 VariableDeclaration 的顶级节点,接下来是 Identifier 的子节点(它的值是a),以及一个叫 AssignmentExpression 的子节点。AssignmentExpression 节点有一个叫做 NumericLiteral 的子节点(它的值是2)

代码生成

将 AST 转换为可执行代码的过程被称为代码生成

抛开具体细节,简单的来说就是有某种方法可以将 var a = 2的AST转化为一组机器指令,用来创建一个叫做 a 的变量(包括分配内存),并将一个值存储在 a

AST 的抽象语法树

JavaScript 学习到一定的基础,总是想打破瓶颈提升到下个阶段,这时候研究 JavaScript 的底层也许可以让你打破这个瓶颈。

AST 平时业务很少用到,但是当你不止于想做一个工程师,而是想当一个大神,大牛,别人口中传颂的大师级人物,或者小牛也可以,写成类似 Vue/React/Webapck 这样的工具时,那你必须懂 AST。

在 JavaScript 世界中,AST 可以认为是最底层的东西,再往下,就是转换和编译的"黑魔法"领域。

全局作用域中,用const和let声明的变量去哪了?

let、const声明的变量,暴露在全局,为什么没挂载到window下?究竟挂载到哪里去了?

我们打开控制台,输入

const a = 123;
function abcd() {
    console.log(a);  // abc函数的作用域能访问到a
};
dir(abcd);

可以在 [[Scopes]] 属性中

image

const、let 这类都是属于“Declarative Environment Records” 声明性环境记录,和函数、类这些一样,在单独的存储空间,var这类,属于“object environment record”,会挂载到某个对象上,也会沿着原型链去向上查找

说明不挂载到对象上,但是在一个上下文的方法中,可以访问到let、const 声明记录

作用域提升

函数声明会提升,但是函数表达式不会被提升

例一

foo (); // 报 ReferenceError 而不是 TypeError
var foo = function (){
    // ...
}

这时候 var foo 被提升了,但是 foo并没有赋值,所以 foo() 实际上是对 undefined值进行 函数调用而导致非法操作,因此抛出 TypeError

例二

foo() // TypeError
bar() // RefenrenceError
var foo = function bar() {
    // ...
}

函数优先

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.