执行上下文

先简单说下执行栈是什么:

js执行代码时会创造一个执行上下文(里面包括执行代码所需要的信息),比如下面代码

function foo(){
    let a=1
    return function b(){
        console.log(a)
    }
    b()
}
foo()

调用函数foo时先创建了函数foo的执行上下文,执行到return 的时候又在执行栈里添加了新的函数b的执行上下文,等函数b执行完了之后就把函数b的执行上下文从执行栈里踢出去,再然后foo的执行上下文也踢出去

再详细说一下执行上下文

在es5里它包含了下面三个内容

  • lexical environment:词法环境,当获取变量时使用。
  • variable environment:变量环境,当声明变量时使用。
  • this value:this 值。

但在es6之后是这个样子的

  • lexical environment:词法环境(环境记录+外部词法引用),当获取变量或者 this 值时使用。
  • variable environment:变量环境,当声明变量时使用。
  • code evaluation state:用于恢复代码执行位置。
  • Function:执行的任务是函数时使用,表示正在被执行的函数。
  • ScriptOrModule:执行的任务是脚本或者模块时使用,表示正在被执行的代码。
  • Realm:使用的基础库和内置对象实例。
  • Generator:仅生成器上下文有这个属性,表示当前生成器。

词法环境会通过内部的环境记录来存储标识符与实际变量的映射关系,一个外部词法引用用于查找非当前作用域的变量时进行逐级溯源查找,以及绑定当前作用域的this指针

再聊一聊let/const/var

var 会将变量提升到当前函数作用域最顶端,let和const则不会,而且let碰到以下语句

  • for;
  • if;
  • switch;
  • try/catch/finally

会生成块级作用域

所以:

for(var i=0;i<5;i++){
    setTimeout(()=>{console.log(i)},1000) // i打印出来的都是5
}
for(let i=0;i<5;i++){
    setTimeout(()=>{console.log(i)},1000) // i打印出来的是0,1,2,3,4
}

并且

var、let、const class和function 在执行上下文的创建阶段时,js会在创建阶段执行上下文就将声明的变量、函数和类都创建,但是var 声明的变量会被初始化为undefined,而 let / const / class 声明的变量不会被初始化 状态为 uninitialized ,并且禁止访问,function 关键字的声明会直接将函数体赋值给对应的函数名。而且除了var之外,后面几个关键字声明的标识符映射是存放在词法环境里,而var声明的标识符映射是存放在变量环境里

所以:
console.log(c);
let c =1;
//Uncaught ReferenceError: Cannot access 'c' before initialization
//但是var
console.log(d) //undefiend
var d=1;

再谈谈闭包

根据古典闭包定义( closure )包含:

  • 环境部分(环境和标识符列表)
  • 表达式部分

我们在对应到js里面

  • 环境(函数的词法环境)
  • 标识符列表( 函数中用到的未声明的变量 )
  • 表达式(函数体)

其实闭包就是一个带有词法环境的函数

ASCII,Unicode 和 UTF-8

ASCII: 八个二进制的一个字节,一共表示256个符号

Unicode: 所有符号的集合,但是中文或者其他的符号需要好几个字节来表示,英文的符号只需要一个字节,就会造成内存的浪费

UTF-8:是对Unicode的一种实现,用1-4个字节来表示一个符号,规则:

1)对于单字节的符号,字节的第一位设为0,后面7位为这个符号的 Unicode 码。因此对于英语字母,UTF-8 编码和 ASCII 码是相同的。

2)对于n字节的符号(n > 1),第一个字节的前n位都设为1,第n + 1位设为0,后面字节的前两位一律设为10。剩下的没有提及的二进制位,全部为这个符号的 Unicode 码。

Unicode符号范围     |        UTF-8编码方式
(十六进制)        |              (二进制)
----------------------+---------------------------------------------
0000 0000-0000 007F | 0xxxxxxx
0000 0080-0000 07FF | 110xxxxx 10xxxxxx
0000 0800-0000 FFFF | 1110xxxx 10xxxxxx 10xxxxxx
0001 0000-0010 FFFF | 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx

UTF-8的编码实现

function encodeUtf8(str) {
  var bytes = []
  for (ch of str) {
    // for...of循环,能正确识别 32 位的 UTF-16 字符, 可以查阅资料了解。
    let code = ch.codePointAt(0)
    if (code >= 65536 && code <= 1114111) {// 位运算, 补齐8位
      bytes.push((code >> 18) | 0xf0)
      bytes.push(((code >> 12) & 0x3f) | 0x80)
      bytes.push(((code >> 6) & 0x3f) | 0x80)
      bytes.push((code & 0x3f) | 0x80)
    } else if (code >= 2048 && code <= 65535) {
      bytes.push((code >> 12) | 0xe0)
      bytes.push(((code >> 6) & 0x3f) | 0x80)
      bytes.push((code & 0x3f) | 0x80)
    } else if (code >= 128 && code <= 2047) {
      bytes.push((code >> 6) | 0xc0)
      bytes.push((code & 0x3f) | 0x80)
    } else {
      bytes.push(code)
    }
  }
  return bytes
}

