【JavaScript 简明入门教程】为了Screeps服务的纯JS入门教程

0 前言

0-1 Screeps: World

请添加图片描述

  • 众所不周知,​Screeps: World是一款面向编程爱好者的开源大型多人在线即时战略(MMORTS)沙盒游戏,其核心机制是通过编写JavaScript代码来控制游戏中的单位(称为“Creep”),以建立和发展自己的帝国。
  • 在游戏中,玩家需要编写代码来自动化单位的行为,包括采集资源、建造建筑、扩张领土等。​这些代码会在游戏服务器上持续运行,即使玩家离线,单位也会按照预设的指令执行任务。
  • 那为了我们愉快的进入游戏玩耍之前,我们今天来速通一下JavaScript的基础语法
0-2 JavaScript

请添加图片描述

  • JavaScript(简称JS)是一种高级、解释型、动态的编程语言,主要用于==网页开发==。它最早由网景(Netscape)公司的布兰登·艾奇(Brendan Eich)在1995年开发,用于增强网页的交互性。如今,JavaScript已经发展成为一种功能强大的通用编程语言,广泛应用于前端、后端、移动端、游戏开发等领域
  • JavaScript的特点:
  1. 解释性语言:无需编译,浏览器或Node.js可以直接执行。
  2. 支持动态类型:变量的类型可以在运行时动态变化。
  3. 弱类型:允许不同类型的数据进行运算。
  4. 基于对象:JavaScript中的几乎所有内容(如数组、函数等)都是对象。
  5. 事件驱动和异步:使用事件监听和回调函数,使网页能响应用户操作。通过Promiseasync/await支持异步编程,提高性能。
  6. 跨平台:适用于Windows、Mac、Linux等各种操作系统,并且支持大多数浏览器(Chrome、Firefox、Edge等)。
0-3 食用本文前须知!!!
  • 通常大部分的JS教程都会和HTMLCSS绑定(毕竟是网页开发捏),但由于本教程的后续目的咱们是为了愉快的玩耍Screeps: World,故本教程将专注于JS 纯逻辑编程 为主,涵盖变量、函数、对象、异步编程等核心内容。
  • 本教程目录:
    • 编程环境搭建和HelloWorld
    • 变量声明和数据类型
    • 函数、作用域与闭包
    • 运算符
    • 异常处理机制
    • 异步机制、回调函数与Promise(Screeps用不上)
    • 类、继承与prototype
    • 多态
    • 数组(Array)

1 编程环境搭建和HelloWorld

1-1 Node.js简介

请添加图片描述

  • 通常传统的JavaScript·只能在浏览器环境中运行,无法直接访问文件系统、操作系统资源或数据库。为了解决上述局限性,我们引入Node.js~
  • Node.js是一个基于 Chrome V8 引擎JavaScript 运行环境,允许 JS 在服务器端运行。
1-2 Node.js的安装
  • 官网:Download Node.js请添加图片描述

  • 如官网所述,windows端的下载打开powershell

# Download and install fnm:
winget install Schniz.fnm# Download and install Node.js:
fnm install 22# 如果输入node -v 出现报错请输入下列代码
# 记得是在poweshell中输出
fnm env --use-on-cd | Out-String | Invoke-Expression# Verify the Node.js version:
node -v # Should print "v22.14.0".# Verify npm version:
npm -v # Should print "10.9.2".
  • winget 是 Windows 10/11自带的 包管理器(类似于 Linux 的 aptbrew)。
  • fnm(Fast Node Manager),是一个 Node.js 版本管理工具。方便管理多个 Node.js 版本并且可以快速进行切换。
  • npm(Node Package Manager)是 Node.js 自带的包管理工具,用于安装和管理 JavaScript 库。
  • 值得一提的是,上述代码在下载完成中验证Node.js的版本时候也许会出现下述报错:请添加图片描述
fnm env --use-on-cd | Out-String | Invoke-Expression
  • 上述代码fnm 的环境变量加载到当前的 PowerShell 会话中,使得 Node.js 的相关命令(如 node -v)能够在当前终端会话中正常使用。

1-3 HelloWorld与你的第一个js程序
  • IDE的话这里大家就随便自己选咯,我这里用的是VSCode
  • 我们新建一个文件命名为Hello.js
console.log("Hello World!");
  • 然后在终端直接使用Node.js运行js文件
node .\hellojs.js
  • 至此我们的第一个JS程序就完成辣请添加图片描述

  • 当然可以考虑安装一些扩展(当然你也可以纯记事本进行编程~)请添加图片描述

1-4 (补充)ESX是啥
  • ESX 通常是一个非正式的表达,泛指 ECMAScript 的各种版本(ES6 及后续版本),即 ES6、ES7、ES8、ES9 等等。
  • ES6(ECMAScript 2015) 是 JavaScript 语言的一次重大更新,引入了 letconst、箭头函数、类(class)、模块(import/export)等重要特性。
