重学javascript

JavaScript是一种高级的、动态的、面向对象的编程语言,用于在Web浏览器中创建交互式的客户端应用程序。它最初由Netscape公司开发,现在是Web开发中不可或缺的组成部分之一。如果你已经对JavaScript有一定的了解,并且想要深入学习它的内部机制、语言运作方式、以及最佳实践,那么这篇文章就是为你准备的。

在本文中,我们将涵盖以下主题:

  • JavaScript的历史和发展
  • JavaScript的语言基础
  • JavaScript的数据类型和变量
  • JavaScript的运算符和表达式
  • 控制流的结构和函数
  • 对象和原型的概念
  • JavaScript的面向对象编程
  • 异步编程和事件驱动模型
  • JavaScript的错误处理和调试

JavaScript是在1995年由Netscape公司的Brendan Eich开发的。当时,Web浏览器只能显示静态HTML页面,没有任何交互功能。为了在Web页面中添加一些动态效果,Netscape开发了JavaScript语言。初始版本的JavaScript只支持基本的语言结构和操作,但随着Web应用程序的需求增加,语言也变得越来越复杂。

随着时间的推移,JavaScript的流行度也越来越高。当其他浏览器厂商开始实现JavaScript时,它成了一种国际标准,由Ecma International组织发布。这种标准被称为ECMAScript,它是JavaScript实现的基础。自那时起,ECMAScript已经发布了多个版本,最新的是ECMAScript 2021。

随着Web技术的不断发展,JavaScript变得更加复杂和强大,可以用于创建各种类型的应用程序,包括客户端应用程序、移动应用程序、后端服务器应用程序等。

JavaScript的语言基础

JavaScript的语言基础包括语法、语言元素、变量、作用域和执行上下文。在本节中,我们将介绍这些基础概念。

2.1 语法

JavaScript的语法类似于其他编程语言,它包括各种关键字、符号和结构。以下是一些常用的语法构造:

  • 变量声明:使用var、let或const关键字声明变量。
  • 函数声明:使用function关键字声明函数。
  • 条件语句:使用if和else关键字执行条件检查。
  • 循环语句:使用for、while和do-while关键字执行循环。
  • 逻辑运算符:包括与(&&)、或(||)、非(!)等运算符。

以下是一个使用JavaScript语法的示例:

var x = 10;
var y = 20;
if (x > y) {
  console.log("x is greater than y");
} else {
  console.log("y is greater than x");
}

2.2 语言元素

JavaScript的语言元素包括变量、函数、数组、对象和类等。在JavaScript中,每个元素都有自己的特定属性和方法。以下是一些常用的元素:

  • 变量:在JavaScript中,变量是存储值的容器。声明变量时需要使用var、let或const关键字。变量可以存储不同类型的数据,包括数字、字符串、布尔值等。
  • 函数:函数是一段可重复使用的代码,它可以接受输入值,并输出处理过的结果。函数可以声明在全局作用域和函数作用域内,并可以作为参数传递给其他函数。
  • 数组:数组是一种有序的、可变的集合。在JavaScript中,数组可以包含任意类型的元素,包括数字、字符串、布尔值、对象等。
  • 对象:对象是一个键值对集合,在JavaScript中,几乎所有的东西都是对象。对象可以包含属性和方法,并且属性可以是简单的数据类型,也可以是其他对象。
  • 类:在ES6中引入了类的概念,类是一种抽象的数据类型,它描述对象的属性和方法。

以下是一个使用JavaScript元素的示例:

// 声明一个函数
function add(a, b) {
  return a + b;
}

// 声明一个对象
var person = {
  firstName: "John",
  lastName: "Doe",
  age: 25,
  fullName: function() {
    return this.firstName + " " + this.lastName;
  }
};

// 声明一个类
class Car {
  constructor(make, model) {
    this.make = make;
    this.model = model;
  }

  details() {
    return this.make + " " + this.model;
  }
}

// 声明一个数组
var numbers = [1, 2, 3, 4, 5];

2.3 变量

