前端语言串讲

162 阅读17分钟

阅读文档

这里他告诉了你如何阅读文档,但其实也只是略要的概括了一下,且并没有给出文档的地址,这里我进行补充:CSS Syntax (w3schools.com)

视频中的案例图片也是来自于此

image.png

W3C和W3School的区别?
  1. W3C(万维网联盟): W3C 是一个国际组织,成立于 1994 年,负责制定和维护 Web 标准。它的目标是确保 Web 发展的长期可持续性和可访问性。W3C 制定了许多 Web 技术的规范,如 HTML、CSS、XML、SVG 等。W3C 的官方网站是 www.w3.org/。在 W3C 网站上,可以找到关于 Web 标准的详细信息和技术规范。
  2. W3Schools: W3Schools 并非 W3C 的官方网站,而是一个独立的在线教育平台。它成立于 1998 年,提供了大量关于 HTML、CSS、JavaScript 等 Web 技术的教程和实例。W3Schools 的目标是为 Web 开发者提供一个易于理解的学习资源。W3Cschools 的官方网站是 www.w3schools.com/。在 W3Cshools 网站上,可以找到关于 Web 技术的教程、示例和实践练习。

而他们最主要的区别(其实是完全不同的两家组织,一开始学习的我一直以为他们是同一家的):

  • W3C 是一个国际组织,负责制定和维护 Web 标准。
  • W3Schools 是一个在线教育平台,提供关于 Web 技术的教程和实例。

JavaScript

coderwhy老师曾经说过了解真相才能获得真正的自由,那么了解一门语言的前生今世同样对于我们理解它有着很棒的作用(不了解它的曾经,又怎么能理解它为什么要做出这样的变化)

  1. 1995 年:JavaScript 的诞生 JavaScript 最早是由 Netscape 公司的程序员 Brendan Eich 开发的,原名叫 Mocha。最初的目标是提供一种浏览器端脚本语言,用于操作 HTML 文档,增加互动性和动态效果。几个月后,Mocha 被重命名为 LiveScript,随后又改名为 JavaScript。尽管名字里包含 "Java",但实际上 JavaScript 和 Java 并无直接关系,这个命名更多是当时为了借助 Java 语言的热度。

  2. 1996 年:ECMAScript 的诞生 为了让 JavaScript 成为一个通用的脚本语言标准,Netscape 将 JavaScript 提交给了欧洲计算机制造商协会(ECMA)。ECMA 开发了一种名为 ECMAScript 的标准化脚本语言规范。自此,JavaScript 成为 ECMAScript 规范的一种实现。

  3. 1997 年:ECMAScript 1.0 发布 ECMA 发布了 ECMAScript 的第一个版本(1.0),标志着 JavaScript 语言正式成为一个独立的编程语言。

  4. 1999 年:ECMAScript 3.0 发布 ECMAScript 3.0 是 JavaScript 发展历程中的一个重要版本,它引入了许多核心功能,如正则表达式、错误处理、更严格的变量声明等。

  5. 2005 年:Ajax 和 Web 2.0 的兴起 2005 年,Ajax(Asynchronous JavaScript and XML)技术兴起,它允许在不刷新整个页面的情况下进行局部数据更新,大大提高了 Web 应用的交互性。这一时期,Web 2.0 的概念开始流行,JavaScript 在 Web 开发中的地位得到了极大的提升。

  6. 2009 年:ECMAScript 5 发布 ECMAScript 5 版本引入了许多新特性,如 JSON 支持、严格模式、访问器属性等。同时,它还优化了一些老旧的功能和语法,使得 JavaScript 更加易用和高效。

  7. 2010 年:Node.js 的诞生 2010 年,程序员 Ryan Dahl 创立了 Node.js,将 JavaScript 扩展到了服务器端。Node.js 的出现使得 JavaScript 成为一种全栈开发语言。

  8. 2015 年:ECMAScript 6(ES2015)发布 ECMAScript 6(也称为 ES2015)是 JavaScript 发展史上最重要的版本之一。ES6(ECMAScript 2015)引入了许多重要的新特性,改进了 JavaScript 语言的编程模式和可读性。这些新特性包括:

    • 类(Class)语法:提供了基于原型的面向对象编程的语法糖。
    • 模块化(Module):引入了模块化编程的概念,使得开发者可以将代码拆分为可重用的模块。
    • 箭头函数(Arrow Function):简化了函数定义的语法,同时自动绑定 this 上下文。
    • Promise:提供了一种更好的异步编程模式,帮助开发者更容易处理异步操作。
    • 解构赋值(Destructuring Assignment):一种更简洁的变量解构和赋值方式。
    • 默认参数(Default Parameters):允许函数参数具有默认值。
    • 模板字符串(Template Literals):提供了一种简单的字符串插值和多行字符串的表示方法。
    • 增强的对象字面量:增加了对于简写属性和方法的支持。
    • let 和 const 关键字:引入了块级作用域,并允许更精确地声明变量和常量。
  9. 2016 年至今:ECMAScript 的年度更新 自 ES6(ECMAScript 2015)发布以来,ECMAScript 规范开始了每年的更新周期。这意味着每年都会有一个新版本的 ECMAScript,其中包括一些新特性和改进。这使得 JavaScript 的发展更加稳定和可预测。

  10. 现代 Web 开发框架和库的兴起 近年来,随着 JavaScript 的发展,许多现代 Web 开发框架和库应运而生。这些框架和库(如 Angular、React、Vue.js 等)极大地提高了开发者的生产力,改变了 Web 开发的方式和规模。

