JS.

the invisible core player.

引擎,编译器(语法分析及代码生成),作用域(标志符/变量的查询及访问权限), 从引擎的角度来思考问题.

var a = 2; 变量的赋值操作: 1. 编译器会在当前作用域中声明一个变量(如果之前没有声明过), 然后运行时引擎会在作用域中查找该变量, 如果能找到就对其进行赋值。

引擎的查找: LHS查询,RHS查询。 LHS查询:查找变量的容器本身,从而可以对其进行赋值。RHS:变量的值→Retrieve the source value. 更好的理解方式:LHS:赋值操作的目标。 RHS:赋值操作的源头。

作用域及作用域嵌套 。

RHS: 如果RHS查询在所有嵌套的作用域中找不到所需的变量,引擎就会抛出referenceError; ReferenceError:作用域判别失败。TypeError: 作用域成功但是操作不合理.

作用域的两种类型: 词法作用域, 动态作用域(Bash脚本,Perl)

闭包:当函数可以记住并访问所在词法作用域时,就产生了闭包,即使函数是在当前词法作用域之外执行。

闭包:无论通过何种手段将内部函数传递到所在的词法作用域以外,它都会持有对原始定义作用域的引用, 无论在何处执行这个函数都会使用闭包。

提升:声明存在于其所在作用域的整个范围内.

作用域:函数作用域和块作用域: 任何声明在某个作用域内的变量,都将附属于这个作用域.编译器的工作就是找到所有的声明,并用合适的作用域将它们关联起来----这也是词法作用域的核心内容。正确的思考思路是,包括变量和函数在内的所有声明都会在任何代码执行前首先被处理。

this: 是在运行时绑定的,并不是在编译时绑定。this的绑定和函数声明的位置没关系,只取决于函数的调用方式. 指向什么完全取决于函数哪里被调用.

执行上下文: 函数被调用时,会创建一个活动记录,包含函数在哪里被调用(调用栈),调用方法,传入的参数。

调用栈和调用位置: this是在调用时确定. 所以对象的方法与对象的关系比较间接,并没有传统OOP那么强。

in操作符,for in VS hasOwnProperty, Ojbect.keys VS Object.getOwnPropertyNames()

forEach, every(), some(), for of.

欺骗作用域

eval(..), setTimeout(..), setInterval(..)的第一个参数是字符串,可以被解释为一段动态生成的函数代码。这些功能已经过时并且不被提倡----引擎无法优化,性能影响.

async, await.

async函数一定会返回一个promise对象. await表达式会暂停整个async函数的执行进程并让出其控制权,只有当其等待的基于promise的异步操作被兑现或被拒绝之后才会恢复进程。 promise的解决值会被当作该await表达式的返回值。使用async / await关键字就可以在异步代码中使用普通的try / catch代码块.

常见作用域

函数作用域,块作用域.

事件循环,调用堆栈,消息队列

await:

主要部分:

ECMA262核心语音定义,DOM, BOM.

迭代器,生成器. 可迭代对象,实现Iterable接口,通过Iterator消费.

语义结构

大小写敏感,驼峰命名。

变量类型:

let, var, const.

let vs var: 1. 作用域区间不同. 2. var可以作为window的属性. 3. var 向上提升 4.

6种简单类型(原始类型): Undefined, Null, Boolean, Number, String, Symbol, 一种复杂数据类型: Object. 使用typeof 操作符来确定类型. typeof只返回上面的

Undefined类型只有一个值:就是特殊值undefined.

Null类型只有一个值: 就是null. 空对象指针.

Boolean 有两个值: true, false.

Symbol: 也是属于原始类型.

转型函数: Boolean()函数可以将任何值转换为Bool类型。自动转换: if的控制会自动执行其他类型到Bool的转换.

常用内置符号

Symbol.asyncIterator, Symbol.hasInstance, Symbol.isConcatSpreadable, Symbol.iterator, Symbol.match,

Number

Number(整数及浮点数): 使用IEEE754格式来. 注意不要测试浮点数. 0.1加0.2不一定为0.3.

