news 2026/10/9 7:39:19

learnxinyminutes-docs 项目 JavaScript 快速入门:从基础语法到原型链与 ES6 的完整实战指南

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
learnxinyminutes-docs 项目 JavaScript 快速入门:从基础语法到原型链与 ES6 的完整实战指南
  • 文档
  • 教程

【免费下载链接】learnxinyminutes-docs

Code documentation written as code! How novel and totally my idea!

项目地址:https://gitcode.com/gh_mirrors/le/learnxinyminutes-docs
点击查看免费下载

导读

本篇以 learnxinyminutes-docs 仓库中的 马来语版 JavaScript 教程(与 英文原版 内容同源)为骨架,将其中以"可运行带注释代码"形式呈现的全部知识点系统化展开,覆盖 JavaScript 的数值与字符串、变量与数组、对象与原型链、控制结构与函数作用域、闭包以及 ES6 新特性。读完本文,你不仅能逐行理解 JavaScript 这门语言的底层行为(如自动分号插入、隐式类型转换、this绑定规则、原型链查找),还能掌握可直接复制运行的代码范例,理解 learnxinyminutes-docs 项目"把文档写成可运行的代码"这一教学组织方式。

一、项目背景:一份"以代码为文档"的 JavaScript 教程

learnxinyminutes-docs 是一个用"带注释的可运行代码"来讲解编程语言的开源仓库,正如 README.md 所述:"Whirlwind tours of popular and ought-to-be-more-popular programming languages, presented as valid, commented code and explained as they go."(以有效、带注释的代码形式,快速巡游流行编程语言)。

仓库中的 JavaScript 教程存在多个语言版本,包括 英文原版 javascript.md、中文版 zh-cn/javascript.md 以及本文所依据的 马来语版 ms/javascript.md。每个文档头部都有 YAML front matter,记录name、contributors、translators、filename等元数据;仓库的 lint/frontmatter.py 脚本会对这些元数据进行键名与类型校验(允许的键为name、where_x_eq_name、category、filename、contributors、translators),确保每一篇教程的格式统一、可被工具链自动检查。

JavaScript 由 Netscape 的 Brendan Eich 于 1995 年发明,最初定位为网站的简单脚本语言,作为更复杂的 Java Web 应用的补充;但由于与网页的紧密集成以及浏览器内置支持,它最终在 Web 前端领域远比 Java 普及。它也不局限于浏览器——基于 Google Chrome V8 引擎的 Node.js 提供了独立运行时。JavaScript 语法接近 C 语言(熟悉 C 或 Java 的读者会发现基础语法很眼熟),但其对象模型与 Java 有本质差异,这正是本文后半部分要重点讲解的内容。

二、语法基础:注释、语句与分号自动插入(ASI)

JavaScript 的注释风格与 C 一致:单行注释以//开头,多行注释以/*包裹。

// 单行注释 /* 多行 注释 */

语句可以用分号;结束,也可以省略——因为 JavaScript 会在换行处"自动插入分号"(Automatic Semicolon Insertion,ASI):

doStuff(); doStuff() // 合法,分号被自动插入

关键陷阱:ASI 只在某些情形下生效,省略分号可能产生意外结果。最典型的例子是return换行问题——如果返回值与return不在同一行,ASI 会在return后立即插入分号,导致函数永远返回undefined:

