菜鸟学 Javascript 系列 Note Part00 – 速览

菜鸟学 Javascript 系列 Note Part00 – 速览

现代 Web 浏览器都包含 Javascript 解释器,Node 使得让浏览器之外的 Javascript 编程成为可能,Javascript 是一门高级、动态、解释型编程语言,非常适合面向对象和函数式编程风格,Javascript 的变量是无类型的,语法大致与 Java 相仿,但除此之外这两门语言之间没有任何关系。

Javascript 是网景公司在 Web 诞生初期创造的,Javascript 是 Sun 公司授权使用的一个注册商标。网景公司将这门语言提交给 Ecma International 进行标准化,由于商标问题,这门语言沿用了别扭的名字 ECMAScript,但在实际过程中,大家仍然称这门语言为 Javascript。ECMAScript 缩写 ES。

2010 年以来,大多数主流浏览器都支持 ES5,ES6 发布于 2015 年,从 ES6 开始,ECMAScript 规范改为每年发布一次,语言版本也以发布的年份来标识 (ES2016、ES2017、ES2018、ES2019 和 ES 2020),

早期版本的 Javascript 有 BUG,为了保证向后兼容,无论一个特性的问题有多严重,也不能把它删除,但在 ES5 之后,程序可以选择切换到严格模式 use strict,在严格模式下,一些早期的语言错误会得到纠正,在 ES6 之后,使用新语言特性经常会隐式触发严格模式,例如,如果使用 ES6 的 class 关键字或者创建 ES6 模块,类和模块中的所有代码都会自动切换到严格模式,在这些上下文中,不能使用老旧、有缺陷的特性。

核心 Javascript 定义了最小限度的 API,可以操作数值、文本、数组、集合,映射等,但不包含任何输入和输出功能,输入输出功能是内嵌 Javascript 的 “宿主环境” 的责任,浏览器是 Javascript 最早的宿主环境,也是 Javascript 最常见的运行环境。2010 年以后,Javascript 有了另一个新的宿主环境 Node,与浏览器提供的 API 不同的是,Node 给予了 Javascript 访问整个操作系统的权限,允许 Javascript 程序读写文件、通过网络发送和接收数据以及发送和处理 HTTP 请求,Node 是实现 Web 服务器的一种流行方式,也是编写可以替代 shell 脚本的简单实用脚本的便捷工具。

如果只是尝试少量 Javascript 代码,最简单的方式是打开浏览器的 Web 开发者工具 (F12、Ctrl + Shift + I 或 Command + Option + I),然后选择 Console 标签页,之后就可以在提示符后面输入代码了:

图片[1]-菜鸟学 Javascript 系列 Note Part00 – 速览-零度非安全

