计算机 · 2021年12月19日 0

JavaScript Tutorial in 10 Days

Hackerrank网站上有一个10天的js教程,作为一个写js的半吊子正好可以过一遍来巩固下自己的js技能。

Day 0: Hello World

  • JavaScript程序是使用Unicode字符集编写的
  • JavaScript对大小写敏感
  • JavaScript忽略token之间的空白字符,包括换行
  • 当两个语句在不同行上的时候,JavaScript语句末尾的分号是可以被省略的
  • JavaScript中变量的命名规则与C语言类似,变量名由字母、数字、下划线或美元符号组成,且不能由数字开头
  • JavaScript支持的注释方法和C++相同

Day 0: DataTypes

  • JavaScript中的原始数据类型(primitive)共有六种:Number, String, Boolean, Symbol, Null, Undefined。他们不是对象而且没有成员方法。其他的数据类型都是Object
    1. Number
      JavaScript中的数字类型只有双精度浮点数一种类型,没有整数相关的类型。一些特殊的值包括:Number.MAX_VALUE,Number.MIN_VALUE,Infinity,-Infinity,NaN,Number.MAX_SAFE_INTEGER,Number.MIN_SAFE_INTEGER。*Number.isSafeInteger()*方法可以用来判断一个Number是否是整数(并且该整数不能由其他整数转为双精度浮点数得到)。
    2. Symbol
      Symbol可以用于作为Object属性的key。
    3. Null
      null值表示一个空对象。
    4. Undefined
      用于表示对象缺少某个属性或者一个变量只被声明没有被定义。
  • JavaScript中的原始数据类型是immutable的,即他们的值不能被改变,只能声明新的变量来储存对原始数据类型变量值的操作结果
  • 可以用typeof来判断变量类型
  • 变量需要声明后才能使用或者在声明的时候就定义该变量,但是未初始化的变量其值为undefined

Day 1: Arithmetic Operators

  • JavaScript支持**符号,表示幂运算
  • JavaScript的switch语句可以是任意类型,不同于C语言
  • JavaScript中的比较符号:
    • ==
      对于原始数据类型进行按值比较,对于对象数据类型则判断两个对象是否指向同一个对象
    • !=
      真值表与==相反
    • ===
      严格相等:
      • 操作数必须类型相同
      • 操作数必须严格相等
    • !==
      非严格相等:真值表与严格相等相反
  • 几个特殊的”假”值:
    • false
    • undefined
    • null
    • 0
    • NaN
    • “”

Day 1: Functions

  • JavaScript通过function关键字,声明一个函数对象,函数默认返回undefined或者通过return语句返回其他值
  • (Function Expression)函数表达式:在需要函数作为参数的地方,可以通过函数表达式直接定义一个匿名函数。函数表达式和函数的区别在于没有函数名。

Day 1: Let and Const

声明变量的三种方式:

  • var
    通过var声明的变量如果位于函数体内则其作用域为该函数,否则就是全局变量
  • let
    通过let声明的变量其作用域限于其位于的block
  • const
    通过const声明的变量不能被赋予新值,并且声明的时候必须被初始化

Day 2: Loops

JavaScript支持的几种循环语句:

  • for
  • while
  • do-while
  • for-in
    用于枚举Object的属性
  • for-of
    用于枚举Array,Map,Set,String,TypedArray,arguments等对象

Day 3: Arrays

mdn关于Array类的介绍

  • Array类的属性
    Array.length
  • 成员函数
    • Array.prototype.push
      在末尾添加元素
    • Array.prototype.forEach
      遍历数组元素
fruits.forEach(function(item, index, array) {
    console.log(item, index)
})
  • Array.prototype.pop
    移除最后一个元素
  • Array.prototype.shift
    移除第一个元素
  • Array.prototype.unshift
    在数组头部添加元素
  • Array.prototype.indexOf
    找到某个元素在数组中的索引
  • Array.prototype.slice
    数组浅拷贝
  • Array.prototype.sort
    数组排序,可以提供一个自定义的比较函数
  • Array.prototype.splice
    移除从某个索引开始的n个元素