版本发布时间重要特性
ES6 (ES2015)2015let / const、箭头函数、类(class)、模板字符串、解构赋值、默认参数、import/export
ES7 (ES2016)2016Array.prototype.includes()、指数运算符 (**)
ES8 (ES2017)2017async/awaitObject.entries()Object.values()
ES9 (ES2018)2018Promise.finally()、正则表达式改进(命名捕获组等)
ES10 (ES2019)2019Array.prototype.flat(), Object.fromEntries()
ES11 (ES2020)2020BigIntPromise.allSettled()、可选链 ?.
ES12 (ES2021)2021String.replaceAll()、逻辑赋值运算符 (`&&=,
1-5 JavaScript 严格模式 ("use strict")
  • 严格模式("use strict")是 ES5 引入的一种 JavaScript 执行模式,旨在 消除 JavaScript 的不安全或错误用法,提高代码质量和执行效率
  • 开启严格模式后,JavaScript 代码会 抛出更多错误,阻止一些潜在的 Bug,同时提高 JS 引擎的优化效率。
  • 如何开启严格模式?
  1. 在代码的第一行添加
"use strict";console.log("严格模式开启!");
  1. 严格模式也可以局部应用于某个函数
function strictFunction() {"use strict";let x = 10;console.log(x);
}
strictFunction();
  • 严格模式总结:
规则解释
必须显式声明变量x = 10; 会报错
禁止重复变量声明var a = 10; var a = 20; 会报错
禁止删除变量/函数delete x; 会报错
普通函数的 thisundefinedfunction test() { console.log(this); }
禁止 with 语句with (obj) { console.log(x); } 会报错
禁止 eval() 影响作用域eval("var x = 10;"); console.log(x);
禁止八进制数var num = 010;

2 变量声明和数据类型

2-1 变量声明
  • JavaScript 提供了 varletconst 三种方式来声明变量
2-1-1 var(已过时,不推荐)
  • 变量可以在声明前使用(变量提升)。
  • 作用域是函数作用域(function scope)。
  • 可以重复声明同名变量。
console.log(a); // undefined(变量提升)
var a = 10;
var a = 20; // 允许重复声明
console.log(a); // 20
2-1-2 let(推荐使用)
  • 作用域是块作用域(block scope)。
  • 不能在声明前使用(不会变量提升)。
  • 不能重复声明同名变量。
console.log(b); // ReferenceError: Cannot access 'b' before initialization
let b = 10;
let b = 20; // ❌ SyntaxError: Identifier 'b' has already been declared
2-1-3 const(推荐用于常量)
  • 作用域是块作用域(block scope)。
  • 必须在声明时初始化,且值不能更改(不可变)。
  • 不能重复声明。
const PI = 3.14159;
PI = 3.14; // ❌ TypeError: Assignment to constant variable
2-2 原始数据类型
  • JavaScript 主要有七种原始数据类型一种对象类型
2-2-1 number(数字类型)
  • 包括整数和浮点数
  • 例如:103.14-5
  • 还有特殊值:Infinity-InfinityNaN
let num1 = 42;
let num2 = 3.14;
let notANumber = NaN;
2-2-2 string(字符串类型)
  • 由字符组成,使用单引号 '、双引号 " 或反引号 `(模板字符串)。
  • 例如:"hello"'world'`Hello, ${name}`
let str1 = "Hello";
let str2 = 'World';
let name = "Alice";
let str3 = `Hello, ${name}`; // 模板字符串
2-2-3 boolean(布尔类型)
  • 只有两个值:truefalse
  • 用于逻辑判断
let isOnline = true;
let hasError = false;
2-2-4 undefined(未定义类型)
  • 变量声明但未赋值时的默认值
let x;
console.log(x); // undefined
2-2-5 null(空值)
  • 表示“空值”或“无值”
  • 通常用于手动赋值,表示变量为空
let y = null;
2-2-6 symbol(符号类型,ES6 新增)
  • 创建独一无二的值,通常用于对象属性键
let sym = Symbol("unique");
2-2-7 bigint(大整数类型,ES11/ES2020 新增)
  • 适用于处理比 Number.MAX_SAFE_INTEGER 更大的整数
let bigNum = 9007199254740991n;

2-3 对象类型

JavaScript 只有一种复杂数据类型——对象(Object),包括:

  • 普通对象 { key: value }
  • 数组 [1, 2, 3]
  • 函数 function() {}
  • 日期 new Date()
  • 正则表达式 /abc/
let person = {name: "Alice",age: 25
};let arr = [1, 2, 3];function sayHello() {console.log("Hello!");
}
  • 可以使用 typeof 来检查变量类型:
console.log(typeof 42);       // "number"
console.log(typeof "hello");  // "string"
console.log(typeof true);     // "boolean"
console.log(typeof undefined); // "undefined"
console.log(typeof null);     // "object"(JavaScript 的历史遗留问题)
console.log(typeof {});       // "object"
console.log(typeof []);       // "object"
console.log(typeof function() {}); // "function"
console.log(typeof Symbol("id")); // "symbol"
console.log(typeof 9007199254740991n); // "bigint"

2-4 对象类型的创建,访问,属性引用
  • 创建对象
    • (下述内容部分超出范围还没说,但是相信熟悉其他编程语言的朋友们可以看懂)
    • (如果没看懂的话可以先往后看后面再回来看这一部分)
const person = {name: "Alice",age: 25,"home city": "New York", greet: function () {console.log("Hello, I'm " + this.name);}
};
2-4-1 访问对象的属性(一):使用 . 访问(常用)
  • . 访问方式只能用于符合变量命名规则的键(如 nameage)。
console.log(person.name); // 输出: Alice
console.log(person.age);  // 输出: 25
2-4-2 访问对象的属性(二):使用 [] 访问(适用于动态键)
  • 可以访问特殊字符(如空格、- 等)的属性(如 "home city")。
  • 可以用变量作为键名,适用于动态访问。
console.log(person["name"]);      // 输出: Alice
console.log(person["home city"]); // 输出: New York
  • 动态键访问
const key = "age";
console.log(person[key]);  // 输出: 25
2-4-4 访问对象的方法
person.greet(); // 输出: Hello, I'm Alice
2-4-5 检查对象是否包含某个属性
  1. 使用 in 关键字
console.log("name" in person);  // true
console.log("gender" in person); // false
  1. 使用 hasOwnProperty() 方法
console.log(person.hasOwnProperty("age"));  // true
console.log(person.hasOwnProperty("gender")); // false
2-4-6 遍历对象的属性
for (let key in person) {console.log(key + ": " + person[key]);
}
2-4-7 删除对象属性
  • 访问对象中不存在的属性时,返回 undefined,不会报错。
delete person.age;
console.log(person.age); // 输出: undefined


3 函数、作用域与闭包

  • JavaScript 中,函数(Function) 是代码的可复用块,允许封装逻辑并在需要时调用。同时,作用域(Scope) 决定了变量的可访问性。
  • JavaScript 提供了三种常见方式来定义函数:
3-1 函数声明(Function Declaration)
  • 关键字 function 开头
  • 支持函数提升(Hoisting),可以在定义前调用
console.log(square(5)); // 25function square(num) {return num * num;
}console.log(square(5)); // 25
3-2 函数表达式(Function Expression)
  • 没有函数名(匿名函数)
  • 赋值给变量后使用
  • 不支持函数提升(只能在定义后调用)