function myFunction() { return // <- 此处自动插入分号 {thisIsAn: 'object literal'}; } myFunction(); // = undefined

因此教程与实践中都建议始终显式使用分号,尤其是采用 Allman 大括号风格(大括号另起一行)时更要小心。

三、数值、字符串与操作符

3.1 单一数值类型:64 位 IEEE 754 双精度浮点

JavaScript 只有一种数值类型——64 位 IEEE 754 双精度浮点数(double)。double 的尾数(mantissa)为 52 位,足以精确存储约9✕10¹⁵以内的整数:

3; // = 3 1.5; // = 1.5

3.2 基本算术、取模与位运算

1 + 1; // = 2 0.1 + 0.2; // = 0.30000000000000004 (浮点精度问题) 8 - 1; // = 7 10 * 2; // = 20 35 / 5; // = 7 5 / 2; // = 2.5 (非整除除法) 10 % 2; // = 0 (取模) 30 % 4; // = 2 18.5 % 7; // = 4.5 (对浮点取模) 1 << 2; // = 4 (位运算,浮点被转换为至多 32 位有符号整数) (1 + 3) * 2; // = 8 (括号控制优先级)

0.1 + 0.2不等于0.3是 IEEE 754 浮点表示的经典结果,理解这一点对处理金额、精确计算等场景至关重要。

3.3 特殊数值与布尔值

Infinity; // 例如 1/0 的结果 -Infinity; // 例如 -1/0 的结果 NaN; // 例如 0/0 的结果,意为 "Not a Number"(非数值) true; false;

3.4 字符串、比较与隐式类型转换

字符串可用单引号'或双引号"创建:

'abc'; "Hello, world";

比较与逻辑运算:

!true; // = false 否定 !false; // = true 1 === 1; // = true 全等 2 === 1; // = false 1 !== 1; // = false 不全等 2 !== 1; // = true 1 < 10; // = true 1 > 10; // = false 2 <= 2; // = true 2 >= 2; // = true

字符串拼接与比较:

"Hello " + "world!"; // = "Hello world!" "1, 2, " + 3; // = "1, 2, 3" 数字被转成字符串拼接 "Hello " + ["world", "!"]; // = "Hello world,!" "a" < "b"; // = true 字符串按字典序比较 13 + !0; // 14 !0 为 true,true 参与算术被转成 1 "13" + !0; // '13true' true 被转成字符串 "true"

**隐式类型转换(type coercion)**是 JavaScript 著名的"怪异"行为来源:使用双等号==比较时会做类型转换,而三等号===不做转换:

"5" == 5; // = true 发生类型转换 null == undefined; // = true "5" === 5; // = false null === undefined;// = false

因此实践中应始终使用===/!==,避免隐式转换带来的意外。

字符串常用方法(教程明确提醒:length是属性,不是方法,不要加括号):

"This is a string".charAt(0); // = 'T' 按索引取字符 "Hello world".substring(0, 5); // = "Hello" 取子串 "Hello".length; // = 5 属性访问

3.5 null、undefined 与真值/假值

null; // 表示刻意设置的"非值" undefined; // 表示当前"值不存在"(尽管 undefined 本身也是一个值)

假值(falsy)集合:false、null、undefined、NaN、0、""——这些在条件判断中为假;除此之外的一切值都为真(truthy)。特别提醒:0是假值而"0"是真值,尽管0 == "0"为 true。

四、变量、数组与对象

4.1 变量声明与赋值

JavaScript 是动态类型语言,变量用var关键字声明,无需指定类型,赋值用单个=:

var someVar = 5;

危险行为:省略var直接赋值不会报错,但变量会被创建在全局作用域而非当前作用域,这是全局污染的重要来源:

someOtherVar = 10; // 创建在全局作用域!

其他声明细节:

var someThirdVar; // 未赋值即声明 -> undefined var someFourthVar = 2, someFifthVar = 4; // 逗号分隔声明多个变量

复合赋值与自增自减:

someVar += 5; // 等价于 someVar = someVar + 5 someVar *= 10; someVar++; // 加 1 someVar--; // 减 1

4.2 数组:有序、可变的异构列表

数组是任意类型值的有序列表,索引从 0 开始,使用方括号下标语法访问:

var myArray = ["Hello", 45, true]; myArray[1]; // = 45 myArray.push("World"); // 末尾追加 myArray.length; // = 4 myArray[3] = "Hello"; // 在指定索引处写入

完整的前后端增删操作:

myArray.unshift(3); // 在首位添加元素 someVar = myArray.shift();// 移除首位元素并返回 myArray.push(3); // 在末尾添加元素 someVar = myArray.pop(); // 移除末尾元素并返回

连接、切片与拼接(splice 会原地修改数组并返回被移除的子数组):

var myArray0 = [32,false,"js",12,56,90]; myArray0.join(";"); // = "32;false;js;12;56;90" myArray0.slice(1,4); // = [false,"js",12] 左闭右开 myArray0.splice(2,4,"hi","wr","ld"); // = ["js",12,56,90] // 现在 myArray0 === [32,false,"hi","wr","ld"]

4.3 对象:无序的键值对集合

JavaScript 对象等价于其他语言中的"字典"(dictionary)或"映射"(map)——无序的键值对集合:

var myObj = {key1: "Hello", key2: "World"};

键本质是字符串,但若是合法的 JavaScript 标识符,可以省略引号;值可以是任意类型:

var myObj = {myKey: "myValue", "my other key": 4};

属性访问有两种语法——方括号下标语法与点语法(后者要求键是合法标识符):

myObj["my other key"]; // = 4 myObj.myKey; // = "myValue"

对象是可变的:可以修改已有值、添加新键;访问未设置的属性得到undefined:

myObj.myThirdKey = true; myObj.myFourthKey; // = undefined

五、逻辑与控制结构

控制结构语法与 Java 高度相似。if / else if / else、while、do-while:

var count = 1; if (count == 3) { // count 为 3 时执行 } else if (count == 4) { // count 为 4 时执行 } else { // 其他情况执行 } while (true) { // 无限循环! } var input; do { input = getInput(); } while (!isValid(input)); // 至少执行一次

for循环与 C/Java 一致(初始化;继续条件;迭代步进):

for (var i = 0; i < 5; i++) { // 循环 5 次 }

带标签的循环可以跳出外层(类似 Java):

outer: for (var i = 0; i < 10; i++) { for (var j = 0; j < 10; j++) { if (i == 5 && j == 5) { break outer; // 跳出外层循环而非仅内层 } } }

for/in遍历对象属性(会沿原型链向上遍历):

var description = ""; var person = {fname:"Paul", lname:"Ken", age:18}; for (var x in person) { description += person[x] + " "; } // description = 'Paul Ken 18 '

for/of遍历可迭代对象(内置的 String、Array、类数组的 arguments 或 NodeList、TypedArray、Map、Set,以及用户自定义的可迭代对象):

var myPets = ""; var pets = ["cat", "dog", "hamster", "hedgehog"]; for (var pet of pets) { myPets += pet + " "; } // myPets = 'cat dog hamster hedgehog '

注意:for/in不应用于遍历需要保序的数组——它不保证按索引顺序返回。

逻辑运算符&&(与)与||(或),二者都会短路求值(short circuit),因此常用于设置默认值:

if (house.size == "big" && house.colour == "blue") { house.contains = "bear"; } if (colour == "red" || colour == "blue") { // colour 为 red 或 blue } var name = otherName || "default"; // otherName 为假值时使用 "default"

switch语句使用===判断相等;每个 case 之后必须写break,否则匹配 case 之后的其余 case 也会依次执行:

grade = 'B'; switch (grade) { case 'A': console.log("Great job"); break; case 'B': console.log("OK job"); break; case 'C': console.log("You can do better"); break; default: console.log("Oy vey"); break; }

六、函数、作用域与闭包

6.1 函数声明与一等公民地位

函数用function关键字声明:

function myFunction(thing) { return thing.toUpperCase(); } myFunction("foo"); // = "FOO"

函数是一等对象(first class objects),可以被重新赋值给不同变量名,也可以作为参数传给其他函数——例如作为事件处理器:

function myFunction() { // 5 秒后执行的代码 } setTimeout(myFunction, 5000); // 注意:setTimeout 并非 JS 语言本身的一部分,而是由浏览器与 Node.js 提供的 API

浏览器提供的另一个 API 是setInterval(每 5 秒执行一次);函数对象甚至可以不命名,直接把匿名函数定义写入另一个函数的实参:

setTimeout(function(){ // 5 秒后执行的代码 }, 5000);

6.2 函数作用域:块没有作用域

JavaScript 具有函数作用域(function scope):函数拥有自己的作用域,但代码块(如if块)没有:

if (true) { var i = 5; } i; // = 5 —— 在块级作用域的语言中这里应为 undefined

这一特性催生了经典的 **IIFE(立即执行匿名函数)**模式,用于防止临时变量泄漏到全局作用域:

(function(){ var temporary = 5; // 可通过给"全局对象"赋值来访问全局作用域: // 浏览器中通常是 window,Node.js 等非浏览器环境中名称可能不同 window.permanent = 10; })(); temporary; // 抛出 ReferenceError permanent; // = 10

6.3 闭包:JavaScript 最强大的特性之一

如果一个函数定义在另一个函数内部,内部函数可以访问外部函数的所有变量——即使外部函数已经执行完毕:

function sayHelloInFiveSeconds(name) { var prompt = "Hello, " + name + "!"; // 内部函数默认被放入局部作用域,如同用 var 声明 function inner() { alert(prompt); } setTimeout(inner, 5000); // setTimeout 是异步的:sayHelloInFiveSeconds 立即返回, // setTimeout 稍后才调用 inner。但由于 inner "闭包"于 // sayHelloInFiveSeconds,它被调用时仍能访问变量 prompt。 } sayHelloInFiveSeconds("Adam"); // 5 秒后弹出 "Hello, Adam!"

闭包是回调、事件处理、模块封装等一切异步与高阶编程模式的基石。

七、对象进阶:this 绑定、构造函数与原型链

7.1 对象方法中的 this

对象可以包含函数;方法被调用时可通过this访问其所属对象:

var myObj = { myFunc: function() { return "Hello world!"; } }; myObj.myFunc(); // = "Hello world!" myObj = { myString: "Hello world!", myFunc: function() { return this.myString; } }; myObj.myFunc(); // = "Hello world!"

核心规则:this的值取决于函数"如何被调用",而非"在哪里定义"。把方法从对象上拆下来调用,this即丢失:

var myFunc = myObj.myFunc; myFunc(); // = undefined

反过来,函数可以在定义之后被挂到对象上,从而通过this获得该对象访问权:

var myOtherFunc = function() { return this.myString.toUpperCase(); }; myObj.myOtherFunc = myOtherFunc; myObj.myOtherFunc(); // = "HELLO WORLD!"

7.2 call、apply 与 bind:显式指定 this

调用函数时可以用call或apply显式指定其执行上下文:

var anotherFunc = function(s) { return this.myString + s; }; anotherFunc.call(myObj, " And Hello Moon!"); // = "Hello World! And Hello Moon!" anotherFunc.apply(myObj, [" And Hello Sun!"]); // = "Hello World! And Hello Sun!"

区别在于:call逐个传入参数,apply接受一个参数数组。后者在处理"接受参数序列的函数 + 数组输入"时极为实用:

Math.min(42, 6, 27); // = 6 Math.min([42, 6, 27]); // = NaN (把数组当作单个参数,出错了) Math.min.apply(Math, [42, 6, 27]); // = 6

call/apply只对单次调用生效;要持久绑定上下文则使用bind:

var boundFunc = anotherFunc.bind(myObj); boundFunc(" And Hello Saturn!"); // = "Hello World! And Hello Saturn!"

bind还可以**部分应用(curry)**函数——预先固定部分参数:

var product = function(a, b) { return a * b; }; var doubler = product.bind(this, 2); doubler(8); // = 16

7.3 构造函数与 new

用new关键字调用函数时,会创建一个新对象并通过this提供给该函数;为此设计、以这种方式调用的函数称为构造函数(constructor):

var MyConstructor = function() { this.myNumber = 5; }; myNewObj = new MyConstructor(); // = {myNumber: 5} myNewObj.myNumber; // = 5

7.4 原型链:JavaScript 的继承机制

与多数主流面向对象语言"由类蓝图创建实例"不同,JavaScript没有 class 蓝图,而是把实例化与继承合并为单一概念:原型(prototype)。每个对象都有原型;当你访问一个对象上不存在的属性时,解释器会去它的原型上查找。

部分实现允许通过魔法属性__proto__访问原型——它便于讲解,但不是标准的一部分(后文会给出标准做法):

var myObj = { myString: "Hello world!" }; var myPrototype = { meaningOfLife: 42, myFunc: function() { return this.myString.toLowerCase(); } }; myObj.__proto__ = myPrototype; myObj.meaningOfLife; // = 42 myObj.myFunc(); // = "hello world!" (函数同样沿原型查找)

如果属性不在原型上,会继续查找原型的原型,如此沿链向上直至null:

myPrototype.__proto__ = { myBoolean: true }; myObj.myBoolean; // = true

这里没有任何复制:每个对象保存的是对其原型的引用。因此修改原型会即时反映到所有继承它的对象上:

myPrototype.meaningOfLife = 43; myObj.meaningOfLife; // = 43

for/in会沿原型链一直遍历到null原型;若只想考虑对象自身的属性,用hasOwnProperty()过滤:

for (var x in myObj) { console.log(myObj[x]); } // 输出: // Hello world! // 43 // [Function: myFunc] // true for (var x in myObj) { if (myObj.hasOwnProperty(x)) { console.log(myObj[x]); } } // 输出: // Hello world!

7.5 创建带指定原型的新对象

__proto__并非标准,且标准中没有"修改既有对象原型"的方法;但有两种标准方式创建带指定原型的新对象。

方式一:Object.create(较新的 API,早期实现可能没有):

var myObj = Object.create(myPrototype); myObj.meaningOfLife; // = 43

方式二:通过构造函数。构造函数有一个名为prototype的属性——注意它不是构造函数自身的原型,而是"用该构造函数配合new创建新对象时赋予新对象的原型":

MyConstructor.prototype = { myNumber: 5, getMyNumber: function() { return this.myNumber; } }; var myNewObj2 = new MyConstructor(); myNewObj2.getMyNumber(); // = 5 myNewObj2.myNumber = 6; myNewObj2.getMyNumber(); // = 6

7.6 包装对象、内置类型原型与 polyfill

字符串、数字等内置类型也有对应的构造函数,可创建包装对象(wrapper object):

var myNumber = 12; var myNumberObj = new Number(12); myNumber == myNumberObj; // = true 宽松比较相等

但它们并不完全等同:

typeof myNumber; // = 'number' typeof myNumberObj; // = 'object' myNumber === myNumberObj; // = false if (0) { // 不执行,因为 0 是假值 } if (new Number(0)) { // 会执行,因为包装对象是对象,而对象永远是真值 }

不过,包装对象与普通内置类型共享同一个原型,因此可以给字符串等类型扩展功能:

String.prototype.firstCharacter = function() { return this.charAt(0); }; "abc".firstCharacter(); // = "a"

这一事实常用于polyfill(垫片):在旧版 JavaScript 子集中实现较新的语言特性,使其可用于老旧浏览器等环境。例如Object.create尚未在所有实现中可用时,可以这样 polyfill:

if (Object.create === undefined) { // 若已存在则不覆盖 Object.create = function(proto) { // 创建一个带正确原型的临时构造函数 var Constructor = function() {}; Constructor.prototype = proto; // 用它创建带正确原型的新对象 return new Constructor(); }; }

八、ES6 新增:let、const 与箭头函数

ES6(ECMAScript 2015)引入了块级作用域变量声明与新的函数语法。

let:在**词法作用域(块级)**中定义变量,区别于var的函数作用域;let声明的变量可以被重新赋值:

let name = "Billy"; name = "William"; // 允许重新赋值

const:同样按词法作用域定义变量,但一旦赋值不可重新赋值:

const pi = 3.14; pi = 4.13; // 不允许!

箭头函数(lambda 语法):允许像const/let变量一样在词法作用域中定义函数:

const isEven = (number) => { return number % 2 === 0; }; isEven(7); // false

传统语法中的"等价"写法:

function isEven(number) { return number % 2 === 0; }

之所以给"等价"打引号,是因为箭头函数不能在定义之前被调用(不存在函数声明提升),下面的用法是非法的:

add(1, 8); // 报错:add 尚未定义 const add = (firstNumber, secondNumber) => { return firstNumber + secondNumber; };

九、深入仓库:如何继续学习与验证

learnxinyminutes-docs 仓库把同一份 JavaScript 内容以多种语言组织:需要对照英文精确理解时查看 javascript.md,中文读者可对照 zh-cn/javascript.md,本文所依据的马来语版本位于 ms/javascript.md。这些文档的代码块本身就是可运行、带预期输出注释的完整示例——你可以将任意一节代码保存为.js文件,用 Node.js 运行验证(node example.js),或在浏览器控制台中逐行执行。

仓库还提供了配套的质量保障工具:lint/frontmatter.py 用于校验每篇文档 YAML front matter 的键名与类型(只允许name、where_x_eq_name、category、filename、contributors、translators六个键),体现了该项目"文档即代码、格式可验证"的组织理念。如果你打算为其他语言撰写类似的快速入门,可参考 CONTRIBUTING.md 中的贡献规范,并模仿现有javascript.md的分节结构与注释风格。

十、常见误区速查

以下是本文全部知识点中初学者最容易踩坑的几处,整理成速查清单:

误区正确理解来源章节
==与===混用==做隐式类型转换("5" == 5为 true),===不做(为 false);应始终用===3.4
return换行ASI 会在return后插入分号,导致函数返回undefined2
省略var赋值变量泄漏到全局作用域4.1
for/in遍历数组for/in不保证数组索引顺序,数组遍历应用for或for/of5
this与定义位置this由调用方式决定;拆出方法调用会丢失上下文,可用call/apply/bind显式绑定7.1–7.2
包装对象与原始值new Number(12)是对象(恒真值),与原始数字===不相等7.6
箭头函数提升箭头函数不可在定义前调用,不存在声明提升8

结语

从数值与隐式转换、数组与对象、控制结构,到函数作用域、闭包、this绑定与原型链,再到let/const/箭头函数——learnxinyminutes-docs 的 JavaScript 教程用最少的篇幅覆盖了这门语言"反直觉"的核心机制。对照 仓库源码 逐行运行这些注释示例,是理解 JavaScript 真实行为最直接的方式;而原型链、闭包与this这三块,正是后续学习模块化、框架源码与现代异步编程的必备地基。

  • 文档
  • 教程

【免费下载链接】learnxinyminutes-docs

Code documentation written as code! How novel and totally my idea!

项目地址:https://gitcode.com/gh_mirrors/le/learnxinyminutes-docs
点击查看免费下载

相关推荐

上一篇:如何在 10 分钟内为成片配上 AI 字幕:AutoSubs 本地字幕生成实战指南
下一篇:Windows激活与Office激活一次搞定:KMS_VL_ALL_AIO本地KMS激活指南

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/9 7:37:44

数据库连接算法详解:从基础概念到嵌套循环优化

一.连接算法1.连接的基本概念&#xff08;1&#xff09;内连接&#xff1a;只保留两张表之中能够匹配的内容&#xff08;2&#xff09;外连接&#xff1a;即使一方没有数据&#xff0c;也保留该侧数据&#xff0c;用NULL填充内连接&#xff1a;只取两边都能匹配上的部分。左外连…

作者头像 李华
网站建设 2026/10/9 7:33:58

TVA智能体技术体系概述(43):驱动具身智能闭环优化机制解析

前沿技术探索:TVA智能体(简称TVA) TVA智能体(亦称“AI智能体视觉”)是依托Transformer架构与“因式智能体”理论构建的新型工业视觉系统,也是当前最具代表性的具身视觉技术之一。它有机融合深度强化学习(DRL)、卷积神经网络(CNN)与因式分解算法(FRA),构成了具身智…

作者头像 李华