let removedItem = fruits.splice(pos, 1)

Day 3: Try, Catch, and Finally

String Basics

string可以放在单引号或者双引号里面,双引号可以放在单引号里面来表示双引号字符,单引号可以放在双引号里面表示单引号字符

String的一些成员函数:

  • String.charAt
  • String.concat
  • String.includes
  • String.endsWith
  • String.indexOf
  • String.lastIndexOf
  • String.match
    在指定字符串中搜索正则表达式,返回一个Object,该Object具有三个属性:搜索的正则表达式,该正则表达式在该字符串匹配位置的索引,该字符串。
  • String.search
    match,但是只返回匹配的索引。
  • Strng.normalize
    没看懂这个函数在干啥~
  • String.repeat
  • String.replace
  • String.slice
    substring类似,但是可以接收负数(以字符串长度为模来进行运算)作为参数。
  • String.split
  • String.startsWith
  • String.substr
substr([start[, length]])
  • String.substring
substring([start[, end]])

substring方法会比较startend大小,选择较小的为起点,较大的为终点(不含)。

  • String.toLowerCase
  • String.toUpperCase
  • String.trim
  • String.trimLeft
  • String.trimRight

异常处理

异常处理的一般模式:

try {
} catch (e) {
} finally {
}

抛出异常的两种方式:

  • 直接throw vale
  • throw new Error(customError),这个customError是一个字符串,通过catch捕获这个异常时,可以通过message属性访问这个字符串。

Day 4: Create a Rectangle Object

  • JavaScript中的对象就是一堆属性的集合,属性的名字甚至可以是空字符串。
  • 访问属性的方式有两种:
    • objectName.propertyName
    • objectName['propertyName']
  • 构造对象的方式也有两种:
    • 使用Object的初始构造函数
      包括像map一样构造({property1:xxx,property2:xxx,property3:xxx})、使用new Object()声明对象然后为属性赋值、使用Object.create函数构造
    • 使用自定义的构造函数配合new表达式
function Actor(firstName, lastName, Age) {
    this.firstName = firstName;
    this.lastName = lastName;
    this.Age = Age;
}

Day 4: Classes

  • Functional Classes
    可以用函数来模拟类:
'use strict';

function Fruit (type) {
    this.type = type;
    this.color = 'unknown';
    this.getInformation = getFruitInformation;
}

function getFruitInformation() {
    return 'This ' + this.type + ' is ' + this.color + '.';
}

let lime = new Fruit('Mexican lime');
console.log(lime.getInformation());

lime.color = 'green';
console.log(lime.getInformation());

像上面代码中的getInformation函数也可以用匿名函数的方式直接定义在函数体内,但是这样会导致每定义一个Fruit对象时都会定义一个新的匿名函数。JavaScript中的每个函数都有一个Prototype属性,更好的做法是将getInfomation函数作为属性加入到Prototype属性中。

'use strict';

function Fruit (type) {
    this.type = type;
    this.color = 'unknown';
}

Fruit.prototype.getInformation = function() {
    return 'This ' + this.type + ' is ' + this.color + '.';
}

let lime = new Fruit('Mexican lime');
console.log(lime.getInformation());

lime.color = 'green';
console.log(lime.getInformation());
  • ClassesECMAScript6提供了类的语法糖,方便按照面向对象的方式编程。
    • 构造函数constructor
class Polygon {
    constructor(height, width) {
        this.height = height;
        this.width = width;
    }
}

let p = new Polygon(1, 2);
console.log('Polygon p:', p);
  • Class Expressions
let Polygon = class {
    constructor(height, width) {
        this.height = height;
        this.width = width;
    }
};

console.log('Polygon:', Polygon);
let p = new Polygon(1, 2);
console.log('p:', p);
let Polygon = class Polygon {
    constructor(height, width) {
        this.height = height;
        this.width = width;
    }
};