const greet = function(name) {return "Hello, " + name;
};
console.log(greet("Bob")); // Hello, Bob
3-3 箭头函数(Arrow Function,ES6)
  • 语法更简洁
  • 没有 this 绑定(this 取决于外部作用域)
  • 适合回调函数 & 简单逻辑
const add = (a, b) => {return a + b;
};
console.log(add(3, 4)); // 7
  • 单行省略 {}return
const multiply = (a, b) => a * b;
console.log(multiply(2, 3)); // 6

3-4 作用域(Scope)
  • 作用域决定了变量的可访问范围。JavaScript 有三种主要作用域
  1. 全局作用域(Global Scope)**: 声明在函数外部的变量,在整个脚本或浏览器窗口中可访问
  2. 函数作用域(Function Scope):在函数内部声明的变量,只能在该函数内部访问
  3. 块级作用域(Block Scope,ES6):letconst 具有块级作用域,var 没有块级作用域
{let x = 10;const y = 20;var z = 30; // ⚠️ var 例外
}
console.log(z); // ✅ 30
console.log(x); // ❌ ReferenceError
console.log(y); // ❌ ReferenceError

3-5 闭包(Closure)
  • 闭包是指内部函数可以访问外部函数的变量,即使外部函数已经执行完毕。4
  • 闭包的作用:
    • 数据私有化
    • 模拟 static 变量
function outer() {let count = 0;return function inner() {count++;console.log("Count:", count);};
}const counter = outer();
counter(); // Count: 1
counter(); // Count: 2
  • 关于闭包的调用方式及其注意点:
调用方式是否形成闭包?变量是否累积?原因
outer();❌ 否❌ 否inner 从未被执行
outer().inner();❌ 否❌ 否count 在每次 outer() 调用后重置
const counter = outer(); counter(); counter();✅ 是✅ 是counter 持有 count 的引用,形成闭包

3-6 this 关键字
  • this 是 JavaScript 中的特殊关键字,它的值取决于函数的调用方式
    1️⃣ 全局作用域
  • 非严格模式下,this 指向 window(浏览器)或 global(Node.js)。
  • 严格模式下,thisundefined
"use strict";
console.log(this);  // 输出:undefined

2️⃣ 作为对象方法调用

  • 此时this 指向对象本身
const obj = {name: "Alice",sayHi: function() {console.log(this.name);}
};obj.sayHi();  // 输出:"Alice"

3️⃣作为构造函数调用

  • 在构造函数中,this 指向新创建的对象
function Person(name) {this.name = name;
}const p = new Person("Bob");
console.log(p.name);  // 输出:"Bob"

4️⃣call / apply / bind 显式绑定

  • JavaScript 允许手动设置 this,可以使用:
    • call() 传递参数列表
    • apply() 传递参数数组
    • bind() 返回一个新的绑定函数
const user = { name: "Charlie" };function sayHello() {console.log("Hello, " + this.name);
}sayHello.call(user);   // 输出:"Hello, Charlie"
sayHello.apply(user);  // 输出:"Hello, Charlie"const boundFunc = sayHello.bind(user);
boundFunc();  // 输出:"Hello, Charlie"

5️⃣ 箭头函数中的 this

  • 箭头函数不会创建自己的 this,而是继承外部作用域的 this
