MK
摩柯社区 - 一个极简的技术知识社区
AI 面试

JavaScript基本语法与结构解析

2021-05-122.8k 阅读

JavaScript 变量

在 JavaScript 中,变量是用于存储数据值的容器。变量的声明和使用是编程的基础操作之一。

变量声明

JavaScript 有几种声明变量的方式,其中最常见的是使用 varletconst 关键字。

  1. var 关键字:这是 JavaScript 早期用于声明变量的关键字。它具有函数作用域,而不是块级作用域。
function exampleVar() {
    if (true) {
        var localVar = 'I am a var variable';
        console.log(localVar);
    }
    console.log(localVar);
}
exampleVar();

在上述代码中,localVar 虽然在 if 块内声明,但由于 var 的函数作用域特性,在 if 块外部依然可以访问到它。

  1. let 关键字let 是 ES6 引入的声明变量的关键字,它具有块级作用域。
function exampleLet() {
    if (true) {
        let localVar = 'I am a let variable';
        console.log(localVar);
    }
    // console.log(localVar); // 这行代码会报错,因为 localVar 在此处不可访问
}
exampleLet();

这里 localVarif 块外部无法访问,因为 let 定义的变量只在其所在的块级作用域内有效。

  1. const 关键字const 同样是 ES6 引入的,用于声明常量。常量一旦声明,其值就不能再改变,并且也具有块级作用域。
function exampleConst() {
    const PI = 3.14159;
    // PI = 3.14; // 这行代码会报错,因为 PI 是常量,不能重新赋值
    console.log(PI);
}
exampleConst();

