美文网首页
JavaScript 回顾(二)JavaScript 知识架构

JavaScript 回顾(二)JavaScript 知识架构

作者: MercuryWang | 来源:发表于2019-08-22 09:29 被阅读0次
    JavaScript.png
    • 在 JavaScript 的模块中,首先我们可以把语言按照文法、语义和运行时来拆分,这符合编程语言的一般规律:用一定的词法和语法,表达一定语义,从而操作运行时
    • 接下来,把运行时分为「数据结构」和「算法」
    • 数据结构包含「类型」和「实例」,JavaScript 的类型系统就是它的 7 种基本类型和 7 种语言类型,实例就是它的内置对象部分
    • 所谓的算法就是 JavaScript 的执行过程

    JavaScript 的类型

    1. 根据最新的语言标准,7 种语言类型:

    • Undefined
    • Null
    • Boolean
    • String
    • Number
    • Symbol
    • Object

    2. Undefined

    Undefined 类型的值是 undefined(declared but not defined 声明但未赋值,同 is not defined 不同), 任何变量在赋值前是 Undefined 类型,值为 undefined

    由于 JS 语言的设计失误,undefined 是一个变量,而非一个关键字。为了避免无意中被篡改,建议使用 void 0 来获取 undefined 的值。以下几种方式都会输出 undefined

    console.log(void 0);
    console.log(void (0));
    console.log(void "hello word!");
    console.log(void true);
    

    在实际编程时,我们一般不会把变量赋值为 undefined,这样可以保证所有值为 undefined 的变量,都是从未赋值的自然状态。

    3. Null

    Null 类型也只有一个值,就是 null,表示的是:“定义了但是为空”。与 undefined 不同,null 是JavaScript 的关键字,所以在任何代码中,都可以放心用 null 关键字来获取 null值。

    4. Boolean

    比较简单,有关键字 true false 来表示两个值。

    5. String

    String 用于表示文本数据,最大长度为 2^53 - 1,这个所谓最大长度,并不是字符数。因为 String 的意义并非“字符串”,而是字符串的 UTF16 编码。所以字符串的最大长度,实际上是受字符串的编码长度影响的。

    6. Number

    JavaScript 中有 2^64 - 2^53 + 3 个值,NaNInfinity-Infinity 都是 Number 类型。

    根据浮点数的定义,非整数的 Number 类型无法用 == (或 ===)来比较,so:

    console.log( 0.1 + 0.2 == 0.3);  // false
    

    浮点数运算的精度问题导致等式两边的结果并不是严格相等,而是相差了个微小的值。所以,需要一个正确的比较方法:

      console.log( Math.abs(0.1 + 0.2 - 0.3) <= Number.EPSILON);
    

    7. Symbol

    Symbol 是 ES6 引入的心类型,它是一切非字符串对象 key 的集合。

    8. Object

    8.1 为什么给对象添加的方法能用在基本类型上?

    答:. 运算符提供了「装箱操作」,它会根据基础类型构造一个临时对象,使得我们能在基本类型上调用对应对象的方法。

    在 JavaScript 中,对象的定义是“属性的集合”。属性分为数据属性和访问器属性,二者都是 key-value 结构,key 可以是字符串或者 Symbol 类型。

    8.2 JavaScript 中几个基本类型,都在对象类型中有个“亲戚”,它们是:
    • Number
    • String
    • Boolean
    • Symbol

    注: 3new Number(3) 完全不同,前者是 Number 类型,后者是对象类型。

    Number String Boolean 的构造器是两用的,当跟 new 搭配时,它们产生新对象;当直接调用时,它们表示强制类型转换。

    Symbol 函数比较特殊,直接使用 new 调用它会抛出错误,但它仍然是 Symbol 对象的构造器。

    8.3 JavaScript 语言在设计上模糊了对象和基本类型之间的关系,so 可以把对象的方法再基本类型上使用:
    console.log("abc".charAt(0)); //a
    

    甚至可以在原型链上添加方法,如:

    Symbol.prototype.hello = () => console.log("hello");
    
    var a = Symbol("a");
    console.log(typeof a); //symbol,a 并非对象
    a.hello(); //hello,有效
    

    类型转换

    推荐禁止使用 ==,而要求程序员进行显式地类型转换后,用 === 比较。

    常见转换规则如下表:

    类型转换.jpg

    JavaScript 中对象的特征

    在实现了对象基本特征的基础上,JavaScript 中对象独有的特色是:具有高度的动态性 -- 这是因为 JavaScript 富裕了使用者在运行时为对象添改状态和行为的能力。

    1. JavaScript 对象的两类属性

    1.1 数据属性,四个特征:
    • value:属性的值
    • writable:决定属性能否被赋值
    • enumerable:决定 for in 能否枚举该属性
    • configuration:决定该属性能否被删除或者改变特征值

    大多数情况下,只关注数据属性的「值」即可。

    1.2 访问器属性(getter/setter):
    • getter:函数或 undefined, 在取属性值时被调用
    • setter:函数或 undefined, 在设置属性值时被调用
    • enumerable:决定 for in 能否枚举该属性
    • configuration:决定该属性能否被删除或者改变特征值

    Object.defineProperty 来定义属性,这样定义属性可以改变属性的 writable 和 enumerable

    Object.getOwnPropertyDescriptor 查看属性

    2. JavaScript 中的常用对象

    2.1 内置对象(Built-in Objects)

    ECMA-262 把内置对象(built-in object)定义为“由 ECMAScript 实现提供的、独立于宿主环境的所有对象,在 ECMAScript 程序开始执行时出现”。这意味着开发者不必明确实例化内置对象,它已被实例化了。ECMA-262 只定义了两个内置对象,即 Global 和 Math (它们也是本地对象,根据定义,每个内置对象都是本地对象)

    MDN 的原文解释:
    「The term "global objects" (or standard built-in objects) here is not to be confused with the global object. Here, global objects refer to objects in the global scope. The global object itself can be accessed using the this operator in the global scope (but only if ECMAScript 5 strict mode is not used; in that case it returns undefined). In fact, the global scope consists of the properties of the global object, including inherited properties, if any.

    Other objects in the global scope are either created by the user script or provided by the host application. The host objects available in browser contexts are documented in the API reference. For more information about the distinction between the DOM and core JavaScript, see JavaScript technologies overview.

    2.3 宿主对象(Host Objects)

    “宿主”就是我们网页的运行环境,即“操作系统”和“浏览器”。所有非本地对象都是宿主对象(host object),即由 ECMAScript 实现的宿主环境提供的对象。所有的 BOM 和 DOM 对象都是宿主对象。

    因为其对于不同的“宿主”环境所展示的内容不同。也就是说,ECMAScript 官方未定义的对象都属于宿主对象,因为其未定义的对象大多数是自己通过 ECMAScript 程序创建的对象。

    2.3.1 浏览器对象:
    1. window 对象是最顶层的对象;
    2. window 对象有6大属性,包括:
    3. documentframeshistorylocationnavigatorscreen,这6大属性本身也是对象;
    4. window 对象下的 document 属性也是对象,并且 document 下也有5大属性(anchorsformsimageslinkslocation)也是对象
    2.3.2 JavaScript 各类型关系图:

    这张图的含义如下:
    1、内置(Build-in)对象与原生(Naitve)对象的区别在于:前者总是在引擎初始化阶段就被创建好的对象,是后者的一个子集;而后者包括了一些在运行过程中动态创建的对象。

    2、引擎扩展对象是一个并不太大的集合,一般来说比较确定,它们也属于引擎的原生对象(但不属于ECMA规范的原生对象)。

    3、宿主对象不是引擎的原生对象,而是由宿主框架通过某种机制注册到 JavaScript 引擎中的对象。

    4、一些宿主会把自己提供的对象/构造器也称为“原生对象”,例如 Internet Explorer 7 就把它提供的 XMLHttpRequest() 称为原生的——与此相对的是在它的更早先版本中通过 new ActiveXObject('Microsoft.XMLHTTP') 这样的方法创建的对象。这种情况下,读者应注意到“宿主的原生对象”与“引擎的原生对象”之间的差异。

    宏观任务(Macro Tasks)和微观任务(Micro Tasks)

    • 宏任务:script (整体代码),setTimeout, setInterval, setImmediate, requestAnimationFrame, I/O, UI rendering.

    • 微任务:process.nextTick, Promise.then, Object.observe, MutationObserver.

    图解1:



    图解2:


    举个例子:

    setTimeout(function() {
        console.log('1. setTimeout');
    })
    
    new Promise(function(resolve) {
        console.log('2. promise');
        resolve();
    }).then(function() {
        console.log('3. then');
    })
    
    console.log('4. console');
    

    解释:

    • 这段代码作为宏任务,进入主线程。
    • 先遇到 setTimeout,那么将其回调函数注册后分发到宏任务Event Queue。(注册过程与上同,下文不再描述)
    • 接下来遇到了 Promisenew Promise 立即执行,then 函数分发到微任务Event Queue。
    • 遇到console.log(),立即执行。
    • 好啦,整体代码 script 作为第一个宏任务执行结束,看看有哪些微任务?我们发现了 then 在微任务 Event Queue 里面,执行。
    • OK,第一轮事件循环结束了,我们开始第二轮循环,当然要从宏任务 Event Queue 开始。我们发现了宏任务 Event Queue 中setTimeout 对应的回调函数,立即执行。
    • 结束。

    更多详情,请参考 这一次,彻底弄懂 JavaScript 执行机制

    函数的分类

    1. 普通函数

    function foo(){
        // code
    }
    

    2. 箭头函数

    const foo = () => {
        // code
    }
    

    3. 在 class 中定义的函数

    class C {
        foo(){
            //code
        }
    }
    

    4. 生成器 generator 函数:用 function* 定义的函数

    function* foo(){
        // code
    }
    

    5. 用 class 定义的类,实际上也是函数

    class Foo {
        constructor(){
            //code
        }
    }
    

    6. 异步函数:普通函数、箭头函数、生成器函数加上 async 关键字:

    async function foo(){
        // code
    }
    const foo = async () => {
        // code
    }
    async function foo*(){
        // code
    }
    

    通过 new 调用函数,跟直接调用 this 取值有明显区别,以上的函数同 new 搭配如下表:

    函数类型 new
    普通函数 新对象
    箭头函数 X
    方法 X
    生成器 X
    新对象
    异步普通函数 X
    异步箭头函数 X
    异步生成器函数 X

    7. 函数体、模块和脚本能使用的语句:

    相关文章

      网友评论

          本文标题:JavaScript 回顾(二)JavaScript 知识架构

          本文链接:https://www.haomeiwen.com/subject/pxzisctx.html