const obj = {name: "Alice",sayHi: function() {const inner = () => {console.log(this.name);};inner();}
};obj.sayHi();  // 输出:"Alice"

4 运算符

  • 本节内容基础就给出表格大家自行参阅!
4-1 比较运算符
运算符描述示例结果
==宽松相等(值相等,类型可转换)'5' == 5true
===严格相等(值相等,类型也必须相同)'5' === 5false
!=宽松不等(值不相等,类型可转换)'5' != 5false
!==严格不等(值或类型不同)'5' !== 5true
>大于10 > 5true
<小于10 < 5false
>=大于等于10 >= 10true
<=小于等于10 <= 5false
4-2 算数运算符
运算符描述示例结果
+加法5 + 38
-减法5 - 32
*乘法5 * 315
/除法5 / 22.5
%取模(取余数)5 % 21
**指数(幂运算)2 ** 38
  • 然后是自增自减老规矩~
形式说明示例结果
x++后置自增(先返回值,再加 1)let a = 5; let b = a++;b = 5, a = 6
++x前置自增(先加 1,再返回值)let a = 5; let b = ++a;b = 6, a = 6
x--后置自减(先返回值,再减 1)let a = 5; let b = a--;b = 5, a = 4
--x前置自减(先减 1,再返回值)let a = 5; let b = --a;b = 4, a = 4
4-3 赋值运算符
运算符等价于示例
+=x = x + yx += 2;
-=x = x - yx -= 2;
*=x = x * yx *= 2;
/=x = x / yx /= 2;
**=x = x ** yx **= 2;
%=x = x % yx %= 2;

5 分支语句(条件语句) 和 循环语句

  • 本节同样基础,我们飞速略过
5-1 if-else 语句
  • 无需多言
if (/*condition1*/)  
{  }  
else if (/*condition2*/)  
{  }  
else  
{  }
5-2 switch 语句
  • 需要注意的是,js的switch 语句可以用于 任何类型stringnumberboolean,甚至 objectfunction)。
  • js的switch 语句支持嵌套(不建议你这么干)
  • 其他部分和其他语言相同:
    • case 语句后必须是具体的值,不能是范围或条件表达式。
    • break 语句用于阻止穿透(fall-through),否则会继续执行下一个 case 代码块。
    • default 是可选的,但建议写上,以防所有 case 都不匹配。
let color = "红色";
switch (color) {case "红色":console.log("你选择了红色");break;case "蓝色":console.log("你选择了蓝色");break;case "绿色":console.log("你选择了绿色");break;default:console.log("未知颜色");
}
5-3 for 循环
for (let i = 1; i <= 5; i++) {console.log(i);
}
  • 注意区分:for...infor...of
语句适用对象作用
for...in对象遍历对象的属性名
for...of数组、字符串遍历数组的
  • for...in:
let person = { name: "张三", age: 25, city: "北京" };
for (let key in person) {console.log(key + ": " + person[key]);
}
  • for...of
let numbers = [10, 20, 30];
for (let num of numbers) {console.log(num);
}
5-4 while 循环
let count = 1;
while (count <= 3) {console.log(count);count++;
}
5-5 do-while循环
let num = 1;
do {console.log(num);num++;
} while (num <= 3);
5-6 breakcontinue
  • 同理:
    • break 终止循环
    • continue跳过当前循环的剩余代码,直接进入下一次循环,不会终止整个循环。

6 异常处理机制

  • 在 JavaScript 开发中,程序运行时可能会遇到错误(比如变量未定义、JSON 解析失败、网络请求错误等)。为了防止这些错误导致程序崩溃,我们可以使用 异常处理机制 来捕获和处理错误。
6-1 异常处理机制 try-catch-finally
try {// 可能会出错的代码
} catch (error) {// 处理错误console.log("捕获错误:", error.message);
} finally{// 无论是否发生错误都会执行,适用于资源释放、日志记录等场景。
}
6-2 throw 关键字(手动抛出异常)
 throw new Error("你的错误信息");

7 异步机制、回调函数与Promise

  • 值得一提的是,Screeps 的代码是 Tick 驱动的,而不是时间驱动的,所以要用 Game.time 来管理逻辑,而不是 setTimeoutPromise
  • 因此本节对Screeps编程毫无作用,不感兴趣的朋友们可以直接跳过~
7-1 异步机制
  • JavaScript 是 单线程 语言,为了防止长时间执行的任务(如网络请求、文件读写)阻塞主线程,采用 异步编程 方式,使代码可以在等待操作完成的同时执行其他任务。
  • 常见的异步操作:
    • setTimeout / setInterval(定时器)
    • DOM 事件监听 (addEventListener)
    • AJAX / Fetch 请求(HTTP 请求)
    • Promiseasync/await
7-2 setTimeout / setInterval(定时器)
  • setTimeoutsetInterval 是 JavaScript 的内置函数。它属于 Web API,由 浏览器或 Node.js 提供,并不直接属于 JavaScript 语言核心。
方法用途特点
setTimeout(fn, delay)延迟执行 fn 一次仅执行一次,需要手动递归调用
setInterval(fn, delay)间隔执行 fn会一直执行,直到调用 clearInterval()
  • 下面我们来看二者具体的区别:
