本教程的这一部分内容是关于 JavaScript 语言本身的。
但是,我们需要一个工作环境来运行我们的脚本,由于本教程是在线的,所以浏览器是一个不错的选择。我们会尽可能少地使用浏览器特定的命令(比如 alert),所以如果你打算专注于另一个环境(比如 Node.js),你就不必多花时间来关心这些特定指令了。我们将在本教程的下一部分中专注于浏览器中的 JavaScript。
首先,让我们看看如何将脚本添加到网页上。对于服务器端环境(如 Node.js),你只需要使用诸如 "node my.js" 的命令行来执行它。
“script” 标签
JavaScript 程序可以在 <script> 标签的帮助下插入到 HTML 文档的任何地方。
比如:
<!DOCTYPE HTML> <html> <body> <p>script 标签之前...</p> <script> alert('Hello, world!'); </script> <p>...script 标签之后</p> </body> </html>
<script> 标签中包裹了 JavaScript 代码,当浏览器遇到 <script> 标签,代码会自动运行。
现代的标记
<script> 标签有一些现在很少用到的属性,但是我们可以在老代码中找到它们:
type 属性:<script type=...>
language 属性:<script language=...>
脚本前后的注释:
<script type="text/javascript"><!-- ... //--></script>
外部脚本
如果你有大量的 JavaScript 代码,我们可以将它放入一个单独的文件。
脚本文件可以通过 src 属性添加到 HTML 文件中。
<script src="/path/to/script.js"></script>
这里,/path/to/script.js 是脚本文件从站点根目录开始的绝对路径。当然也可以提供当前页面的相对路径。例如,src=“script.js” 表示当前文件夹中的 “script.js” 文件。
我们也可以提供一个完整的 URL 地址,例如:
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/3.2.0/lodash.js"></script>
要附加多个脚本,请使用多个标签:
<script src="/js/script1.js"></script> <script src="/js/script2.js"></script> …
请注意:
一般来说,只有最简单的脚本才嵌入到 HTML 中。更复杂的脚本存放在单独的文件中。
使用独立文件的好处是浏览器会下载它,然后将它保存到浏览器的缓存[1]中。
之后,其他页面想要相同的脚本就会从缓存中获取,而不是下载它。所以文件实际上只会下载一次。
这可以节省流量,并使得页面(加载)更快。
提醒:如果设置了 src 属性,script 标签内容将会被忽略。
一个单独的 <script> 标签不能同时有 src 属性和内部包裹的代码。
这将不会工作:
<script src="file.js"> alert(1); // 此内容会被忽略,因为设定了 src </script>
我们必须进行选择,要么使用外部的 <script src="…">,要么使用正常包裹代码的 <script>。
为了让上面的例子工作,我们可以将它分成两个 <script> 标签。
<script src="file.js"></script> <script> alert(1); </script>
总结
有关浏览器脚本以及它们和网页的关系,还有很多可学的。但是请记住,教程的这部分主要是针对 JavaScript 语言本身的,所以我们不该被浏览器特定的实现分散自己的注意力。我们将使用浏览器作为运行 JavaScript 的一种方式,这种方式非常便于我们在线阅读,但这只是很多种方式中的一种。
作业题
1. 显示一个提示语
重要程度:??????????
创建一个页面,然后显示一个消息 “I'm JavaScript!”。
在沙箱中或者在你的硬盘上做这件事都无所谓,只要确保它能运行起来。
你可以先看一下 新窗口的演示结果[2]。
在微信公众号「技术漫谈」后台回复 1-2-1 获取本题答案。
2. 使用外部的脚本显示一个提示语
重要程度:??????????
打开题目 1 的答案。将答案中脚本的内容提取到一个外部的 alert.js 文件中,放置在相同的文件夹中。
打开页面,确保它能够工作。
你可以先看一下 新窗口的演示结果[3]。
在微信公众号「技术漫谈」后台回复 1-2-1 获取本题答案。
现代 JavaScript 教程:开源的现代 JavaScript 从入门到进阶的优质教程。React 官方文档推荐,与 MDN 并列的 JavaScript 学习教程[4]。
在线免费阅读:https://zh.javascript.info/
参考资料
[1] 缓存: https://en.wikipedia.org/wiki/Web_cache
[2] 新窗口的演示结果: https://zh.js.cx/task/hello-alert/solution/
[3] 新窗口的演示结果: https://zh.js.cx/task/hello-alert/solution/
[4] React 官方文档推荐,与 MDN 并列的 JavaScript 学习教程: https://zh-hans.reactjs.org/docs/getting-started.html#javascript-resources
关注微信公众号「技术漫谈」,订阅更多精彩内容。
一阵子利用Balazor开发了一个NuGet站点,对WebAssembly进行了初步的了解,觉得挺有意思。在接下来的一系列文章中,我们将通过实例演示的方式介绍WebAssembly的一些基本概念和编程模式。首先我们先来说说什么是WebAssembly,它主要帮助我们解决什么问题。
本文演示实例下载:app1 app2
一、概述
二、WebAssembly程序(app.wat)
三、编译生成app.wasm
四、JavaScript程序
五、跑起来看看
六、调用导出函数
WebAssembly可以视为一种采用精简的”二进制格式”的“低等级”、“类汇编”语言。目前主流的浏览器均提供了对WebAssembly的支持,虽然WebAssembly的执行性能(它能够提供near-native的执行性能)是JavaScript无法比拟的,但是在表达能力和灵活性还是不如JavaScript,所以WebAssembly的出现并不是要取代JavaScript,而是作为JavaScript的“助手”,两者配合,各自发挥自身的优势,进而开发出更高质量的Web应用。
与其说WebAssembly像汇编,不如说它更像MSIL,因为它不是面向开发者的高级语言,而是高级语言的“编译目标”。虽然.NET 的运行时CLR不能直接执行C#、VB.NET和F#这样的高级语言编写的代码,而执行执行MSIL指令,但是我们可以将前者编译成后者。与之类似,我们也可以使用C、C++、C#、Rust和AssemblyScript(面向WebAssembly的TypeScript)作为开发语言,然后将代码编译成WebAssembly。
与汇编一样,虽然WebAssembly采用的是单纯的二进制格式,但是可以转换成文本形式。不仅如此,我们还可以按照这样的文本格式来编写程序(在接下来的内容中,我们提供的WebAssembly程序均采用这样的编写方式),并利用相应的工具将其编程成WebAssembly。WebAssembly文本采用一种名为S-expression的树形结构,我们定义的内容都存在与一个具体的“节点”中,每个节点通过小括号包裹起来,子节点直接内嵌于父节点中。由于模块是WebAssembly的基本部署和加载单元,所以module总是它们的根节点,如下所示的就是一个合法的最简单的WebAssembly程序。
(module)
为了让大家对WebAssembly文本的S-expression有一个大致的了解,我们采用这样的形势定义了一个进行整数加法运算的add函数。如下面的代码片段所示,我们定义的函数通过内嵌于module节点的(func)节点表示。它具有一些子节点,其中(export "add") 表示将这个函数以名称“add”进行导出,这意味着加载此模块的JavaScript应用可以直接调用此函数。额外三个节点(param $x i32) (param $y i32) (result i32)定义了函数的签名,揭示了此函数包含两个Int32(i32)的输入参数,返回值(结果)的类型也是Int32(i32)。为了提供可读性,同时也方面传参方面,我们将参数进行了命名($x和$y)
(module
(func (export "add") (param $x i32) (param $y i32) (result i32)
local.get $x
local.get $y
i32.add)
)
值得一提的是,WebAssembly仅仅支持4种数据类型,分别是32和64位的整数(i32和i64)和浮点数(f32和f64),连我们最常使用的字符串类型都不支持。由于字符串本质上就是一组字符序列,而一个字符本质上是采用某种编码的一段字节序列,所以WebAssembly中针对字符串的处理需要自行解决编解码的工作,所以直接以S-expression文本的形式编写WebAssembly程序并不容易。
上面说WebAssembly更像MSIL,还因为执行WebAssembly的VM是一个“堆栈机(Stack Machine)”,意味着它采用“压栈”的方式传递参数。而汇编面向的是真正的机器语言,是“堆栈机(Stack Machine)”和“寄存器机(Register Machine)”的结合,不仅参数传递可以采用堆栈,也可以采用寄存器。这一点可以从add函数的实现看出来,由于最终需要执行i32.add指令,我们需要在这之前调用local.get指令将两个参数压入栈中。i32.add执行后的结果也将入栈,并成为函数返回值。
在对WebAssembly以及基于S-expression的文本形式有了基本了解之后,我们通过一个简单的例子来演示一下一个WebAssembly程序大体上如何编写,我们着重关注JavaScript应用和WebAssembly之间的功能交互。我们创建一个空的目录,并创建两个文本文件app.wat和index.html,前者代表以S-expression文本形式编写的WebAssembly程序,后者是一个空的HTML页面,我们利用它提供的JavaScript程序加载并执行编译后的WebAssembly模块。
如下所示的是app.wat的内容,看起来很长,好在我们现在对S-expression有了基本的了解,所以理解起来没有什么问题。模块的第一个节点(func $print (import "js" "print") (param $op1 i32) (param $op2 i32) (param $op i32) (param $result i32))同样是定义了一个函数,我们将其命名为$print, 子节点(import "js" "print") 表明该函数是从作为宿主的Javascript应用中导入的,具体的路径为js->print。如果导入的Javascript对象通过变量imports表示,意味着imports.js.print表示的就是这个导入的对象。至于其余的四个节点(param $op1 i32) (param $op2 i32) (param $op i32) (param $result i32))同样是提供了函数的签名:个i32类型的参数,分别表示第一个操作数、第二个操作数、操作符(1,2,3,4分别代表加、减、乘、除)和执行结果。由于这个函数仅仅打印运算表达式,所以没有返回值。
(module
;; import js func print (op1, op2, op, result)
(func $print (import "js" "print")
(param $op1 i32)
(param $op2 i32)
(param $op i32)
(param $result i32))
;; int32 add (int32 x, int32 y)
(func $add (param $x i32) (param $y i32) (result i32)
local.get $x
local.get $y
i32.add)
;; int32 sub(int32 x, int32 y)
(func $sub (param $x i32) (param $y i32) (result i32)
local.get $x
local.get $y
i32.sub)
;; int32 mul(int32 x, int32 y)
(func $mul (param $x i32) (param $y i32) (result i32)
local.get $x
local.get $y
i32.mul)
;; int32 div(int32 x, int32 y)
(func $div (param $x i32) (param $y i32) (result i32)
local.get $x
local.get $y
i32.div_u)
(func $main
;; call print(1, 2, add(1,2), 1)
i32.const 1
i32.const 2
i32.const 1
i32.const 1
i32.const 2
call $add
call $print
;; call print(1, 2, sub(1,2), 2)
i32.const 1
i32.const 2
i32.const 2
i32.const 1
i32.const 2
call $sub
call $print
;; call print(1, 2, mul(1,2), 3)
i32.const 1
i32.const 2
i32.const 3
i32.const 1
i32.const 2
call $mul
call $print
;; call print(1, 2, div(1,2), 4)
i32.const 1
i32.const 2
i32.const 4
i32.const 1
i32.const 2
call $div
call $print
)
(start $main)
)
接下来我们定义了四个进行加、减、乘和除运算的函数add、sub、mul和div,它们与上面定义的add函数类似,不过由于缺少了(export “{funcname}”)节点,所以它们仅仅是四个内部函数而已。接下来,我们定义了一个$main函数,它会传入相同的参数(1、2)调用上述4个函数,并调用导入的print方法将包含结果的运算表达式打印出来。虽然命名为$main,但是它也仅仅是一个普通的函数而已,所以我们需要利用(start $main)节点将其作为入口函数,这样它就会在加载的时候自动执行了。
以文本形式编写的WebAssembly程序需要编译成二进制模块才能被加载执行,这里我们使用的wat2wasm这个工具,这个工具可以从这里下载。除了将wat文件转化成wasm文件的wat2wasm,下载包里还包含了其他一些有用的工具,比如进行反向操作的wasm2wat。上面编写的app.wat文件利用如下的命令就可以编译生成WebAssembly目标文件app.wasm。
wat2wasm app.wat -o app.wasm
如下所示的就是index.html文件的内容,我们着重关注其提供的JavaScript代码。我们首先定义被WebAssembly导入的用来输出运行表达式的函数print,然后按照导入路径js.print将其封装到一个导入对象中({"js":{"print":print}})。我们调用WebAssembly.instantiateStreaming函数以异步方式加载app.wasm模块,并创建对应的实例。具体下载app.wasm模块通过第一个参数提供的Promise(fetch("app.wasm"))完成,第二个参数代表导入对象。
<!DOCTYPE html>
<html>
<head></head>
<body>
<script>
var url="app.wasm";
var print=(op1, op2, op, result)=> {
switch (op) {
case 1:
console.log(`${op1} + ${op2}=${result}`);
break;
case 2:
console.log(`${op1} - ${op2}=${result}`);
break;
case 3:
console.log(`${op1} * ${op2}=${result}`);
break;
case 4:
console.log(`${op1} / ${op2}=${result}`);
break;
default:
console.log("invalid operator.");
}
};
WebAssembly
.instantiateStreaming(fetch("app.wasm"),
{"js":{"print":print}});
</script>
</body>
</html>
我们采用相应的方式将当前目录发布为本地web站点,比如执行Python命令(python -m http.server
),然后我们利用浏览器访问此站点的默认文件index.html,浏览器的控制台输出就会看到WebAssembly模块初始化输出的四个运算表达式。
上面我们演示了WebAssembly模块在初始化的时候调用导入的JavaScript函数,现在我们来演示JavaScript应用如何调用从WebAssembly导出的函数,为此我们将app.wat的代码改写成如下的形式,仅仅保留4个导出的函数add、sub、mul和div。
(module
(func (export "add") (param $x i32) (param $y i32) (result i32)
local.get $x
local.get $y
i32.add)
(func (export "sub") (param $x i32) (param $y i32) (result i32)
local.get $x
local.get $y
i32.sub)
(func (export "mul") (param $x i32) (param $y i32) (result i32)
local.get $x
local.get $y
i32.mul)
(func (export "div") (param $x i32) (param $y i32) (result i32)
local.get $x
local.get $y
i32.div_u)
)
index.html中的Javascript代码也做了如下的修改:我们在调用WebAssembly.instantiateStreaming函数成功加载WebAssembly模块并创建对应模块实例后,利用返回结果的instance属性得到这个模块实例。模块导出的成员都保存在该实例的exports属性返回的集合中,为此我们从中提取出导出的四个返回,并利用它们完成对应的运算后,调用console.log函数将包含结果的运算表达式输出到控制台上。由于WebAssembly模块不在需要调用导入的函数,所以调用instantiateStreaming函数的时候不需要在指定导入对象。
<!DOCTYPE html>
<html>
<head></head>
<body>
<script>
var url="app.wasm";
WebAssembly
.instantiateStreaming(fetch("app.wasm"))
.then(result=> {
var exports=result.instance.exports;
var result=exports.add(1,2);
console.log(`1 + 2=${result}`);
result=exports.sub(1,2);
console.log(`1 - 2=${result}`);
result=exports.mul(1,2);
console.log(`1 * 2=${result}`);
result=exports.div(1,2);
console.log(`1 / 2=${result}`);
});
</script>
</body>
</html>
程序运行之后,浏览器的控制台上依然会输出相同的结果。
喽,大家好,我是Giggle,一个专注于做自己原创作品的人,很高兴能在这里和大家分享一下我多年的编程经验,希望能给大家带来实质性的收获~
首先,我们先来简短的介绍一下什么是HTML,HTML就是网页代码,当你打开浏览器,输入网址后显示的网页其实可以叫做HTML代码,但是一个网站绝不可能仅仅只有HTML代码就能完成的,它还需要CSS,JS来配合HTML才能达到你想看到的结果,那么今天我们就先来讲讲前端(前端web中包含了HTML,CSS,JS等)中HTML,至于后端和前端的其他内容,我们后期会和大家讲明白的。
那么既然说到了HTML,就少不了需要有编辑软件来写这些代码。如果我们仅仅用win自带的记事本来编辑,那是很难的,win自带的记事本会自作聪明改变你的编码模式,所以我们给大家推荐几款比较适合入门的同学用的编辑软件:
1.Notepad++;2.Sublime Text;3.Editplus
那么在开始讲HTML之前,我先来教大家一个比较简单的装逼模式,那就是开发者模式,开发者模式是在大部分浏览器都有的功能,当你按下F12就会跳出来
那么,这个就是开发者模式,这个有什么用呢?
其实很多时候我们调试页面都需要用到这个东西,接下来我给大家演示一下怎么在无形中装逼
首先我们可以打开支付宝的网页版
你发现你可能只有四位数或者五位数的存款,没关系,下面我就教大家怎么修改这个数字
首先我们按F12打开开发者模式
点一下我蓝色箭头所指的那个(快捷键:Shift+Ctrl+C)
3.移到你想要更改的数字上,然后点左键
4.你会发现右侧会有一行蓝色的代码,把它点开点开
你有没有发现,有个0和.00,其实这两个就是刚才点击的那个余额,我们双击开发者模式中的那个0,就可以更改他了,比如我们改成7895试试(改完记得回车)
是不是我们就已经把余额给改了呢,但是有点脑子的都知道,这是假的,一刷新就没了,但也算是一个小技巧吧,毕竟不做互联网的人真的很少知道开发者模式,那么接下来的这段时间我们会和大家讲解Html的入门与小Demo,我们明天见~
*请认真填写需求信息,我们会在24小时内与您取得联系。