变量命名规则

  1. 只能包含字母、数字、下划线(_)和美元符号($:例如 myVariable_underscore$dollar 都是合法的变量名,但 1stVariable 是不合法的,因为变量名不能以数字开头。
  2. 不能是 JavaScript 关键字或保留字:像 ifelsefunction 等关键字不能作为变量名。保留字如 await(在非 async 函数中)也不能用作变量名。
  3. 区分大小写myVarMyVar 是两个不同的变量。

数据类型

JavaScript 拥有丰富的数据类型,可分为原始数据类型和引用数据类型。

原始数据类型

  1. 数值(Number):JavaScript 中的数值类型既可以表示整数,也可以表示浮点数。
let integer = 42;
let floatingPoint = 3.14;
let anotherNumber = Number('42'); // 将字符串转换为数值
console.log(typeof integer); // 输出 "number"

JavaScript 还提供了一些特殊的数值,如 NaN(表示非数字)、Infinity(表示无穷大)和 -Infinity(表示负无穷大)。

let notANumber = NaN;
let positiveInfinity = Infinity;
let negativeInfinity = -Infinity;
console.log(isNaN(notANumber)); // 输出 true
console.log(positiveInfinity > 1000000); // 输出 true
  1. 字符串(String):用于表示文本数据。字符串可以用单引号(')、双引号(")或模板字面量( )来定义。
let singleQuoted = 'This is a single - quoted string';
let doubleQuoted = "This is a double - quoted string";
let templateLiteral = `This is a template literal. The value of 2 + 2 is ${2 + 2}`;
console.log(templateLiteral); // 输出 "This is a template literal. The value of 2 + 2 is 4"

字符串提供了许多有用的方法,如 length 属性获取字符串长度,charAt() 方法获取指定位置的字符等。

let str = 'Hello, World!';
console.log(str.length); // 输出 13
console.log(str.charAt(0)); // 输出 'H'
  1. 布尔值(Boolean):只有两个值,truefalse,常用于逻辑判断。
let isDone = true;
let isError = false;
if (isDone) {
    console.log('Task completed');
}
  1. 空值(null):表示一个空的对象引用。
let myNull = null;
console.log(typeof myNull); // 输出 "object"(这是 JavaScript 的历史遗留问题)
  1. 未定义(undefined):当一个变量声明但未赋值时,其值为 undefined
let myVar;
console.log(myVar); // 输出 undefined
  1. 符号(Symbol):ES6 引入的一种新的原始数据类型,符号的值是唯一的。
let sym1 = Symbol('description');
let sym2 = Symbol('description');
console.log(sym1 === sym2); // 输出 false

引用数据类型

  1. 对象(Object):对象是一种复杂的数据结构,用于存储多个键值对。
let person = {
    name: 'John',
    age: 30,
    address: {
        city: 'New York',
        country: 'USA'
    }
};
console.log(person.name); // 输出 'John'
console.log(person.address.city); // 输出 'New York'

可以使用 Object.keys() 方法获取对象的所有键,使用 Object.values() 方法获取对象的所有值。

let keys = Object.keys(person);
let values = Object.values(person);
console.log(keys); // 输出 ['name', 'age', 'address']
console.log(values); // 输出 ['John', 30, {city: 'New York', country: 'USA'}]
  1. 数组(Array):数组是一种特殊的对象,用于存储有序的数据集合。
let numbers = [1, 2, 3, 4, 5];
console.log(numbers.length); // 输出 5
console.log(numbers[0]); // 输出 1

数组提供了许多方法,如 push() 在数组末尾添加元素,pop() 删除数组末尾的元素等。

numbers.push(6);
console.log(numbers); // 输出 [1, 2, 3, 4, 5, 6]
numbers.pop();
console.log(numbers); // 输出 [1, 2, 3, 4, 5]
  1. 函数(Function):在 JavaScript 中,函数也是一种对象。函数可以接受参数并返回值。
function add(a, b) {
    return a + b;
}
let result = add(3, 5);
console.log(result); // 输出 8

运算符

JavaScript 提供了丰富的运算符,用于执行各种操作。

算术运算符

  1. 加法(+:用于两个数值相加,当其中一个操作数是字符串时,会进行字符串拼接。
let num1 = 5;
let num2 = 3;
let sum = num1 + num2;
console.log(sum); // 输出 8

let str1 = 'Hello';
let str2 = 'World';
let combinedStr = str1 + ', ' + str2;
console.log(combinedStr); // 输出 'Hello, World'
  1. 减法(-)、乘法(*)、除法(/)和取模(%:这些运算符分别用于减法、乘法、除法和取模运算。
let subResult = num1 - num2;
let mulResult = num1 * num2;
let divResult = num1 / num2;
let modResult = num1 % num2;
console.log(subResult); // 输出 2
console.log(mulResult); // 输出 15
console.log(divResult); // 输出 1.6666666666666667
console.log(modResult); // 输出 2

赋值运算符

  1. 简单赋值(=:将右侧的值赋给左侧的变量。
let x = 10;
  1. 复合赋值运算符:如 +=-=*=/=%= 等,先进行相应的算术运算,再进行赋值。
let y = 5;
y += 3; // 相当于 y = y + 3
console.log(y); // 输出 8

比较运算符

  1. 相等(==)和严格相等(===== 会在比较前进行类型转换,而 === 不会。
console.log(5 == '5'); // 输出 true,因为会进行类型转换
console.log(5 === '5'); // 输出 false,类型不同
  1. 不相等(!=)和严格不相等(!==:与相等运算符相反。
console.log(5 != '5'); // 输出 false
console.log(5!== '5'); // 输出 true
  1. 大于(>)、小于(<)、大于等于(>=)和小于等于(<=:用于比较数值大小。
console.log(5 > 3); // 输出 true
console.log(5 < 3); // 输出 false

逻辑运算符

  1. 逻辑与(&&:只有当两个操作数都为 true 时,结果才为 true
let a = true;
let b = false;
console.log(a && b); // 输出 false
  1. 逻辑或(||:只要两个操作数中有一个为 true,结果就为 true
console.log(a || b); // 输出 true
  1. 逻辑非(!:用于取反操作,将 true 变为 falsefalse 变为 true
console.log(!a); // 输出 false

位运算符

  1. 按位与(&:对两个操作数的每一位进行与运算,只有当两位都为 1 时,结果位才为 1
let num3 = 5; // 二进制 0101
let num4 = 3; // 二进制 0011
let bitwiseAnd = num3 & num4; // 二进制 0001,结果为 1
console.log(bitwiseAnd);
  1. 按位或(|:对两个操作数的每一位进行或运算,只要有一位为 1,结果位就为 1
let bitwiseOr = num3 | num4; // 二进制 0111,结果为 7
console.log(bitwiseOr);
  1. 按位异或(^:对两个操作数的每一位进行异或运算,当两位不同时,结果位为 1
let bitwiseXor = num3 ^ num4; // 二进制 0110,结果为 6
console.log(bitwiseXor);
  1. 按位非(~:对操作数的每一位进行取反操作。
let bitwiseNot = ~num3; // 二进制 1010,结果为 -6
console.log(bitwiseNot);

流程控制语句

流程控制语句用于控制程序的执行顺序。

if...else 语句

用于根据条件执行不同的代码块。

let age = 18;
if (age >= 18) {
    console.log('You are an adult');
} else {
    console.log('You are a minor');
}

switch...case 语句

用于基于不同的条件执行不同的代码块,它比多个 if...else 语句更简洁。

let day = 'Monday';
switch (day) {
    case 'Monday':
        console.log('It is the start of the week');
        break;
    case 'Tuesday':
        console.log('The week is in progress');
        break;
    default:
        console.log('Another day of the week');
}

for 循环

用于重复执行一段代码指定的次数。

for (let i = 0; i < 5; i++) {
    console.log(i);
}

while 循环

只要指定的条件为 true,就会重复执行代码块。

let count = 0;
while (count < 3) {
    console.log(count);
    count++;
}

do...while 循环

while 循环类似,但它会先执行一次代码块,然后再检查条件。

let num = 0;
do {
    console.log(num);
    num++;
} while (num < 3);

函数

函数是 JavaScript 中封装可重用代码的一种方式。

函数定义

  1. 函数声明:使用 function 关键字定义函数。
function greet(name) {
    return 'Hello, ' + name;
}
let greeting = greet('John');
console.log(greeting); // 输出 'Hello, John'
  1. 函数表达式:将函数赋值给一个变量。
let addNumbers = function (a, b) {
    return a + b;
};
let sumResult = addNumbers(2, 3);
console.log(sumResult); // 输出 5
  1. 箭头函数:ES6 引入的一种更简洁的函数定义方式。
let multiply = (a, b) => a * b;
let product = multiply(4, 5);
console.log(product); // 输出 20

函数参数和返回值

  1. 参数:函数可以接受零个或多个参数,这些参数在函数调用时传递。
function calculateArea(radius) {
    return Math.PI * radius * radius;
}
let area = calculateArea(5);
console.log(area); // 输出约 78.53981633974483
  1. 返回值:函数可以通过 return 关键字返回一个值。如果没有 return 语句,函数默认返回 undefined
function sayHello() {
    console.log('Hello');
    // 这里没有 return 语句,所以默认返回 undefined
}
let result = sayHello();
console.log(result); // 输出 undefined

函数作用域和闭包

  1. 函数作用域:变量的作用域是其可访问的范围。函数作用域意味着变量在函数内部定义,在函数外部无法访问。
function innerFunction() {
    let localVar = 'I am only accessible inside this function';
    console.log(localVar);
}
// console.log(localVar); // 这行代码会报错,因为 localVar 在此处不可访问
innerFunction();
  1. 闭包:闭包是指函数可以访问其外部函数作用域中的变量,即使外部函数已经执行完毕。
function outerFunction() {
    let outerVar = 'I am from outer function';
    function innerFunction() {
        console.log(outerVar);
    }
    return innerFunction;
}
let closure = outerFunction();
closure(); // 输出 'I am from outer function'

对象

对象是 JavaScript 中重要的数据结构,用于组织和存储相关的数据和功能。

对象字面量

使用对象字面量可以快速创建对象。

let car = {
    brand: 'Toyota',
    model: 'Corolla',
    year: 2020,
    startEngine: function () {
        console.log('The engine has started');
    }
};
console.log(car.brand); // 输出 'Toyota'
car.startEngine(); // 输出 'The engine has started'

访问对象属性

  1. 点表示法:使用点(.)来访问对象的属性。
console.log(car.model); // 输出 'Corolla'
  1. 方括号表示法:使用方括号([])可以通过变量来访问对象属性,并且可以访问属性名包含特殊字符的属性。
let property = 'year';
console.log(car[property]); // 输出 2020

let specialProperty = 'engine type';
let specialCar = {
    'engine type': 'Gasoline'
};
console.log(specialCar[specialProperty]); // 输出 'Gasoline'

对象方法

对象方法是对象中定义的函数。

let personObject = {
    name: 'Alice',
    sayHello: function () {
        console.log('Hello, my name is'+ this.name);
    }
};
personObject.sayHello(); // 输出 'Hello, my name is Alice'

这里的 this 关键字指向调用该方法的对象。

原型和原型链

  1. 原型:每个 JavaScript 对象都有一个原型对象。原型对象可以包含属性和方法,这些属性和方法可以被对象继承。
function Animal(name) {
    this.name = name;
}
Animal.prototype.speak = function () {
    console.log(this.name +'makes a sound');
};
let dog = new Animal('Buddy');
dog.speak(); // 输出 'Buddy makes a sound'
  1. 原型链:当访问一个对象的属性或方法时,如果对象本身没有该属性或方法,JavaScript 会沿着原型链向上查找,直到找到该属性或方法,或者到达原型链的顶端(null)。
function Dog(name) {
    Animal.call(this, name);
}
Dog.prototype = Object.create(Animal.prototype);
Dog.prototype.constructor = Dog;
Dog.prototype.bark = function () {
    console.log(this.name +'barks');
};
let myDog = new Dog('Max');
myDog.bark(); // 输出 'Max barks'
myDog.speak(); // 输出 'Max makes a sound'

数组

数组是用于存储多个值的有序集合。

数组创建

  1. 数组字面量:使用方括号([])创建数组。
let numbersArray = [1, 2, 3, 4, 5];
  1. new Array() 构造函数:也可以使用 new Array() 构造函数创建数组。
let newNumbersArray = new Array(1, 2, 3);

数组操作

  1. 访问数组元素:通过索引访问数组元素,索引从 0 开始。
console.log(numbersArray[0]); // 输出 1
  1. 修改数组元素:可以通过索引修改数组元素的值。
numbersArray[2] = 30;
console.log(numbersArray); // 输出 [1, 2, 30, 4, 5]
  1. 添加和删除元素
    • push():在数组末尾添加一个或多个元素。
numbersArray.push(6);
console.log(numbersArray); // 输出 [1, 2, 30, 4, 5, 6]
- **`pop()`**:删除数组末尾的元素并返回该元素。
let poppedElement = numbersArray.pop();
console.log(poppedElement); // 输出 6
console.log(numbersArray); // 输出 [1, 2, 30, 4, 5]
- **`unshift()`**:在数组开头添加一个或多个元素。
numbersArray.unshift(0);
console.log(numbersArray); // 输出 [0, 1, 2, 30, 4, 5]
- **`shift()`**:删除数组开头的元素并返回该元素。
let shiftedElement = numbersArray.shift();
console.log(shiftedElement); // 输出 0
console.log(numbersArray); // 输出 [1, 2, 30, 4, 5]

数组遍历

  1. for 循环
for (let i = 0; i < numbersArray.length; i++) {
    console.log(numbersArray[i]);
}
  1. forEach() 方法
numbersArray.forEach(function (element) {
    console.log(element);
});
  1. map() 方法:用于创建一个新数组,其元素是原数组元素调用一个函数后的返回值。
let squaredNumbers = numbersArray.map(function (num) {
    return num * num;
});
console.log(squaredNumbers); // 输出 [1, 4, 900, 16, 25]
  1. filter() 方法:用于创建一个新数组,其元素是原数组中满足指定条件的元素。
let evenNumbers = numbersArray.filter(function (num) {
    return num % 2 === 0;
});
console.log(evenNumbers); // 输出 [2, 4]

模块

在 JavaScript 中,模块是一种将代码组织成独立单元的方式,有助于提高代码的可维护性和复用性。

ES6 模块

ES6 引入了原生的模块系统。一个模块可以导出变量、函数、类等,其他模块可以导入这些导出的内容。

  1. 导出:使用 export 关键字导出内容。
// math.js
export function add(a, b) {
    return a + b;
}
export const PI = 3.14159;
  1. 导入:使用 import 关键字导入模块中的内容。
// main.js
import {add, PI} from './math.js';
let sum = add(2, 3);
console.log(sum); // 输出 5
console.log(PI); // 输出 3.14159

其他模块系统

  1. CommonJS 模块:常用于 Node.js 环境。使用 exportsmodule.exports 导出,使用 require() 导入。
// math.js (CommonJS)
function add(a, b) {
    return a + b;
}
exports.add = add;
// main.js (CommonJS)
let math = require('./math.js');
let sumResult = math.add(2, 3);
console.log(sumResult); // 输出 5
  1. AMD(Asynchronous Module Definition):主要用于浏览器环境,通过 define() 定义模块,require() 加载模块。
// math.js (AMD)
define(function () {
    function add(a, b) {
        return a + b;
    }
    return {
        add: add
    };
});
// main.js (AMD)
require(['./math.js'], function (math) {
    let sum = math.add(2, 3);
    console.log(sum); // 输出 5
});

事件处理

在 JavaScript 中,事件处理用于响应用户的操作,如点击按钮、滚动页面等。

HTML 事件处理

可以在 HTML 标签中直接添加事件处理属性。

<button onclick="alert('Button clicked')">Click me</button>

DOM 事件处理

  1. 通过 addEventListener() 方法:这是一种更灵活的事件处理方式。
<button id="myButton">Click me</button>
<script>
    let button = document.getElementById('myButton');
    button.addEventListener('click', function () {
        console.log('Button clicked');
    });
</script>
  1. 事件对象:在事件处理函数中,可以访问事件对象,它包含了与事件相关的信息。
<input type="text" id="myInput">
<script>
    let input = document.getElementById('myInput');
    input.addEventListener('input', function (event) {
        console.log('Input value:'+ event.target.value);
    });
</script>

错误处理

在 JavaScript 中,错误处理是确保程序稳健运行的重要部分。

try...catch...finally 语句

用于捕获和处理异常。

try {
    let result = 10 / 0; // 这会导致一个除零错误
    console.log(result);
} catch (error) {
    console.log('An error occurred:'+ error.message);
} finally {
    console.log('This will always be printed');
}

自定义错误

可以通过继承 Error 类来创建自定义错误。

class MyCustomError extends Error {
    constructor(message) {
        super(message);
        this.name = 'MyCustomError';
    }
}
try {
    throw new MyCustomError('This is a custom error');
} catch (error) {
    if (error instanceof MyCustomError) {
        console.log('Caught custom error:'+ error.message);
    } else {
        console.log('Caught other error:'+ error.message);
    }
}

通过对上述 JavaScript 基本语法与结构的深入理解,开发者可以更好地利用这门语言进行各种应用程序的开发,无论是前端的网页交互,还是后端的服务器端编程。同时,随着不断的实践和学习,对 JavaScript 的掌握也会更加熟练和深入。