参考

http://www.ruanyifeng.com/blog/2007/10/ascii_unicode_and_utf-8.html

https://juejin.im/post/5e328bdff265da3e4569ad9b

语言类型

静态语言(强类型语言)

静态语言是在编译时变量的数据类型即可确定的语言,多数静态类型语言要求在使用变量之前必须声明数据类型。 
例如:C++、Java、Delphi、C#等。

动态语言(弱类型语言)

动态语言是在运行时确定数据类型的语言。变量使用之前不需要类型声明,通常变量的类型是被赋值的那个值的类型。 
例如PHP/ASP/Ruby/Python/Perl/ABAP/SQL/JavaScript/Unix Shell等等。

强类型定义语言

强制数据类型定义的语言。也就是说,一旦一个变量被指定了某个数据类型,如果不经过强制转换,那么它就永远是这个数据类型了。举个例子:如果你定义了一个整型变量a,那么程序根本不可能将a当作字符串类型处理。强类型定义语言是类型安全的语言。

弱类型定义语言

数据类型可以被忽略的语言。它与强类型定义语言相反, 一个变量可以赋不同数据类型的值。强类型定义语言在速度上可能略逊色于弱类型定义语言,但是强类型定义语言带来的严谨性能够有效的避免许多错误

例如 js是弱类型动态语言,python是强类型动态语言

preview

ABNF 描述四则运算

文法分为:

无限制文法、上下文相关文法、上下文无关文法、正则文法

BNF 巴科斯诺尔范式是一种用于表示上下文无关文法的语言 ,一类形式语言

BNF规定是推导规则(产生式)的集合 表示为 : 符号 ::= <使用符号的表达式>

终结符 是指一个形式语言的基本符号 不能被分解为更小的单位,产生式的组合必须完全由终结符组成

非终结符 是可以被替代的符号

< >     : 内包含的为必选项。
[ ]     : 内包含的为可选项。
{ }     : 内包含的为可重复0至无数次的项。
|       : 表示在其左右两边任选一项,相当于"OR"的意思。
::=     : 是“被定义为”的意思
"..."   : 术语符号
[...]   : 选项,最多出现一次
{...}   : 重复项,任意次数,包括 0 次
(...)   : 分组
|       : 并列选项,只能选一个

ABNF 是对bnf 的扩充 写为

 规则 = 定义 ; 注释 CR LF  

更多参考 https://www.jianshu.com/p/15efcb0c06c8

abnf表示四则运算

Expr   = Term   *Sum   ; 继续绕圈子, *Sum 有或者没有, 先写求和是有原因的
Term   = Factor *Mul   ; 再写乘积, *Sum 不匹配, 就尝试乘积
Sum    = SumOp  Term   ; 求和的运算, 有运算符必定要有后续表达式
Mul    = MulOp  Factor ; 乘积的运算,
Factor = Num /         ; 引向终结
         "(" Expr ")"  ; 括号永远都在

Num    = 1*(0-9)      ; 数字, 这可以是独立的终结符
SumOp  = "+" / "-"    ; 加或者减, 可以叫做求和, 小技巧
MulOp  = "*" / "/"    ; 乘或者除, 可以叫做乘积

更多参考 https://wizardforcel.gitbooks.io/go-blog-in-action/Chapter07.html

HTML 里面的实体是什么

一个HTML 实体 是一段文本(“串”),以与符号(开始&)和结束用分号(;)。实体通常用于显示保留字符(否则将被解释为HTML代码)和不可见字符(例如不间断空格)。您也可以使用它们来代替标准键盘难以键入的其他字符。

比如 &lf;&gf;   nbsp 等等

所有实体的图表: https://html.spec.whatwg.org/multipage/named-characters.html#named-character-references

  nbsp是不换行的空格,用在页面排版的时候保证A”nbsp; “B 中的A和B不会分开在两行展示

前端知识图谱

1. Range 接口表示一个包含节点与文本节点的一部分的文档片段。

2.

Node 是一个接口,许多 DOM API 对象的类型会从这个接口继承。它允许我们使用相似的方式对待这些不同类型的对象;比如, 继承同一组方法,或者用同样的方式测试。

以下接口都从 Node 继承其方法和属性:DocumentElementAttrCharacterData (which TextComment, and CDATASection inherit), ProcessingInstructionDocumentFragmentDocumentTypeNotationEntityEntityReference