image.png

image.png

基础语法

JavaScript的七种基本数据类型:

这些类型分为两大类:原始类型(Primitive)和对象类型(Object)。

  1. Number(数字): Number 类型用于表示整数和浮点数。在 JavaScript 中,所有数字都是双精度浮点数(64位),遵循 IEEE 754 标准。这意味着 JavaScript 中并没有真正的整数类型。另外,Number 类型还包括特殊值如:Infinity(正无穷大)、-Infinity(负无穷大)和 NaN(非数值)。
  2. String(字符串): String 类型表示一串字符。在 JavaScript 中,字符串是不可变的,这意味着一旦创建了一个字符串,就不能对其内容进行修改。字符串可以用单引号、双引号或反引号(模板字符串)括起来。
  3. Boolean(布尔值): Boolean 类型只有两个值:true(真)和 false(假)。布尔值通常用于表示条件、逻辑操作或比较的结果。
  4. Null(空值): Null 类型只有一个值:null。它表示一个空值或不存在的引用。通常用于表示变量没有被赋值,或表示一个空对象。
  5. Undefined(未定义): Undefined 类型只有一个值:undefined。当一个变量声明了,但尚未赋值时,其默认值为 undefined。它表示变量的值尚未确定。
  6. Symbol(符号): Symbol 类型是 ECMAScript 6(ES2015)引入的新类型。Symbol 类型的值是唯一且不可变的,主要用于创建对象的唯一属性名,以防止属性名冲突。
  7. Object(对象): Object 类型用于表示复杂的数据结构,如对象、数组和函数。对象是键值对的集合,键是字符串,值可以是任何数据类型。数组是值的有序集合,而函数是可调用的代码块。

在 JavaScript 中,原始类型(Number、String、Boolean、Null、Undefined 和 Symbol)是不可变的基本数据类型,而对象类型(Object)是可变的引用数据类型

image.png

声明赋值
//这个表达式涉及到了 JavaScript 中的变量声明、赋值操作以及类型转换
var a = 7 + "2"
//执行过程:
//首先,var a 声明了一个名为 a 的新变量。然后,执行 7 + "2" 的操作。因为其中一个操作数("2")是一个字符串,所以 + 会执行字符串连接操作。在这种情况下,JavaScript 会自动将数字 7 转换为字符串 "7"(隐式转换),然后将两个字符串连接起来,得到新字符串 "72"。最后,将得到的字符串 "72" 赋值给变量 a。
复制代码