在JavaScript中,变量可以使用var、let或const关键字声明。这些关键字的使用方式略有不同,如下所示:

  • var:使用var声明的变量可以在全局作用域和函数作用域内使用。如果在函数内没有使用var关键字声明变量,则该变量被视为全局变量。
  • let:使用let声明的变量作用域在声明它的块级作用域内有效,例如if、while和for循环等。
  • const:使用const关键字声明的变量是常量,它的值无法改变。

以下是一个使用不同变量类型的示例:

// 使用var声明的变量
var x = 10;

function test() {
  // y是全局变量
  y = 20; 
}

test();
console.log(x); // 10
console.log(y); // 20

// 使用let声明的变量
function test1() {
  let z = 30;

  if (true) {
    let z = 40;
    console.log(z); // 40
  }

  console.log(z); // 30
}

test1();

// 使用const声明的变量
const PI = 3.141592653589793;
console.log(PI);

2.4 作用域和执行上下文

在JavaScript中,作用域是指变量和函数的可访问性。JavaScript中有两种作用域:全局作用域和函数作用域。

全局作用域是指在JavaScript程序中没有任何函数中声明的变量。在全局作用域中声明的变量可以在程序中的任何地方使用。

函数作用域是指在函数内声明的变量。函数作用域内的变量只能在函数内部使用,并且在函数外部是不可见的。

每个JavaScript程序都有一个执行上下文(EC),它是一个抽象概念,描述了JavaScript代码的执行环境。JavaScript代码可以分为三个类型:全局代码、函数代码和eval代码。对于每个类型的代码,都有一个相应的执行上下文。执行上下文包括三个部分:变量对象、作用域链和this指针。

变量对象是JavaScript中函数的内部对象,它包括函数的所有变量、函数的参数,以及函数声明。作用域链是一组连接所有变量对象的链表。当JavaScript查找变量时,它首先在当前作用域的变量对象中查找,然后继续向上遍历作用域链,直到找到该变量或者到达全局作用域。this指针是指当前执行函数的对象。

以下是一个使用作用域和执行上下文的示例:

var globalVar = "global";

function outer() {
  var outerVar = "outer";

  function inner() {
    var innerVar = "inner";
    console.log(globalVar); // "global"
    console.log(outerVar); // "outer"
    console.log(innerVar); // "inner"
  }

  inner();
}

outer();

JavaScript的数据类型和变量

JavaScript有多种数据类型,包括数字、字符串、布尔值、对象、数组等。在本节中,我们将介绍这些数据类型及其用法。

3.1 数字

在JavaScript中,数字可表示为整数、浮点数、指数形式等。以下是一些常规数字类型的示例:

var number = 42; // 整数
var floatNumber = 3.14; // 浮点数
var exponentNumber = 2.998e8; // 指数

JavaScript也支持一些特殊值,例如Infinity表示正无穷大,-Infinity表示负无穷大,NaN表示非数字。以下是一些特殊值的示例:

var inf1 = Infinity; // 正无穷大
var inf2 = -Infinity; // 负无穷大
var nan = NaN; // 非数字

console.log(inf1 / inf2); // NaN
console.log(1 / 0); // Infinity
console.log("hello" / 2); // NaN

JavaScript还提供了一些数字函数和常量,例如Math对象包括各种用于数学计算的函数(例如sin、cos、tan、log等),并且包括常量π、自然常数e等。

3.2 字符串