表示范围:Number.MIN_VALUE, Number.MAX_VALUE. 超过范围则表示为+-Infinity(或者Number.NEGATIVE_INFINITY, Number.POSITIVE_INFINITY). Infinity不能用于计算。 使用isFinite()函数来检测.

NaN: Not a Number, 除以0返回NaN, isNan()

数值zhuanhuan: Number(), parseInt(), parseFloat()

转型函数:Number(), 如果类型为对象,则调用其valueOf()

数组/字符串.

String: length属性,[]方法,indexOf, slice, toLowerCase, toUpperCase, replace.

Array: length属性,[]方法,split,join, push/pop, unshift()/shift(),

条件/循环/函数

if , do-while, while,

for, for-in,

for-in是一种严格的迭代语句,用于枚举对象中的非符号键属性.

for-of是一种严格的迭代语句,用于遍历可迭代对象的元素. 例如数组元素. ES2018对for-of语句进行了扩展,增加了for-await-of, 支持生成期约promise的异步可迭代对象.

标签及break, continue语句.

with语句:将代码作用域设置为特定对象----难以调试 不推荐使用

变量

包含原始值及引用值.6种原始值: Undefined, Null, Boolean, Number, String, Symbol. 保存原始值的变量按值访问.

对象按引用值访问. 只有引用值可以动态的添加属性.

执行上下文与作用域:

每一个上下文都有一个关联的变量对象,在这个上下文中定义的变量和函数都存在于这个对象上.

全局上下文,例如window对象。

对象以及原型式继承(非复制)

属性的两种访问方法,点和数组(加’’), 所以对象也叫关联数组.

使用构造函数这种特殊的函数来定义对象(而不是class).

Javascript: 一种基于原型的语言: prototype-based language: 每个对象有一个原型对象,对象以其原型对象为模版,从原型继承方法和属性.原型对象也可能拥有原型,并从中继承方法和属性,一层一层,以此类推。这种关系被称为Prototype chain. 准确的说,这些属性和方法定义在Object的构造器函数之上的prototype属性上,而非对象实例本身.

对象的原型属性,构造函数的prototype属性。对象的__proto__属性就是构造函数的prototype属性。原型链中的方法和属性没有被复制到其他对象--它们被访问需要通过 prototype chain的方式. 这是非常重要的:对于对象的一切访问

没有官方的方法用于直接访问一个对象的原型对象----原型链的链接被定义在一个内部属性中,在javascript语言标准中用[[prototype]]表示. 大多数浏览器提供了一个名为__proto__的属性,其中包含了对象的原型.

对象的原型可以通过Object.getPrototypeOf(obj)或者已被弃用的__proto__属性获得,与构造函数的prototype属性之间的区别:前者是每个实例都有的属性,后者是构造函数的属性。 也就是说Object.getPrototypeOf(new Foobar())和Foobar.prototype指向同一个对象。

__proto__与prototype, this指向什么? this关键字并不指向当前对象的原型对象,----对象的原型对象是一个内部对象用__proto__访问。prototype属性包含(指向)一个对象,你在这个对象中定义需要被继承的成员.

Object:

任何对象都有的属性: constructor, hasOwnProperty(propertyName), isPrototypeOf(), propertyIsEnumerable(propertyName), toLocalString(), toString(), valueOf()

操作符:

注意在应用给对象时,操作符通常会调用valueOf()或者toString()方法取得可以计算的值。

前缀与后缀操作符: 前缀,在语句计算之前变量的值被改变.

相等操作与全等操作: 相等,比较之前执行转换操作;全等,比较之前不执行转换。

构建对象

  • new Constructor();
  • Object.create();

最佳实践: 在构造器函数体中定义属性,在prototype属性上定义方法。如此构造器只包含属性定义,而方法则分装在不同的代码块,代码更具可读性。

Object.create(obj): 以obj为原型创造新的对象。

基本引用类型

Date, Date.UTC(), Date.parse(), Date.now();

RegExp, 元字符在模式中必须转义: (),[],{},\,^,$,|,?,*,+,.

二次转义: RegExp的两个参数都是字符串,所以在某些情况下需要二次转义.例如\n, \转义之后的字符串为\\, 在正则表达式字符串中要写成\\\\