让我们详细剖析这个表达式中的含义:

  1. varvar 关键字用于声明一个变量。在这里,var 表示我们将要创建一个新变量。
  2. a:这是我们声明的变量的名称。变量名可以是任何有效的 JavaScript 标识符,通常用于表示该变量存储的数据的含义。
  3. =:赋值操作符,用于将等号右侧的值赋给等号左侧的变量。在这里,它表示我们要将等号右侧的表达式的计算结果存储在变量 a 中。
  4. 7:这是一个数字字面量,表示整数 7。它的类型是 Number。
  5. +:这是一个加法操作符。通常,它用于对两个数字进行加法运算。然而,当它的操作数之一或两者都是字符串时,+ 会变成字符串连接操作符。在这种情况下,它会将两个操作数连接成一个字符串。
  6. "2":这是一个字符串字面量,表示字符 "2"。它的类型是 String。注意,这里的 "2" 是一个字符串,而不是数字。

但是这里我想要扩充另一个知识点,当我们换一种形式的话,它的类型转换还会是隐式拼接字符串吗?

let a = 7 - "2"
console.log(a)//5
复制代码
  • a会输出5,且是Number数字类型。因为 - 操作符仅适用于数字,所以 JavaScript 会尝试将字符串 "2" 转换为数字。在这种情况下,字符串 "2" 可以成功转换为数字 2
  • 通过这种系列的《黑魔法》式操作会降低可读性,所以我们应该尽量避免这种操作
Object

在 JavaScript 中,Object(对象)是一种引用数据类型,用于表示一组键值对。对象可以用来存储和操作数据,它是 JavaScript 中最基本和重要的数据结构。

以下包括函数部分全部都是简要概括,深入的了解和运用场所还得通过其他视频或者文档或者项目实践去进一步学习

  • 键值对(Key-Value Pair): 对象由一组键值对组成,键是字符串,值可以是任何数据类型(包括原始类型和引用类型)。键也称为属性名(Property Name),而值称为属性值(Property Value)。键和值之间用冒号分隔,键值对之间用逗号分隔。
  • 对象字面量(Object Literal): 对象字面量是创建对象的一种简洁表示方式。它使用大括号 {} 包围一组键值对。例如:
//在这个例子中,person 对象有三个属性:name、age 和 greet。name 和 age 分别存储字符串和数字,而 greet 存储一个函数
const person = {
  name: "XiaoYu",
  age: 20,
  greet: function() {
    console.log("Hello, my name is " + this.name);
  }
};
复制代码
  1. 属性访问(Property Access): 可以使用点表示法(Dot Notation)或方括号表示法(Bracket Notation)访问对象的属性。例如:
console.log(person.name); // Output: "XiaoYu"
console.log(person["age"]); // Output: 20
复制代码
  1. 属性操作(Property Manipulation): 可以通过赋值操作符为对象添加新属性,也可以通过赋值操作符修改现有属性的值。要删除对象的属性,可以使用 delete 操作符。例如:
person.gender = "Man"; // 添加新属性
person.name = "小满"; // 修改现有属性的值
delete person.gender; // 删除属性
复制代码
  1. 方法(Method): 对象的属性值可以是函数。这种类型的属性称为方法(Method)。方法通常用于表示对象的行为,它们可以访问和操作对象的其他属性。例如:
person.greet(); // Output: "Hello, my name is XiaoYu"
复制代码
  • this 关键字: 在对象的方法中,可以使用 this 关键字引用该对象本身。这使得方法可以访问和操作对象的其他属性。例如,在上面的 person 对象中,greet 方法使用 this.name 访问 name 属性。

    • this是JavaScript中的一大难点,在《你不知道的JavaScript》上卷中,将它分为了默认调用、隐式调用、显式调用、new调用四种情况,具体过程需要自行去学习,或者在我的GitHub中也有提供对应的笔记
Function