除了使用浏览器控制台外,另一种方式是下载并安装 Node (https://nodejs.org/) 安装好后,打开终端,输入 node 回车开启 Javascript 会话:

图片[2]-菜鸟学 Javascript 系列 Note Part00 – 速览-零度非安全

当需要尝试更长的代码时,这种以行为单位的环境可能就不合适了,此时需要一个文本编辑器来编写代码,VS Code 就是一个不错的选择:

node snippet.js

也可以在 html 文件中来引用 Javascript 文件:

<script src="hello.js"></script>

Javascript 可以操作的另外两个非常重要的类型是对象和数组:

// Javascript 最重要的两种数据类型
// 对象是一个名/值对的集合,或者一个字符串到值的映射
let book = {
    topic: "Javascript",
    edition: 7
};

// 使用 . 或 [] 访问对象的属性
book.topic					// => "Javascript"
book["edition"]					// => 7: 另一种访问属性值的方法
book.author = "zeronohacker"	                // 通过赋值创建新属性
book.contents = {};				// {} 是一个没有属性的对象

// 使用 ?. (ES2020) 条件式访问属性
book.content?.ch01?.sect1		        // =>undefine: book.contents 没有 ch01 这个属性

// Javascript 也支持值的数组
let primes = [2, 3, 5, 7]
primes[0]
primes.length
primes[primes.length - 1]
primes[4] = 9;
primes[4] = 11;
let empty = [];
empty.length

// 数组和对象可以保存数组对象
let points = [
    {x: 0, y: 0},
    {x: 1, y: 1}
];
let data = {
    trial1: [[1, 2], [3, 4]],
    trial2: [[2, 3], [4, 5]]
};

函数预览:

// 函数是可以调用的有参数的 Javascript 代码块
function plus1(x) {
    return x + 1;
}
plus1(3)
// 函数也是值,可以赋给变量
let square = function(x) {
    return x * x;
}
square(plus1(3))

ES6 及之后,有一种定义函数的简写方式,这种简写的语法使用 => 来分隔参数列表和函数体,称为 箭头函数箭头函数 经常把一个未命名函数作为参数传给另一个函数:

const plus1 = x => x + 1;
const square = x => x * x;
plus1(3)					// => 4
square(plus1(3))				// => 16

在通过对象使用函数时,称其为方法:

let a = [];
a.push(1, 2, 3);
a.reverse();

// 我们也可以自己定义自己的方法,此时的 this 引用的是
// 方法所在的对象
points.dist = function() {
    let p1 = this[0];
    let p2 = this[1];
    let a = p2.x - p1.x;
    let b = p2.y - p1.y;
    return Math.sqrt(a * a + b * b);
};
points.dist()

控制结构:

function abs(x) {
    if (x >= 0) {
        return x;
    }
    else {
        return -x;
    }
}
abs(-10) === abs(10)

function sum(array) {
    let sum = 0;
    for (let x of array) {
        sum += x;
    }
    return sum;
}
sum(primes)

function factorial(n) {
    let product = 1;
    while (n > 1) {
        product *= n;
        n--;
    }
    return product;
}
factorial(4)

function factorial2(n) {
    let i, product = 1;
    for (i = 2; i <= n; i++) {
        product *= i;
    }
    return product;
}
factorial2(5)

面向对象简单示例:

class Point {
    constructor(x, y) {
        this.x = x;
        this.y = y;
    }
    
    distance() {
        return Math.sqrt(
        	this.x * this.x +
            this.y * this.y
        );
    }
}
let p = new Point(1, 1);
p.distance()

示例:字符频率柱形图

/*
 * 这个 Node 程序从标准输入中读取文本,计算文本中每个
 * 字母出现的频率,然后使用频率降序显示一个柱形图
 * 运行这个程序需要 Node 12 或更高版本
 *
 * 在一个 Unix 类型的环境中,可以像下面这样调用它:
 * node charfreq.js < corpus.txt
 */
class DefaultMap extends Map {
    constructor(defaultValue) {
        super();
        this.defaultValue = defaultValue;
    }

    get(key) {
        if (this.has(key)) {
            return super.get(key)
        }
        else {
            return this.defaultValue;
        }
    }
}

class Histogram {
    constructor() {
        this.letterCounts = new DefaultMap(0);
        this.totalletters = 0;
    }

    add(text) {
        text = text.replace(/\s/g, "").toUpperCase();
        for (let character of text) {
            let count = this.letterCounts.get(character);
            this.letterCounts.set(character, count + 1);
            this.totalletters++;
        }
    }

    toString() {
        let entries = [...this.letterCounts]
        entries.sort((a, b) => {
            if (a[1] == b[1]) {
                return a[0] < b[0] ? - 1 : 1;
            } else {
                return b[1] - a[1];
            }
        });

        for (let entry of entries) {
            entry[1] = entry[1] / this.totalletters;
        }

        entries = entries.filter(entry => entry[1] >= 1);

        let lines = entries.map(([l, n]) => '${l}: ${"#".repeat(Math.round(n))} ${n.toFixed(2)}%');

        return lines.join("\n");
    }
}

async function histogramFromStdin() {
    process.stdin.setEncoding("utf-8");
    let histogram = new Histogram();
    for await (let chunk of process.stdin) {
        histogram.add(chunk);
    }
    return histogram;
}

histogramFromStdin().then(histogram => { console.log(histogram.toString()); })
© 版权声明
THE END
喜欢就支持一下吧
点赞0赞赏 分享
评论 抢沙发

请登录后发表评论