RegExp: 实例方法exec(), 主要用于配合捕获组使用。

原始值包装类型Boolean, Number, String.

let s1 = ‘some text‘; let s2 = s1.substring(2);

同名转型函数与构造函数:

ECMA的内置对象

除了Object, Array, String, 还有两个单例内置对象. Global, Math.

Global对象上还有一些方法: encodeURI(), encodeURIComponent()

Array

Array: Array构造函数还有两个ES6新增的用于创建数组的静态方法: from(), of()

Array的原型上暴露了3个用于检索数组迭代器方法: keys, values(), entries(),因为这些方法都返回迭代器,所以可以用Array.from()直接转换为数组实例.

  • 栈方法push(), pop()

  • 队列方法:shift(), push(), 逆队列方法unshift(), pop()

  • 排序方法sort,按照升序. 小的在前,大的在后。比较函数:如果第一个参数在第二个前,就返回正值。

  • concat: Symbol.isConcatSpreadable, slice()方法, splice() 可以删除,插入,或者替换.

  • 搜索和位置: 按严格相等搜索和按断言相等搜索: indexOf(), lastIndexOf(), includes(); find(), findIndex()方法使用了断言函数.

    迭代方法

    ECMA为数组定义了5个迭代方法。每个方法接收两个参数: 函数和this(作为函数运行上下文的作用域对象)

    every,filter, forEach(), map, some.

    归并方法: reduce(), reduceRight

定型数组

ArrayBuffer:所有定型数组及引用的基本单位. 为canvas元素相关的开发而保留.

Map.

set(), has(), size, delete(), clear()

Object只能使用数值,字符串或符号作为键。Map可以使用任何JavaScript数据类型作为键.

迭代协议/迭代器/生成器函数

迭代协议分为可迭代协议以及迭代器协议. 可迭代协议允许Javascript对象定义或定制它们的迭代行为。例如在一个for…of结构中,哪些值可以被遍历到。一些内置类型同时内置可迭代对象,并且有默认的迭代行为,例如Array, Map.

可迭代对象,比如说实现@@iterator方法。对象或者原型链上的某个对象比如有一个键为@@iterator属性,可以通过常量Symbol.iterator访问.[Symbol.iterator]: 一个无参数函数,返回一个符合迭代器协议的对象。

实现Iterable接口(可迭代协议): 1. 支持迭代的自我识别能力和创建Iterator接口的对象的能力. 在ECMA中,前者Symbol.iterator这个键来实现. 后者通过一个迭代器工厂函数实现,调用这个工厂函数必须返回一个新迭代器. str[Symbol.iterator]: 工厂函数; str[Symbol.iterator]():迭代器.

迭代器协议: 定义了产生一系列值的标准方式.只有实现了next()方法语义,一个对象才能称为迭代器。 迭代器是一种一次性使用的对象.每个迭代器都会暴露其关联可迭代对象的API.迭代器无需了解与其关联的可迭代对象的结构,只需要知道如何取得连续的值。这种分离正是Iterable和Iterator的强大之处。

next()方法返回迭代器对象IteratorResult

很多内置类型都实现了Iterable接口: 字符串,数组,map, set, arguments对象,NodeList等DOM集合类型。

实际写代码中,不需要显式调用这个工厂函数来生成迭代器,接收可迭代对象的原生语言特性: for-of, 数组解构,扩展操作符,Array.from(), 创建集合,创建映射,Promise.all(), Promise.race, yield*操作符(在生成器中使用。)

forEach: 数组,集合,map的方法。

生成器函数/yield关键字

函数前加星号为生成器函数,调用生成器函数会产生一个生成器对象. 生成器对象实现了Iterable接口.调用生成器对象的next()方法会让生成器开始或者恢复执行.

对象

创建自定义对象的方式通常是创建Object的一个新实例,然后添加属性和方法。早期Javascript开发者频繁使用这种方式创建新对象。几年后,对象字面量变成了更流行的方法。

包含属性和方法。ECMA-262使用一些内部特征来描述属性的特征。开发者在Javascript中不能直接访问, 规范用两个中括号把特性的名称例如[[Enumerable]]. 属性分两种: 数据属性和访问器属性.

