JavaScript 笔记

Brief Syntax Introduction

  1. JS 是解释型语言

解释型语言 与 编译型语言:

解释型:一行一行看,容易出错但方便,可以及时方便地找到出错位置以及出错原因,容易跨平台(可以嵌入到其他软件)。
编译型:把高级语言预先翻译成机器语言,并把结果保存下来,速度快(编译器优化),不易出错,但不能跨平台(e.g. .exe can't be run in MacOS)。

  1. 行末分号非必需: JS 中的每一行都可以选择使用分号终止,即编译器会自动补全没有用分号的地方。

  2. JS 中的变量是弱类型的,即变量的类型只有在被赋值的时候才得到确认。

数据类型与变量

  1. const 用来申明常量(一旦声明后续值不可更改),let 用来申明变量(一个变量只能申明一次,值以及值的类型可以被多次更改)。

  2. JS 中允许一个变量未被提前申明就使用。此时该变量会被自动被申明为全局变量。若在程序的最开始加上 use strict 语句,则可以避免这支双刃剑带来的弊端。(在 strict 模式下,变量必须要先经过申明,才能被使用,否则会报错)

  3. JS 中的基本类型有数字、字符串、布尔值、符号、nullundefined。数字中不区分整数和浮点数。

  4. JS 中遇到计算除法时除数为 0 的情况时,不会报错,会根据被除数的值来返回对应的结果。若被除数是正数,则返回 Infinity ;若被除数是负数,则返回 -Infinity;若被除数是 0 ,则返回 NaN (Not a Number)。
    除以 0 的余数(1 % 0)为 NaN

  5. python 类似, JS 中一个 * 代表相乘, ** 则代表幂运算。

  6. JS 中 === 表示检查是否相等,!== 表示检查是否不等。

字符串

  1. JS 中的字符串用 ''"" 括起来表示。若想表达的字符串中本身含有 '",则需要用到转义字符。
    e.g. I'm "OK"! 的表示是:

    'I\'m \"OK\"!';
    
  2. 在 JS 中输出多行字符串的方式是用反引号。
    e.g.

    `No 
    \n
    anymore
    `;
    
  3. 与 python 类似,要把多个字符串连接起来,可以用 + 号连接。也可以通过模版字符串的方式来方便输出过程。(反引号与 ${} 的结合)

    let name = '小明';
    let age = 20;
    let message1 = '你好, ' + name + ', 你今年' + age + '岁了!';
    let message2 = `你好, ${name}, 你今年${age}岁了!`
    //message1 = message2
    
  4. JS 中的字符串是不可变的,即不能通过 s[id] = 'A' 的方式来将 sid 位置的字母改成 A

  5. JS 中有很多类似 python 和 C++ STL 中的字符串函数,如 toUpperCaseindexOf(搜索元素在数据结构中出现的位置,未找到则返回 -1),substring 等。

数组

  1. JS 中的数组可以包含任意数据类型,并通过索引来访问/修改每个元素。

    a = [1, 'hello, world', ['a', b, 100]];
    a[0] = 'qaq';
    a; // a = ['qaq', 'hello, world', ['a', b, 100]]
    
  2. 在 JS 中允许给数组的 length 赋一个新值。除此之外,假如进行了数组的越界访问,也不会报错。

    var arr = [1, 2, 3];
    arr.length = 6;
    arr; // arr 变为 [1, 2, 3, undefined, undefined, undefined]
    arr.length = 2;
    arr; // arr变为[1, 2]
    
    arr[4] = 'qaq';
    arr; // arr 变为 [1, 2, undefined, undefined, 'qaq']
    
  3. 同 python 的切片类似,slice() 可以将一个数组的局部“拿出来”,变成一个新的数组。

    var arr = ['A', 'B', 'C', 'D', 'E', 'F', 'G'];
    arr.slice(0, 3); // 从索引0开始,到索引3结束,但不包括索引3: ['A', 'B', 'C']
    arr.slice(3); // 从索引3开始到结束: ['D', 'E', 'F', 'G']
    var aCopy = arr.slice();
    aCopy; // ['A', 'B', 'C', 'D', 'E', 'F', 'G']
    
  4. 如果要在数组的头部添加若干元素,可以使用 unshift() ; shift() 则可以用来把数组的第一个元素删除。
    splice() 则可以从指定的索引开始删除若干元素,然后再从该位置添加若干元素。

    var arr = [1, 2, 3, 4];
    arr.unshift('A', 'B'); // 返回Array新的长度: 6
    arr; // ['A', 'B', 1, 2, 3, 4]
    arr.shift(); // 'A'
    arr; // ['B', 1, 2, 3, 4]
    // 从索引 1 开始删除 3 个元素,然后再添加 2 个元素:
    arr.splice(1, 3, 'qaq', 222); // 返回删除的元素 [1, 2, 3]
    arr; // ['B', 4, 'qaq', 222]
    
  5. 如果要在数组的尾部添加/删除若干元素,可以使用 push()pop()

    var arr = [1, 2];
    arr.push('A', 'B'); // 返回Array新的长度: 4
    arr; // [1, 2, 'A', 'B']
    arr.pop(); // pop()返回'B'
    arr; // [1, 2, 'A']
    arr.pop(); arr.pop(); arr.pop(); // 连续pop 3次
    arr; // []
    arr.pop(); // 空数组继续pop不会报错,而是返回undefined
    arr; // []
    

对象

在 JS 中,对象是一种无序集合数据类型,由若干键值对组成。用法与 python 中的 dictionary 很像。但 JS 对象的键必须是字符串,值可以是任意数据类型。这一点和 dictionary 对键和值类型的无限制不同( JS 中 Map 的引入解决了这个问题)。

var xiaoming = {
    name: 'Yiling Zhang',
    birth: 2003,
    school: 'Xidian University',
    height: 1.77,
    weight: 65,
    score: 100
};

函数

函数的定义与调用

function get_pow(x, y) {
    var res = 1, i;
    for (i = 1; i <= y; i++) res = res * x;
    return res;
}

var get_pow = function (x, y) {
    var res = 1, i;
    for (i = 1; i <= y; i++) res = res * x;
    return res;
};
//匿名函数,在 JS 中函数也可以作为变量,通过这个变量就可以调用该函数。

传入函数的多个变量以逗号分隔开。如果传入某个函数的变量的个数,比该函数预先设定的要多,程序仍然会返回正确的结果,且不会报错。如果要少,则不会报错,但是结果可能不正确。

在函数的内部,系统提供了关键字 arguments。该关键字只在函数内部起作用,通过该参数可以访问到传入该函数的所有参数。可以通过访问 arguments.length() 来获取到传入某个函数的参数的个数。

function abs() {
    if (arguments.length() == 0) return 0;
    else {
        var x = arguments[0];
        return x >= 0 ? x : -x;
    }
}

abs(); // 0
abs(-2, 1); // 2

变量作用域与解构赋值

局部作用域、块级作用域

若在函数内部用 var 申明变量,则该变量的作用域是该函数内部,即这是一个局部变量。 在 JS 中允许函数的嵌套,即某个函数内可以定义另一个函数。同时允许内函数和外函数中定义重名的变量。 函数在查找变量时从自身函数定义开始,从内向外查找。如果内部函数定义了与外部函数重名的变量,则内部函数的变量将“屏蔽”外部函数的变量。

use strict;
function f() {
    var x = 1;
    function g() {
        var x = 2;
        x; // x = 2
    }
    x; // x = 1
}

在函数内部中用 var 申明一个变量,该变量会在整个函数中都起作用,不具有块级作用域。用 let 来申明则不会有这种问题,新申明的变量会具有块级作用域。

function f() {
    var sum = 0;
    for (var i = 0; i < 100; i++) sum += i;
    i++; // 仍然可以使用在上一个循环内定义的i
}

function f() {
    var sum = 0;
    for (let i = 0; i < 100; i++) sum += i;
    i++; // SyntaxError (与在c++中的逻辑一样)
}

请严格遵守在函数内部首先申明所有变量这一规则!否则会出一些奇奇怪怪的错误。

全局作用域

不在任何函数内定义的变量就具有全局作用域。 JS 默认有一个全局对象window ,全局作用域的变量(变量、函数等)实际上被绑定到 window 的一个属性。

var x = 1;
alert(x); // 1
alert(windows.x); // 1
解构赋值

在 JS 中可以使用解构赋值,直接对多个变量同时赋值:

let [x, [y, z]] = ['hello', ['JavaScript', 'ES6']];
x; // 'hello'
y; // 'JavaScript'
z; // 'ES6'
var person = {
    name: '小明',
    age: 20,
    gender: 'male',
    passport: 'G-12345678',
    school: 'No.4 middle school'
};

let {name, passport : id} = person; // 把passport属性赋值给变量id:
name; // '小明'
id; // 'G-12345678'
// 注意: passport不是变量,而是为了让变量id获得passport属性:
passport; // Uncaught ReferenceError: passport is not defined

解构赋值在很多时候可以大大简化代码。例如,交换两个变量 \(x\)\(y\) 的值,可以这么写,不再需要临时变量:

var x = 1, y = 2;
[x, y] = [y, x]

快速获取当前页面的域名和路径:

var {hostname : domain, pathname : path} = location;

如果一个函数接收一个对象作为参数,那么,可以使用解构直接把对象的属性绑定到变量中。例如,下面的函数可以快速创建一个 Date 对象:

function buildDate({year, month, day, hour = 0, minute = 0, second = 0}) {
    return new Date(year + '-' + month + '-' + day + ' ' + hour + ':' + minute + ':' + second);
}

buildDate({ year: 2017, month: 1, day: 1 }); // Sun Jan 01 2017 00:00:00 GMT+0800 (CST)
// 传入的对象只需要year、month和day这三个属性

方法

可以给对象绑定函数。绑定到对象上的函数叫 方法 ,其在内部使用了 this 关键字。 在方法内部, this 始终指向当前对象。

var xiaoming = {
    name: '小明',
    birth: 1990,
    age: function () {
        var y = new Date().getFullYear();
        return y - this.birth;
    }
};

xiaoming.age; // function xiaoming.age()
xiaoming.age(); // 今年调用是25,明年调用就变成26了

若不通过某个对象直接在函数里调用 thisthis 默认指向 windows 。在 strict 模式下,函数的 this 指向的是 undefined ,从而系统会报错提醒你这里的不规范写法。故要保证 this 指向正确,必须用 obj.xxx() 的形式调用,或者可以用一个变量首先捕获 this

'use strict';

var xiaoming = {
    name: '小明',
    birth: 1990,
    age: function () {
        var y = new Date().getFullYear();
        return y - this.birth;
    }
};

var fn = xiaoming.age;
fn(); // Uncaught TypeError: Cannot read property 'birth' of undefined
'use strict';

var xiaoming = {
    name: '小明',
    birth: 1990,
    age: function () {
        var that = this; // 在方法内部一开始就捕获this
        function getAgeFromBirth() {
            var y = new Date().getFullYear();
            return y - that.birth; // 用that而不是this
        }
        return getAgeFromBirth();
    }
};

xiaoming.age(); // 25
posted @ 2023-10-07 17:06  BeyondLimits  阅读(18)  评论(0编辑  收藏  举报