函数(Function)是一种特殊的对象,它封装了一段可执行的代码。函数的主要作用是实现代码的复用、模块化和抽象。

  1. 函数声明(Function Declaration): 函数声明是定义函数的一种方法。函数声明以 function 关键字开始,后面跟着函数名、一对圆括号(包含参数列表)和一对大括号(包含函数体)

    function greet(name) {
      console.log("Hello, " + name);
    }
    复制代码
    
  2. 函数表达式(Function Expression): 函数表达式是另一种定义函数的方法。函数表达式将一个匿名函数赋值给一个变量。

    const greet = function(name) {
      console.log("Hello, " + name);
    };
    复制代码
    
  3. 箭头函数(Arrow Function): 箭头函数是 ECMAScript 6(ES2015)引入的一种简洁的函数语法。箭头函数使用 => 符号,它可以使代码更简洁、易读。

    const greet = (name) => {
      console.log("Hello, " + name);
    };
    复制代码
    
  4. 参数(Parameters)和实参(Arguments): 函数可以接受参数(Parameters)。参数是在函数声明或表达式中定义的,用于接收调用函数时传递的实参(Arguments)。实参是在调用函数时传递给函数的值。

    function add(a, b) {
      return a + b;
    }
    ​
    const sum = add(3, 4); // 传递实参 3 和 4
    复制代码
    
  5. 返回值(Return Value): 函数可以返回一个值,这个值可以是任何数据类型。要返回一个值,可以在函数体内使用 return 语句。如果函数没有 return 语句或者 return 语句后面没有任何值,那么函数的返回值默认为 undefined

    function add(a, b) {
      return a + b;
    }
    ​
    const sum = add(3, 4); // sum 将接收返回值 7
    复制代码
    
  6. 调用(Calling)或执行(Invoking)函数: 要调用或执行一个函数,可以使用函数名后跟一对圆括号(包含实参列表)。

    greet("Alice"); // Output: "Hello, Alice"
    复制代码
    
  7. 作用域(Scope): 在 JavaScript 中,函数有自己的作用域。这意味着在函数内部声明的变量和函数只能在函数内部访问。同样,函数外部的变量和函数在函数内部也是可访问的(除非被其他嵌套函数阻止)。

  8. 闭包(Closure): 闭包是 JavaScript 中一个强大的特性(也是一个很难的知识点,在《你不知道的JavaScript》上卷中一样有详细介绍)。闭包是指一个函数可以访问并操作其外部作用域中的变量,即使在外部作用域已经结束或函数已返回之后。闭包的一个常见用途是在一个函数内部创建另一个函数,这样内部函数可以访问和操作外部函数的变量。

    function makeCounter() {
      let count = 0;
    ​
      return function() {
        count += 1;
        console.log(count);
      };
    }
    ​
    const counter = makeCounter();
    counter(); // Output: 1
    counter(); // Output: 2,数量变成2,证明上一次调用的结果并没有被垃圾回收掉
    //在这个例子中,makeCounter 函数返回一个匿名函数,这个匿名函数可以访问和操作 makeCounter 函数内的 count 变量。即使 makeCounter 函数已经执行完毕,counter(匿名函数的引用)仍然可以访问和操作 count 变量。这就是闭包的作用。
    复制代码
    
  9. 高阶函数(Higher-Order Function): 高阶函数是指接受其他函数作为参数或返回一个函数作为结果的函数。高阶函数在 JavaScript 中非常常见,特别是在函数式编程中。例如,Array.prototype.mapArray.prototype.filterArray.prototype.reduce 等内置函数都是高阶函数。

    const numbers = [1, 2, 3, 4, 5];
    ​
    const doubled = numbers.map(function(num) {
      return num * 2;
    });
    ​
    console.log(doubled); // Output: [2, 4, 6, 8, 10]
    //在这个例子中,我们使用 map 高阶函数将一个数组中的每个元素乘以 2。map 函数接受一个函数作为参数,并将这个函数应用于数组的每个元素。这个在React中会经常出现,用来替代for循环
    复制代码
    