7-2-1 setTimeout
  • setTimeout 是 JavaScript 的内置函数,用于延迟执行代码
setTimeout(callback, delay, param1, param2, ...);
  • callback(必填):延迟执行的 函数(匿名函数或函数引用)。
  • delay(必填):延迟时间(单位:毫秒 ms1000ms = 1秒)。
  • param1, param2, ...(可选):传递给 callback 的参数。
  • 注意可以使用clearTimeout(timer); // 取消定时器
let timer = setTimeout(() => {console.log("不会执行");
}, 5000);clearTimeout(timer);  // 取消定时器
7-2-2 ``setInterval`
  • setInterval 是 JavaScript 内置的定时器函数,用于按指定时间间隔重复执行某个函数,直到调用 clearInterval() 停止。
setInterval(callback, delay, param1, param2, ...);
  • callback 要执行的函数(可以是匿名函数或函数引用)
  • delay 时间间隔(毫秒),1000ms = 1秒
  • param1, param2, … 传递给 callback 的参数(可选)
setInterval(() => {console.log("每 2 秒执行一次");
}, 2000);
  • 使用 clearInterval(intervalID) 停止 setInterval
let count = 0;
let intervalID = setInterval(() => {count++;console.log("执行次数:" + count);if (count === 5) {clearInterval(intervalID);  // 停止定时器console.log("定时器已停止");}
}, 1000);
7-3 回调函数
  • 回调函数 是一种最基本的异步处理方式,即将一个函数作为参数传递,待操作完成后调用该函数。
function fetchData(callback) {setTimeout(() => {console.log("数据获取成功");callback("数据内容");}, 2000);
}fetchData((data) => {console.log("回调函数接收数据:", data);
});

缺点:

  • 回调地狱(Callback Hell):多个回调嵌套使代码变得难以维护。
  • 错误处理不方便:错误需要通过回调手动传递,容易遗漏。
7-4 Promise
  • Promise 是 ES6 引入的一种异步编程解决方案,它可以更优雅地处理异步操作,避免回调地狱。
  • *Promise 三种状态:
    • pending(进行中)
    • fulfilled(已成功)
    • rejected(已失败)
function fetchData() {return new Promise((resolve, reject) => {setTimeout(() => {let success = true; // 模拟成功或失败if (success) {resolve("数据获取成功");} else {reject("数据获取失败");}}, 2000);});
}fetchData().then((data) => console.log("成功:", data))   // 处理成功.catch((error) => console.log("失败:", error)) // 处理失败.finally(() => console.log("请求完成"));       // 无论成功失败都会执行

优势:

  • 避免回调地狱,使代码更易读。
  • 提供 .then().catch().finally() 结构,方便管理异步操作。
7-5 async/await(基于 Promise)
  • async/awaitES8 引入的一种更直观的异步编程方式,它是 Promise 的语法糖,使异步代码更接近同步写法。
async function fetchData() {try {let data = await new Promise((resolve) => setTimeout(() => resolve("数据获取成功"), 2000));console.log(data);} catch (error) {console.log("错误:", error);} finally {console.log("请求完成");}
}fetchData();

特点:

  • await 关键字会等待 Promise 处理完成后再执行后续代码。
  • try/catch 可用于错误处理,比 .catch() 更直观。

8 类、继承与prototype

  • 在 JavaScript 中,类(Class)原型(Prototype) 是实现面向对象编程(OOP)的核心。ES6 之前,JavaScript 使用 原型继承(Prototype Inheritance),而在 ES6 引入了 class 语法,使面向对象编程更直观。
8-1 class(类)
  • ES6 引入 class 关键字,使 JavaScript 的面向对象代码更加清晰,但本质上它仍然是 基于原型的继承
class Person {constructor(name, age) {this.name = name;this.age = age;}// 定义方法(自动添加到原型上)sayHello() {console.log(`Hi, I'm ${this.name} and I'm ${this.age} years old.`);}
}// 创建对象
const person1 = new Person("Alice", 25);
person1.sayHello();  // 输出: Hi, I'm Alice and I'm 25 years old.
  • constructor():构造函数,在创建对象时自动执行。
  • sayHello():实例方法,所有 Person 对象共享。
8-2 静态方法 (Static Methods)
  • 在 JavaScript 中,静态方法是定义在类本身而不是类的实例上的方法。静态方法可以通过类名直接访问,而不能通过类的实例来调用。
  • 使用 static 关键字定义静态方法。
class MyClass {// 静态方法static staticMethod() {console.log("This is a static method");}// 实例方法instanceMethod() {console.log("This is an instance method");}
}// 调用静态方法
MyClass.staticMethod();  // 输出: This is a static method// 创建类的实例
const myInstance = new MyClass();// 调用实例方法
myInstance.instanceMethod();  // 输出: This is an instance method// 无法通过实例调用静态方法
// myInstance.staticMethod();  // TypeError: myInstance.staticMethod is not a function
8-3 继承(Inheritance)
  • 在 ES6 中,可以使用 extends 关键字实现 类继承,并使用 super() 调用父类的构造函数。
class Student extends Person {constructor(name, age, grade) {super(name, age);  // 调用父类的构造函数this.grade = grade;}study() {console.log(`${this.name} is studying in grade ${this.grade}.`);}
}const student1 = new Student("Bob", 20, "10th");
student1.sayHello();  // 继承父类的方法
student1.study();     // 输出: Bob is studying in grade 10th.
  • extends 让子类继承父类。
  • super() 允许调用 父类的构造函数必须在 constructor第一行执行。
  • 子类可以扩展自己的方法。

  • 静态方法也可以被继承,子类可以继承父类的静态方法,或者重写静态方法。
class Animal {static type() {console.log("I am an animal");}
}class Dog extends Animal {static type() {console.log("I am a dog");}
}// 调用父类静态方法
Animal.type();  // 输出: I am an animal// 调用子类重写的静态方法
Dog.type();  // 输出: I am a dog
8-4 prototype(原型)
  • JavaScript 是基于 原型继承 的语言,每个对象都有一个 __proto__ 属性,指向其 原型(prototype)
  • JavaScript 本质上仍然是基于原型的继承class 只是语法糖。
  • 类的方法实际上是添加到 prototype 上的。
function Animal(name) {this.name = name;
}// 添加方法到原型
Animal.prototype.makeSound = function () {console.log(`${this.name} makes a sound.`);
};const dog = new Animal("Dog");
dog.makeSound();  // 输出: Dog makes a sound.
console.log(Person.prototype.sayHello === person1.sayHello); // true
  • prototype 让所有实例共享方法,减少内存占用。
  • 直接操作 prototype 可实现手动继承。

9 多态

  • 多态(Polymorphism)指的是相同的方法在不同对象上具有不同的行为。在 JavaScript 中,多态主要通过 **方法重写(Method Overriding)****鸭子类型(Duck Typing)** 实现。
  • JavaScript 是支持多态的,但它不像 Java、C++ 那样有严格的类型系统,而是依赖于其动态特性和原型继承来实现多态。
9-1 方法重写(Method Overriding)
  • 子类可以重写父类的方法,实现不同的功能。
class Animal {makeSound() {console.log("Some generic animal sound");}
}class Dog extends Animal {makeSound() {console.log("Woof! Woof!");  // 重写父类的方法}
}class Cat extends Animal {makeSound() {console.log("Meow~");  // 重写父类的方法}
}// 统一调用
const animals = [new Dog(), new Cat()];//不关心 `animal` 的具体类型,只调用 `makeSound()`。
animals.forEach(animal => animal.makeSound());  
// 输出:
// Woof! Woof!
// Meow~
9-2 鸭子类型(Duck Typing)
  • “如果它会游泳、嘎嘎叫,那么它就是一只鸭子。” —— 鸭子类型 JavaScript 是动态语言,只要对象实现了相同的方法,就可以被当作同一种类型使用,而不关心它的类继承关系
class Bird {speak() {console.log("Chirp chirp");}
}class Robot {speak() {console.log("Beep boop");}
}// 统一处理不同对象
const entities = [new Bird(), new Robot()];
entities.forEach(entity => entity.speak());// 输出:
// Chirp chirp
// Beep boop
  • BirdRobot 没有继承同一个父类,但都实现了 speak() 方法。
  • entities.forEach(entity => entity.speak()); 实现了多态,因为 JS 只在运行时检查 speak() 是否存在,而不检查对象的类型。
9-3 函数多态(参数多态)
  • JavaScript 的函数可以接收不同类型的参数,表现出函数多态(Function Polymorphism)。
function printMessage(msg) {if (typeof msg === "string") {console.log(`Text: ${msg}`);} else if (typeof msg === "number") {console.log(`Number: ${msg}`);} else {console.log("Unknown type");}
}printMessage("Hello"); // Text: Hello
printMessage(123);     // Number: 123
printMessage(true);    // Unknown type

10 数组(Array)

  • 在JavaScript中,数组是存储一组数据的对象。数组的元素可以是任何类型,包括其他对象和函数等。
10-1 数组的基本创建和访问
  • 有两种常见的方式来创建数组:
// 使用数组字面量创建数组
let numbers = [1, 2, 3, 4];  // 数字数组
let names = ['Alice', 'Bob', 'Charlie'];  // 字符串数组// 使用Array构造函数
let emptyArray = new Array();  // 创建一个空数组
let anotherArray = new Array(10);  // 创建一个包含10个空位的数组
let filledArray = new Array(1, 2, 3);  // 创建并初始化数组
10-2 元素访问
  • 数组的索引是从 0 开始的。我们可以通过索引来访问数组的元素。
let arr = [10, 20, 30, 40];
console.log(arr[0]);  // 输出:10
console.log(arr[2]);  // 输出:30
  • indexOf():查找元素的索引位置。
let arr = [10, 20, 30, 40];
console.log(arr.indexOf(30)); // 输出:2
10-3 数组内建方法
  • push(): 向数组末尾添加一个或多个元素,返回新数组的长度。
let arr = [1, 2, 3];
arr.push(4); // arr变为 [1, 2, 3, 4]
console.log(arr); // 输出:[1, 2, 3, 4]
  • pop(): 删除数组末尾的元素,返回删除的元素。
let arr = [1, 2, 3, 4];
let poppedElement = arr.pop(); // poppedElement = 4
console.log(arr); // 输出:[1, 2, 3]
  • shift(): 删除数组开头的元素,返回删除的元素。
let arr = [1, 2, 3, 4];
let shiftedElement = arr.shift(); // shiftedElement = 1
console.log(arr); // 输出:[2, 3, 4]
  • unshift(): 向数组的开头添加一个或多个元素。
let arr = [1, 2, 3];
arr.unshift(0); // arr变为 [0, 1, 2, 3]
console.log(arr); // 输出:[0, 1, 2, 3]
  • splice(): 在任意位置添加或删除元素。
let arr = [1, 2, 3, 4];
arr.splice(2, 1, 5); // 从索引2删除1个元素,插入5
console.log(arr); // 输出:[1, 2, 5, 4]
  • map():对数组中的每个元素执行一个函数并返回一个新数组。
let arr = [1, 2, 3];
let squared = arr.map(x => x * x); // [1, 4, 9]
console.log(squared);
  • filter():根据条件过滤数组元素,返回一个新数组。
let arr = [1, 2, 3, 4];
let evenNumbers = arr.filter(x => x % 2 === 0); // [2, 4]
console.log(evenNumbers);
  • reduce():将数组元素通过某个函数累积成一个单一的值。
let arr = [1, 2, 3, 4];
let sum = arr.reduce((acc, current) => acc + current, 0); // 10
console.log(sum);
10-4 数组遍历
  • for 循环:传统的遍历方式。
let arr = [10, 20, 30];
for (let i = 0; i < arr.length; i++) {console.log(arr[i]);
}
  • forEach():对每个元素执行一个函数。
let arr = [10, 20, 30];
arr.forEach((element, index) => {console.log(`Index: ${index}, Value: ${element}`);
});
  • map():创建一个新数组,数组的每个元素是通过提供的函数对原数组每个元素进行处理的结果。
let arr = [1, 2, 3];
let doubled = arr.map(x => x * 2); // [2, 4, 6]
console.log(doubled);
10-5 注意点
  • 数组大小:在JavaScript中,数组实际上是对象,且键名是数字(数组的索引)。因此,处理大型数组时,性能可能会成为问题。尤其是使用shift()unshift()操作时,数组的所有元素会被重新索引,可能导致性能下降。

11 总结

  • 本教程我们从Screeps: World必须的JavaScript,将JSCSSHTML的教程分离,专注于讲解JS的原生基础语法。

  • 完成上述基础知识学习,你就可以正式开始学习玩耍Screeps咯,事不宜迟那就从教程开始吧:Screeps官方教程请添加图片描述

  • 如有错误,欢迎指出!!!!!

  • 感谢大家的支持!!!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/41455.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【CSS文字渐变动画】

CSS文字渐变动画 HTML代码CSS代码效果图 HTML代码 <div class"title"><h1>今天是春分</h1><p>正是春天到来的日子&#xff0c;花都开了&#xff0c;小鸟也飞回来了&#xff0c;大山也绿了起来&#xff0c;空气也有点嫩嫩的气息了</p>…

【论文阅读】基于思维链提示的大语言模型软件漏洞发现与修复方法研究

这篇文章来自于 Chain-of-Thought Prompting of Large Language Models for Discovering and Fixing Software Vulnerabilities 摘要 软件安全漏洞在现代系统中呈现泛在化趋势&#xff0c;其引发的社会影响日益显著。尽管已有多种防御技术被提出&#xff0c;基于深度学习&…

SpringMVC_day02

一、SSM 整合 核心步骤 依赖管理 包含 SpringMVC、Spring JDBC、MyBatis、Druid 数据源、Jackson 等依赖。注意点&#xff1a;确保版本兼容性&#xff08;如 Spring 5.x 与 MyBatis 3.5.x&#xff09;。 配置类 SpringConfig&#xff1a;扫描 Service 层、启用事务管理、导入…

基于ADMM无穷范数检测算法的MIMO通信系统信号检测MATLAB仿真,对比ML,MMSE,ZF以及LAMA

目录 1.算法运行效果图预览 2.算法运行软件版本 3.部分核心程序 4.算法理论概述 4.1 ADMM算法 4.2 最大似然ML检测算法 4.3 最小均方误差&#xff08;MMSE&#xff09;检测算法 4.4 迫零&#xff08;ZF&#xff09;检测算法 4.5 OCD_MMSE 检测算法 4.6 LAMA检测算法 …

CSS动画

目录 一、核心概念与语法 1. keyframes 关键帧 2. animation 属性 二、动画调速函数&#xff08;animation-timing-function&#xff09; 1. 预设值 2. 贝塞尔曲线 3. 步进函数&#xff08;steps()&#xff09; 三、动画控制与交互 1. 暂停与恢复 2. JavaScript 控制…

架构思维:预约抢茅子架构设计

文章目录 案例&#xff1a;预约抢茅子复杂度分析商品预约阶段等待抢购阶段商品抢购阶段订单支付阶段 技术方案商品预约阶段一、基于 Redis 单节点的分布式锁方案1. 核心流程2. 关键设计点 二、Redis 单节点方案的局限性1. 单点故障风险2. 主从切换问题 三、多节点 Redis 实现高…

PHP大马的使用

BestShell/best_php_shell.php at master Kevil-hui/BestShell 这里用到的是这位师傅的大马&#xff08;主要是从头开始写一个大马实在太麻烦了&#xff09; 用pikachu靶场进行上传的测试 在这里传马&#xff0c;这个是简单的前端校验&#xff0c;bp抓包改后缀就好了 上传成…

HCI 清除 SCP纳管残留信息

项目场景&#xff1a; 一台测试HCI主机&#xff0c;之前有连接了SCP&#xff0c;由于环境变更&#xff0c;无法与SCP连通&#xff0c;HCI残留了SCP纳管信息 问题描述 集群管理中没有脱离SCP的选项 点击vmware 虚拟机 显示被接管 云安全中心也显示被接管 原因分析&#xff1a; …

【算法day22】两数相除——给你两个整数,被除数 dividend 和除数 divisor。将两数相除,要求 不使用 乘法、除法和取余运算。

29. 两数相除 给你两个整数&#xff0c;被除数 dividend 和除数 divisor。将两数相除&#xff0c;要求 不使用 乘法、除法和取余运算。 整数除法应该向零截断&#xff0c;也就是截去&#xff08;truncate&#xff09;其小数部分。例如&#xff0c;8.345 将被截断为 8 &#x…

顺序表(C语言源码详解,附加测试代码)

目录 顺序表的基本实现 顺序表结构 顺序表的初始化 检查顺序表容量空间 顺序表的头插 顺序表的打印 顺序表的头删 顺序表的尾插 顺序表的尾删 顺序表的查找 ​编辑指定位置之前插入数据 指定位置删除数据 顺序表的销毁 顺序表的基本实现 顺序表结构 对顺序表的数…

draw.io费的思维导图软件、支持ProcessOn无水印导出。

draw.io的官方网址是 https://www.drawio.com/ 通过官方下载&#xff0c;本文只是安装及使用教程。 一、从别的思维导图软件导出并导入到Draw.io&#xff0c;&#xff08;ProcessOn为例&#xff09; 选择要付费下载流程图&#xff0c;并以ViSio格式导出&#xff08;后缀名…

springboot启动事件CommandLineRunner使用

什么是CommandRunner CommandRunner是springboot启动完成时会调用的一个runner 启动参数会传递到这个runner 我们能用来做一些初始化工作和缓存预热等工作 ApplicationRunner VS CommandRunner? 这两个Runner作用一样 只是得到的启动参数格式不一样 前者是一个Argument对象…

能源革命新突破:虚拟电厂赋能微电网智能调控,构建低碳生态新格局

在“双碳”目标的引领下&#xff0c;中央一号文件明确提出了“推进农村能源革命&#xff0c;深化绿色低碳技术应用”。作为能耗集中区域&#xff0c;产业园区如何实现清洁能源高效消纳与碳减排的目标成为了难题&#xff0c;中电国为推出的虚拟电厂与风光储充柴多能互补的微电网…

LabVIEW FPGA与Windows平台数据滤波处理对比

LabVIEW在FPGA和Windows平台均可实现数据滤波处理&#xff0c;但两者的底层架构、资源限制、实时性及应用场景差异显著。FPGA侧重硬件级并行处理&#xff0c;适用于高实时性场景&#xff1b;Windows依赖软件算法&#xff0c;适合复杂数据处理与可视化。本文结合具体案例&#x…

智慧高速,安全护航:视频监控平台助力高速公路高效运营

随着我国高速公路里程的不断增长&#xff0c;交通安全和运营效率面临着前所未有的挑战。传统的监控方式已难以满足现代化高速公路管理的需求&#xff0c;而监控视频平台的出现&#xff0c;则为高速公路的安全运营提供了强有力的技术支撑。高速公路视频监控联网解决方案 高速公路…

聚焦能源数字化转型,遨游通讯携智能化防爆手机亮相cippe2025

2025年3月26日&#xff0c;第二十五届中国国际石油石化技术装备展览会在北京中国国际展览中心&#xff08;新馆&#xff09;盛大开幕。作为全球石油石化行业的年度盛会&#xff0c;cippe2025北京石油展汇聚了来自全球75个国家和地区的近2000家企业&#xff0c;共同展示最新的石…

【银河麒麟系统常识】需求:安装.NET SDK

前提 网络状态正常(非离线安装)&#xff1b; 终端命令如下所示 根据不同系统的版本&#xff0c;自行选择&#xff0c;逐行执行即可&#xff1b; # 基于 Ubuntu/Debian 的银河麒麟系统 wget https://packages.microsoft.com/config/ubuntu/20.04/packages-microsoft-prod.deb -O…

K8S学习之基础五十:k8s中pod时区问题并通过kibana查看日志

k8s中pod默认时区不是中国的&#xff0c;挂载一个时区可以解决 vi pod.yaml apiVersion: v1 kind: Pod metadata:name: counter spec:containers:- name: countimage: 172.16.80.140/busybox/busybox:latestimagePullPolicy: IfNotPresentargs: [/bin/sh,-c,i0;while true;do …