数据属性有四个特征:[[Configurable]], [[Enumerable]],[[Writable]],[[Value]], 要修改属性的默认特征,必须使用Object.defineProperty(对象,属性的名称,描述符对象)

访问器属性不包含数据值。相反,包含一个getter函数和一个setter函数. 访问器属性不能直接定义,必须使用Object.defineProperty; Object.defineProperties; ECMA2017

可计算属性键: 可以直接在对象字面量定义的时候使用, 方法名简写。

对象解构语法,使用与对象匹配的结构来实现对象属性赋值。

创建对象

  1. 使用new Object()创建再添加属性.
  2. 使用对象字面量创建.
  3. 工厂模式: 用于抽象创建特定对象的过程(没有解决对象标识问题,即新创建的对象是什么类型.)
  4. 构造函数模式,可以确保实例被标识为特定类型.
  5. 使用Object.create()来创建一个新对象,同时为其指定原型.

构造函数与普通函数唯一的区别是调用方式不同。任何函数只要使用new操作符调用就是构造函数.

最佳实践: 属性在构造函数内,方法在构造函数外(原型模式)。原因:如果方法函数放在构造函数内,那么每个实例都会创建自己的函数实例,会带来不同的作用域链和标志符解析。

原型模式prototype, 理解

构造函数与原型对象是完全不同..原型对象的constructor指向构造函数。 构造函数的原型对象的原型. 实例通过__proto__链接到原型对象,它实际上指向隐藏特性[[prototype]], 构造函数通过prototype属性链接到原型对象。 实例与构造函数没有直接联系,与原型对象有直接联系.

instandof操作符检查实例的原型链.

isPrototypeOf()方法.会在传入参数的[[Prototype]]指向调用它的对象时返回true.Person.prototype.isPrototypeOf(person1)

for-in, in 操作符与hasOwnProperty: own来自于实例。in 来自于实例或者原型都行----可枚举的。Object.keys()方法:

对象迭代: 两个静态方法Object.values(), Object.entries()

构建继承的最佳实践

  1. 构造函数 function Teacher(),调用其原型Person的构造函数(constructor stealing).
  2. 设置Teacher()的原型和构造器引用 Teacher.prototype = Object.create(Person.prototype);
  3. Object.defineProperty(Teacher.prototype, ‘contructor‘, {value:Teacher, enumerable: false, writable: true});(或者直接constructor属性=Teacher,但是最好将enumerable属性为false.)
  4. 使用Teacher.prototype来添加其他方法.

继承的属性和方法定义在prototype属性之上。

Class

  • 类可以包含构造函数方法,实例方法,获取函数,静态类方法.
  • 关键字:constructor, static.
  • 可以把方法定义在类构造函数中 或者 类块中,
  • static关键字: static函数中的this指的是类本身.
  • 类定义语法支持在原型和类本身上定义生成器

new

  1. 在内存中创建一个新对象.
  2. 这个新对象内部[[Prototype]]指针被赋值为构造函数的prototype属性(原型对象)
  3. 构造函数内的this被赋值为这个新对象(this指向新对象)
  4. 执行构造函数内部的代码(给新对象添加属性)
  5. 返回该对象.

Super(), [[HomeObject]]

super只能在派生类构造函数和静态方法中使用. this不能在super之前使用。super()会调用父类构造函数,并将返回实例赋值给this.

new.target, Object.assign()

把不同类的行为集中到一个类是一种常见的Javascript模式。Object.assign()方法是为了混入对象行为而设计的.

组合胜过继承: React中转向组合模式.

Proxy

主要目的: 定义trap.

函数

函数是对象,每个函数都是Function类型的实例. Fucntion也有属性和方法。

函数声明,函数表达式, 箭头函数(arraow function), 使用Function构造函数.

函数名是指向函数的指针.

name属性.

参数以及arguments

函数的参数:参数的个数与类型并不做要求。ECMAScript函数的参数在内部表现为一个数组。函数被调用时总会接收一个数组,但函数并不关心这个数组中包含什么.

arguments是一个支持迭代的类数组对象,有length属性。