image.png

三剑客在浏览器中的运行

  1. HTTP 请求:浏览器向服务器发送请求,获取网页的 HTML、CSS、JavaScript 文件以及其他资源(如图片、字体等)。
  2. 构建 DOM 树:浏览器解析 HTML 文件,构建一个 DOM(Document Object Model)树。DOM 树是一个以节点形式表示的 HTML 文档结构。每个节点代表 HTML 文档中的一个元素、属性或文本。
  3. 计算 CSS 树:浏览器解析 CSS 文件,构建一个 CSSOM(CSS Object Model)树。CSSOM 树是一个以节点形式表示的 CSS 规则结构。
  4. 排版(Layout):浏览器将 DOM 树和 CSSOM 树结合,生成一个渲染树(Render Tree)。渲染树包含了 DOM 中的可见元素及其对应的 CSS 规则。接着,浏览器会计算渲染树中每个节点的位置和大小,这个过程称为排版或布局(Layout)。
  5. 渲染合成:浏览器将渲染树中的各个节点分层,创建渲染层(Render Layers)。每个层包含一个或多个节点,具有独立的绘制和合成上下文。
  6. 绘制(Painting):浏览器根据渲染层绘制每个节点的视觉效果(如文本、颜色、图像、边框、阴影等),生成位图(Bitmaps)。绘制过程可能会在 GPU(图形处理器)上完成,以提高性能。
  7. 合成(Compositing):浏览器将渲染层的位图合成为一个完整的屏幕图像,然后显示在屏幕上。合成过程通常由 GPU 完成,以实现高效的图像合成。

在这个过程中,JavaScript 代码的解析与执行可能穿插在各个阶段,因为 JavaScript 可以操作 DOM、CSSOM 和浏览器 API,从而改变页面的内容、样式和交互行为。这些变化可能需要浏览器重新执行排版、绘制和合成等任务。因此,在编写 JavaScript 代码时,应尽量减少对 DOM 和 CSSOM 的操作,以提高页面性能。

image.png

Browser(V8引擎工作流程)

JavaScript本质上也是一段文本,需要通过解释器才能够运行

  1. Source code:JavaScript 源代码作为 V8 引擎的输入。
  2. Parser:V8 引擎将 JavaScript 源代码解析成一个抽象语法树(Abstract Syntax Tree,简称 AST)。AST 是源代码的一种树状表示,其中每个节点表示一个源代码中的语法结构(如变量声明、函数调用等)。
  3. AST:生成的抽象语法树将用于接下来的编译和优化过程。
  4. Ignition:V8 引擎中的 Ignition 是一个解释器(Interpreter),它负责将 AST 转换为字节码(Bytecode)。字节码是一种中间表示,比源代码更接近机器代码,但仍具有平台无关性。
  5. Bytecode Execute:Ignition 解释器执行字节码,实现 JavaScript 源代码的功能。在执行字节码的过程中,V8 会收集代码的运行时信息(如类型信息等),用于后续的优化过程。
  6. Feedback:V8 引擎收集的运行时信息(如变量类型、函数调用频率等)称为反馈(Feedback)。这些信息将用于指导后续的即时编译(JIT)过程,生成更高效的机器代码。
  7. TurboFan:V8 引擎中的 TurboFan 是一个即时编译器(Just-In-Time Compiler,简称 JIT),它负责将字节码优化为机器代码。TurboFan 会根据收集到的反馈信息对代码进行特定的优化(如内联函数、消除数组边界检查等),生成性能更好的机器代码。
  8. Machine code (Intel, ARM, MIPS):TurboFan 生成的机器代码是针对特定处理器架构(如 Intel x86/x64、ARM、MIPS 等)的低级代码。这些机器代码可以直接在目标处理器上执行,实现更高的性能。

V8 引擎通过这个工作流程实现了 JavaScript 源代码的高效执行。在实际使用过程中,V8 会根据代码的运行情况动态调整优化策略,确保在不同场景下都能实现最佳性能。