JavaScript中的字符串可以由单引号或双引号括起来,也可以由反引号(`)括起来。使用反引号括起来的字符串称为模板字面量,它们支持字符串插值和多行文本等特殊语法。

以下是一些字符串类型的示例:

var str1 = "Hello World!"; // 使用双引号
var str2 = 'Hello World!'; // 使用单引号
var str3 = `Hello World!`; // 使用反引号

JavaScript中还有一些特殊的字符串字面量,例如转义序列和Unicode转义序列等。以下是一些特殊字符串的示例:

var escapeStr = "Julie said "hello" to me."; // 转义序列
var utfStr = "\u53ef\u7231\u7684 JavaScript"; // Unicode转义序列
console.log(escapeStr); // Julie said "hello" to me.
console.log(utfStr); // 可爱的 JavaScript

JavaScript的字符串可以通过常见的字符串操作函数进行处理,例如concat、slice、substr等。以下是一些常用字符串函数的示例:

var str = "Hello World!";
console.log(str.concat(" I am learning JavaScript.")); // Hello World! I am learning JavaScript.
console.log(str.slice(0, 5)); // Hello
console.log(str.substr(3, 5)); // lo Wo
console.log(str.length); // 12

3.3 布尔值

在JavaScript中,布尔值有两个可能的值:true和false。在JavaScript中,任何值都可以转换为布尔值。以下是一些布尔值转换的示例:

console.log(Boolean(0)); // false
console.log(Boolean("")); // false
console.log(Boolean("Hello")); // true
console.log(Boolean(undefined)); // false
console.log(Boolean(null)); // false
console.log(Boolean(NaN)); // false
console.log(Boolean({})); // true

除了普通的布尔值,JavaScript还提供了一些逻辑运算符,例如与(&&)、或(||)、非(!)等。这些运算符常常用于条件测试和逻辑布尔值的计算。

3.4 对象

在JavaScript中,对象是一种特殊的数据类型,它由一组属性和方法组成。对象的属性可以是简单的数据类型或其他对象。以下是一些示例:

var person = {
  firstName: "John",
  lastName: "Doe",
  age: 25,
  fullName: function() {
    return this.firstName + " " + this.lastName;
  }
};

console.log(person.firstName); // John
console.log(person.fullName()); // John Doe

除了常规的对象类型,JavaScript还提供了一些内置的对象类型。一些常见的内置对象类型包括:

  • 数组:一种由一组元素组成的对象类型。
  • 日期:实现日期和时间操作的对象类型。
  • 数学:提供数字操作函数的对象类型。

以下是使用内置对象类型的示例:

var arr = [1, 2, 3, 4, 5];
console.log(arr.length); // 5

var date = new Date();
console.log(date.getFullYear()); // 2021

console.log(Math.PI); // 3.141592653589793

3.5 类型检查

在JavaScript中,可以使用typeof运算符进行类型检查。以下是一些类型检查示例:

var x = 42;
console.log(typeof x); // number

var str = "Hello World!";
console.log(typeof str); // string

var arr = [1, 2, 3];
console.log(typeof arr); // object

var isTrue = true;
console.log(typeof isTrue); // boolean

var obj = {};
console.log(typeof obj); // object

var func = function() {};
console.log(typeof func); // function

JavaScript的运算符和表达式

JavaScript支持各种运算符和表达式,用于操作各种数据类型。在本节中,我们将介绍以下运算符类型:

  • 算术运算符:包括加号+、减号-、乘号 、除号/、取模%、指数运算符* 等运算符,用于对数字进行算术计算。
  • 比较运算符:包括等于==、不等于!=、大于>、小于<、大于等于>=、小于等于<=等运算符,用于比较数字或字符串的大小关系。
  • 逻辑运算符:包括与(&&)、或(||)、非(!)、条件运算符等运算符,用于测试布尔值的逻辑关系。
  • 位运算符:包括按位与&、按位或|、按位异或^、按位取反~、左移<<、右移>>等运算符,用于对数字的二进制位进行操作。
  • 赋值运算符:包括=、+=、-=、*=、/=、%=、&=、|=、^=、<<=、>>=等运算符,用于给变量赋值。
  • 三元条件运算符:用于根据三元条件的真值进行不同的操作,具体语法为condition? expr1 : expr2。

以下是一些运算符和表达式的示例:

var x = 10;
var y = 20;
console.log(x + y); // 30
console.log(x > y); // false
console.log(x && y); // 20
console.log(~x); // -11
console.log(x += 5); // 15
console.log(x > y ? "x is greater" : "y is greater"); // "y is greater"

控制流的结构和函数

控制流是指程序的执行方式,JavaScript中主要有以下几种控制流的结构:

  1. 条件语句:

条件语句用于根据某个条件来执行不同的代码块,JavaScript中有if语句、if…else语句、switch语句等。

if语句:

if (condition) { //执行该部分代码 }

if…else语句:

if (condition) { //执行该部分代码 } else { //执行该部分代码 }

switch语句:

switch(expression) { case value1: //执行该部分代码 break; case value2: //执行该部分代码 break; default: //执行该部分代码 break; }

  1. 循环语句:

循环语句用于重复执行某个代码块,JavaScript中有while循环、do…while循环、for循环等。

while循环:

while (condition) { //执行该部分代码 }

do...while循环:

do { //执行该部分代码 } while (condition);

for循环:

for (initialization; condition; increment) { //执行该部分代码 }
  1. 跳转语句:

跳转语句用于在代码块内跳转到不同的位置,JavaScript中有break语句、continue语句和return语句等。

break语句:

for (var i = 0; i < 10; i++) { if (i === 5) { break; } console.log(i); }

continue语句:

for (var i = 0; i < 10; i++) { if (i % 2 === 0) { continue; } console.log(i); }

return语句:

function myFunction() { return "这是一个返回值"; }

函数是具有特定功能的代码块,可以通过给函数传递参数来执行特定的操作,JavaScript中定义函数使用function关键字,如下所示:

function functionName(parameters) { //执行该部分代码 }

其中,parameters是函数的参数,可以为一个或多个。可以在函数内部使用if…else语句、循环语句等控制流结构来实现特定的功能。函数可以在需要的地方进行调用,以执行该函数的特定操作。

例如:

function addNumbers(x, y) { var sum = x + y; return sum; }
var result = addNumbers(5, 10); // 调用addNumbers函数,并将5和10作为参数传递进函数,将返回值赋给result变量。

对象和原型的概念

avaScript中的对象是一种数据类型,用于描述实体或抽象的事物,可以包含属性和方法等信息。在JavaScript中,对象可以通过字面量、构造函数或Object.create()等方式进行创建。对象可以被看做是属性的集合,每个属性都具有名称和值。

原型是JavaScript对象的一个属性,它包含了对其他相关对象的引用,这些相关对象被称为“原型对象”。原型对象包含了属性和方法,它们可以被所有引用它的对象所共享。当访问某个对象的属性或方法时,JavaScript会首先搜索该对象的属性列表,如果没有找到,就会在该对象的原型链中继续查找。

下面是一个通过字面量的方式创建对象,并利用原型继承方式创建一个新对象的例子:

// 创建一个person对象,包含name和age属性
var person = {
  name: "Tom",
  age: 25,
  // 通过方法在对象中创建function
  sayHello: function () {
    console.log("Hello, my name is " + this.name);
  }
};

// 通过直接继承person对象来创建一个新对象teacher
var teacher = Object.create(person);

// 在teacher对象中添加新属性
teacher.subject = "Mathematics";

// 在teacher对象中添加新方法
teacher.saySubject = function() {
    console.log("I teach " + this.subject);
}

// 调用teacher对象的方法
teacher.sayHello();     //输出“Hello, my name is Tom”
teacher.saySubject();   //输出“I teach Mathematics”

在这个例子中,首先通过字面量的方式创建了一个person对象,包含name和age属性和sayHello方法。然后,通过Object.create()方法来直接继承person对象的属性和方法,创建了一个新对象teacher。在teacher对象中添加了新属性和方法,并进行了调用。当调用teacher对象的方法时,JavaScript会首先在teacher对象的属性列表中查找相应的方法,没有找到就会继续在它的原型链中查找,最终找到了从person对象中继承的sayHello方法,并输出了结果。

JavaScript的面向对象编程

JavaScript是一种基于对象的编程语言,它支持面向对象编程的各种特性,包括封装、继承和多态等。下面是JavaScript中实现面向对象编程的一个简单的例子:

// 定义一个Animal类
class Animal {
  constructor(name, age) {
    this.name = name;
    this.age = age;
  }

  sayHello() {
    console.log(`Hello, my name is ${this.name}.`);
  }
}

// 定义一个Cat类,继承自Animal类
class Cat extends Animal {
  constructor(name, age, color) {
    super(name, age);
    this.color = color;
  }

  catchMouse() {
    console.log(`${this.name} is catching mouse.`);
  }
}

// 创建一个Cat对象
let cat = new Cat("Tom", 2, "white");

// 调用Cat对象的方法和属性
cat.sayHello();     //输出“Hello, my name is Tom.”
cat.catchMouse();   //输出“Tom is catching mouse.”

在这个例子中,我们定义了一个Animal类,并在其中定义了一个名为sayHello的方法。然后,我们定义了一个Cat类,继承自Animal类,并在其中添加了一个名为catchMouse的方法。最后,我们创建了一个Cat对象,可以调用它的sayHello和catchMouse方法。

在ES6之前,JavaScript没有类的概念,而是通过函数和原型来实现面向对象编程。下面是一个通过函数和原型实现面向对象编程的例子:

// 定义一个Animal类的构造函数
function Animal(name, age) {
  this.name = name;
  this.age = age;
}

// 在Animal类原型中添加sayHello方法
Animal.prototype.sayHello = function() {
  console.log(`Hello, my name is ${this.name}.`);
}

// 定义一个Cat类的构造函数,并继承自Animal类
function Cat(name, age, color) {
  Animal.call(this, name, age);
  this.color = color;
}

// 设置Cat类原型为Animal类原型的一个实例,实现继承
Cat.prototype = Object.create(Animal.prototype);

// 在Cat类原型中添加catchMouse方法
Cat.prototype.catchMouse = function() {
  console.log(`${this.name} is catching mouse.`);
}

// 创建一个Cat对象
let cat = new Cat("Tom", 2, "white");

// 调用Cat对象的方法和属性
cat.sayHello();     //输出“Hello, my name is Tom.”
cat.catchMouse();   //输出“Tom is catching mouse.”

在这个例子中,我们定义了一个Animal类的构造函数,并在原型中添加了一个sayHello方法。然后,我们定义了一个Cat类的构造函数,并在原型中添加了一个catchMouse方法。通过设置Cat类原型为Animal类原型的一个实例,实现了继承关系。最后,我们创建了一个Cat对象,可以调用它的sayHello和catchMouse方法。

异步编程和事件驱动模型

avaScript异步编程和事件驱动模型是Web开发中重要的概念。异步编程指的是一种编程方式,在此方式中,函数在执行时不会阻塞主线程的运行,而是通过使用回调函数、Promise对象或async/await等方式来处理异步操作。而事件驱动模型则是一种编程模式,其中事件会触发回调函数的执行,延迟了函数的调用时机,从而实现了异步编程。

例1:回调函数

function add(a, b, callback) {
  setTimeout(() =&gt; {
    callback(a + b);
  }, 1000);
}

function display(result) {
  console.log(result);
}

add(2, 3, display);  // 通过回调函数的方式执行异步操作
console.log("异步操作执行中...");  // 在异步操作执行时继续执行同步代码

在这个例子中,我们定义了一个add函数,用于执行异步加法操作,该函数通过回调函数的方式返回结果。然后,我们定义了一个display函数,用于处理add函数的结果,并输出到控制台。最后,我们调用add函数,并传递display函数作为回调函数参数。在异步操作执行的过程中,程序将继续执行同步代码,最后输出“异步操作执行中…”和异步操作的结果。

例2:Promise对象

function add(a, b) {
  return new Promise(function(resolve, reject) {
    setTimeout(() =&gt; {
      resolve(a + b);
    }, 1000);
  });
}

add(2, 3)
  .then(function(result) {
    console.log(result);
  })
  .catch(function(error) {
    console.log(error);
  });
console.log("异步操作执行中...");  // 在异步操作执行时继续执行同步代码

在这个例子中,我们定义了一个add函数,它返回一个Promise对象,用于处理异步加法操作。然后,我们调用add函数,并使用.then()和.catch()方法分别处理成功和失败的情况,并输出结果或错误信息。在异步操作执行的过程中,程序将继续执行同步代码,最后输出“异步操作执行中…”和异步操作的结果。

例3:async/await

function add(a, b) {
  return new Promise(function(resolve, reject) {
    setTimeout(() =&gt; {
      resolve(a + b);
    }, 1000);
  });
}

async function display() {
  try {
    const result = await add(2, 3);
    console.log(result);
  } catch (error) {
    console.log(error);
  }
}

display();
console.log("异步操作执行中...");  // 在异步操作执行时继续执行同步代码

在这个例子中,我们定义了一个add函数和一个async函数display,它们用于处理异步加法操作。注意到在async函数中,我们使用await关键字等待add函数的结果,然后通过try/catch语句处理返回结果或错误信息。最后,我们调用display函数,并在异步操作执行的过程中继续执行同步代码,最后输出“异步操作执行中…”和异步操作的结果。

总之,JavaScript异步编程和事件驱动模型可以帮助我们更好地处理异步操作,提高了程序的性能和可维JavaScript是一门单线程编程语言,这意味着它只能一次处理一个任务。但是,在现代Web应用程序中,我们需要执行很多长时间运行的操作,如网络请求、文件读写和用户交互等,如果使用同步编程方式,则可能导致UI卡顿或阻塞应用程序的运行。为了解决这些问题,JavaScript提供了异步编程模型和事件驱动模型。

异步编程模型通过回调函数、Promise和async/await等方式,允许程序在等待操作完成的同时,继续执行其他操作。当异步操作完成时,会触发回调函数或resolve Promise,才继续执行相应的操作。

事件驱动模型是一种广泛应用的异步编程模型,它基于事件和事件监听器,程序的响应是由事件的触发和相应的处理函数来控制的。在事件驱动模型中,程序会监听事件的发生,当事件发生时,会调用对应的事件处理函数来处理事件。

下面是JavaScript中的异步编程和事件驱动模型的一个简单例子:

// 异步执行一个网络请求
function fetchData(url, callback) {
  setTimeout(function() {
    callback("请求结果: " + url);
  }, 2000);
}

// 调用网络请求函数
console.log("程序开始执行");
fetchData("https://www.example.com", function(result) {
  console.log(result);
});
console.log("程序继续执行");

// 使用事件驱动模型实现异步编程
const EventEmitter = require('events');
const myEmitter = new EventEmitter();

// 在myEmitter中注册事件监听器
myEmitter.on('myEvent', function(data) {
  console.log('事件触发: ' + data);
});

// 触发事件
myEmitter.emit('myEvent', '传递的数据');

在这个例子中,我们定义了一个fetchData函数,用于模拟异步网络请求,请求完成后触发回调函数。我们调用fetchData函数,然后输出了“程序开始执行”和“程序继续执行”两个日志。当网络请求完成时,会调用回调函数,并输出请求结果。由于网络请求是异步的,所以程序可以在网络请求等待的同时继续执行其他操作。

在第二个示例中,我们使用了Node.js中的EventEmitter类,实现了事件驱动模型。我们创建了一个myEmitter事件对象,并在其中注册监听器来监听事件的发生。然后,我们调用myEmitter.emit方法触发事件,从而调用相应的监听器来处理事件。

JavaScript的错误处理和调试

JavaScript的错误处理和调试是在开发过程中非常重要的一部分。

错误处理是指在程序运行时遇到的错误,JavaScript会抛出一个exception异常对象。错误处理可以有如下方式:

  1. try-catch语句
try {
  //代码块
} catch (err) {
  //异常处理代码
}
  1. throw语句
function throwError() {
  throw new Error('出现错误');
}
  1. finally语句
try {
  //代码块
} catch (err) {
  //异常处理代码
} finally {
  //无论是否出现异常都会执行
}

调试可以使用以下方式:

  1. console.log输出信息
console.log("这是一个调试信息");
  1. debugger语句
function add() {
  var a = 10;
  debugger; // 在这里设置断点
  var b = 20;
  return a + b;
}
  1. 浏览器调试工具

chrome开发者工具、Firebug工具等都可以较为方便的进行js的调试工作。

举个例子:

function divide(a, b) {
  if (b == 0) {
    throw new Error('除数不能为0');
  }
  return a / b;
}

try {
  const result = divide(10, 0);
  console.log(result); //不会执行
} catch (err) {
  console.log(err.message); //输出: "除数不能为0"
}

上面的代码中,当传入的除数b为0时,会抛出一个Error对象,我们可以使用try-catch语句来捕获这个错误,输出相应信息进行处理。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值