使用箭头函数无法使用arguments,只能通过命名参数访问.

没有重载

函数名是指针。没有不同的签名。

显式定义默认参数:

函数内部

arguments, callee属性

this参数. 在函数定义和箭头函数中有不同的行为。 标准函数中,this引用的是把函数当成方法调用的上下文对象,这时候通常称为this 值。

Promise, async, await.

传统方式的问题在于1. 类似于深度嵌套的复杂维护 2. 如果有结果要尽快处理.

Promise: ECMA6的新的引用类型, 一个有状态的对象pending, fulfulled, rejected.

期约fullfilled,就会有一个私有的内部值value, rejected:就有一个reason.

期约的状态是私有的,只能在内部进行操作,内部操作在执行器函数中完成。

执行器函数的职责: 初始化期约的异步行为,控制状态的最终转换.

包含要素: 执行状态及结果, 执行函数(Promise中初始化),状态转换函数(resolve, reject),处理方法.

期约的实例方法 then

连接外部同步代码与内部异步代码.1. 访问异步操作返回的数据/处理期约成功和失败的结果,/连续对期约求值/添加只有期约进入终止状态时才会执行的代码.

then()方法,实现了Thenable()接口. Promise.prototype.then()是为期约实例添加处理程序的主要方法. Promise.prototype.catch()----语法糖,调用它相当于调用Promise.prototype.then(null, onRejected)

Promise.prototype.finally(): 清理代码. 与状态无关.

异步函数 async/await in ES8

解决利用异步结构组织代码的问题

四类属性和方法:

  1. 那些定义在构造函数中,用于给予对象实例的
  2. 属性或方法: this.x = x; 是可用于对象实例的成员.
  3. 那些直接在构造函数上定义,仅在构造函数上可用的属性或方法. 例如Object.keys(),它们一般称为静态属性或静态方法
  4. 在构造函数原型上定义,由所有实例和对象类继承的属性和方法。eg: myContructor.prototype.x()

ECMA2015 Classes

ECMA2015引入了class syntax,更像C++/Java.

class Teacher extends Person

getters and setters

JSON

是一个对象:

XMLHttpRequest 取得数据,JSON.parse(), JSON.stringify()

code style

  1. 函数命名: 以动词开始,如果是bool用is开头.
  2. 常量值全部大写以下划线连接。
  3. 初始化变量使变量类型透明化.
  4. HTML和DOM分开,通过外部文件引入Javascript, 然后使用DOM

DOM

属性及只读:

NodeType, nodeName, nodeValue, childNodes, parentNode, firstNode, lastNode, previousSibling, nextSibling, hasChildNodes(), owerDocument

操纵节点:

appendChild(),insertNode()

cloneNode(),

Document类型

document是HTMLDocument的实例。使用documentElement快速访问HTML页面的html元素。

body属性,指向body元素.

document作为HTMLDocument的实例,还有一些标准Document对象没有的属性.这些属性提供浏览器加载网页的信息: title, URL, domain, referer.

定位元素

getElementById(), getElementsByTagName(), getElementsByName()

id: 元素的id属性值。 getElementsByTagName()返回HTMLCollection对象,一个列表。

对于HTMLCollection对象而言,中括号可以接受数值索引,也可以接收字符串索引(name属性)。 在后台,数值索引会调用item()

Element类型

子节点可以是Element, Text, Comment, ProcessingInstruction, CDataSection

HTML元素

所有HTML元素都通过HTMLElement类型表示. 属性id, 属性classNmae(class属性)

attributes属性: Element类型是唯一使用attributes属性的DOM节点类型。

创建元素: document.createElement()

DOM扩展

selectors API和HTML5 DOM扩展.

AJax, Fetch API

实际开发中,尽量使用fetch()

头部字段

Accept, Accept-Charset, Accept-Encoding, Accet-Language, Connection, Cookie, Host, Referer, User-Agent.

setHttpHeader:在open()之后,send()之前调用.

getResponseHeader():

GET请求:

Subscribe to sanmazi
Receive the latest updates directly to your inbox.
Verification
This entry has been permanently stored onchain and signed by its creator.