console.log('Polygon:', Polygon);
let p = new Polygon(1, 2);
console.log('p:', p);
  • Prototype Methods在类的定义中直接实现的方法是Prototype Methods
'use strict';

class Polygon {
    constructor(height, width) {
        this.height = height;
        this.width = width;
    }
    getArea() {
        return this.height * this.width;
    }
}

const square = new Polygon(10, 10);

console.log(square.getArea());
  • Static Methods
    如果函数声明时用了static关键字,那么只能通过类来调用该方法,不能通过该类的实例来调用该方法。
  • 继承
    通过extends关键字实现类的继承,子类通过super调用父类的构造函数和父类中定义的同名函数。
'use strict';

class Animal {
    constructor(name) {
        this.animalType = 'Animal'
        this.name = name;
    }
    type() {
        console.log(this.name, 'is type', this.animalType);
    }
    speak() {
        console.log(this.name, 'speaks.');
    }
}

class Dog extends Animal {
    constructor(name, collarColor) {
        super(name);
        this.animalType = 'Dog';
        this.collarColor = collarColor;
    }
    speak() {
        console.log(this.name, 'barks.');
    }
    collar() {
        console.log(this.name, 'has a', this.collarColor, 'collar.');
    }
}

let spot = new Dog('Spot', 'red');
spot.type();
spot.speak();
spot.collar();

// Because the Animal constructor only expects one argument,
// only the first value passed to it is used
spot = new Animal('Spot', 'white');
spot.type();
spot.speak();
try {
    spot.collar();
}
catch (exception) {
    console.log(exception.name + ': ' + exception.message
    + ' (collar is a method of Dog, not Animal).');
}

Day 5: Template Literals

  • 可以使用**`**来表示跨越多行的字符串。
  • expression interpolation
    可以用**${expression}**的方式在template literals中加入表达式或者直接使用字符串与表达式相加的方式。
  • Tagged Template Literals
    可以通过在每个**${expression}前面加一个名字的方式形成Tagged Template Literals**:
var a = 5;
var b = 10;

function foo(strings, ...values) {
    console.log("." + strings[0] + ".");
    console.log("." + strings[1] + ".");
    console.log("." + strings[2] + ".");
    console.log("." + strings[3] + ".");
    console.log(values[0]);
    console.log(values[1]);
    console.log(values[2]);
}

foo`Sum ${a + b}
Product ${a * b}
Division ${b / a}`;

Day 5: Arrow Functions

这个教程里讲的Arrow Functions大概就是lambda表达式

(parameter) => {statements}
parameter => {statements}
parameter => expression
parameter => {return expression}

(param1, param2, ..., paramN) => {statements}
(param1, param2, ..., paramN) => expression
(param1, param2, ..., paramN) => {return expression}

Day 7: Regular Expressions

  • 创建Regular Expression Literal:

可以通过把正则表达式的pattern放在两个’/’中间的方式来创建正则表达式:

   const re = /ab+c/;

或者直接声明一个正则表达式对象:

   const re = new RegExp('ab+c'); 	
  • 正则表达式的flag参数: /pattern/flagsnew RegExp(pattern[, flags])两种方式都提供了一个可选的flags参数,flags可以是以下参数的组合:
  • g:全局搜索;
  • i:忽略大小写;
  • m:跨行搜索;
  • uTreat pattern as a sequence of unicode code points
  • y:sticky;
  • 正则表达式中的回溯引用 问题:匹配同一个元音字母开头和结尾的字符串。需要使用回溯引用(backreference)来引用正则表达式前面部分匹配的结果(捕获组, capture groups)。
function regexVar() {
    /*
     * Declare a RegExp object variable named 're'
     * It must match a string that starts and ends with the same vowel (i.e., {a, e, i, o, u})
     */
    const re = /^([aeiou]).*\1$/;
    
    /*
     * Do not remove the return statement
     */
    return re;
}