学习JavaScriptday02

总结一些js中常用的基本概念20240401

正则

在JavaScript中,正则表达式(Regular Expression,简称regex)是处理字符串的强大工具,用于匹配、查找和替换文本。通过定义一套搜索模式,你可以用它来检查一个字符串是否符合某个模式(例如,是否有电子邮件地址的格式)、提取出匹配的字符串、或者用其他文本替换掉匹配到的文本。

创建正则表达式
在JavaScript中,可以通过两种方式创建正则表达式:

使用正则表达式字面量,由一对斜杠/包围的模式组成:

var regex = /pattern/;
//使用RegExp构造函数创建正则表达式对象:
var regex = new RegExp('pattern');

常用模式匹配符号
:匹配输入的开始。例如,/A/不匹配"apple"中的"A",但是匹配"An apple"中的"A"。
:匹配输入的结束。例如, / t :匹配输入的结束。例如,/t :匹配输入的结束。例如,/t/不匹配"eater"中的"t",但是匹配"eat"中的"t"。
.:匹配除换行符之外的任意单个字符。
*:匹配前一个表达式0次或多次。等价于{0,}。
+:匹配前一个表达式1次或多次。等价于{1,}。
?:匹配前一个表达式0次或1次。也用于表示非贪婪匹配。
\d:匹配一个数字。等价于[0-9]。
\w:匹配字母、数字或下划线。等价于[A-Za-z0-9_]。
|:选择符,匹配左边或右边的表达式。
[]:字符集合。匹配所包含的任意一个字符。
正则表达式的方法
test():测试字符串是否匹配某个模式,返回true或false。

var regex = /hello/;
console.log(regex.test('hello world')); // 输出: true

exec():在字符串中执行一个搜索匹配,返回一个匹配信息数组或null。

var regex = /\d+/;
console.log(regex.exec('room 101')); // 输出: ["101"]

match():字符串方法,用正则表达式进行匹配,返回匹配的结果数组或null。

var str = 'The rain in SPAIN stays mainly in the plain';
var result = str.match(/ain/g); // 使用全局搜索标志g
console.log(result); // 输出: ["ain", "ain", "ain"]

replace():字符串方法,用正则表达式来指定替换操作。

var str = 'Visit Microsoft!';
var newStr = str.replace(/Microsoft/, 'W3Schools');
console.log(newStr); // 输出: "Visit W3Schools!"

正则表达式是一个强大的工具,但由于其复杂性,它也是许多开发者觉得难以掌握的一部分。熟练使用正则表达式可以在处理字符串时大大提高你的效率。

Canvas

Canvas是HTML5提供的一个元素,用于在网页上绘制图形。它可以用来绘制路径、盒子、圆形、字符以及添加图像。Canvas元素本身只是一个容器,实际的绘图需要使用JavaScript来完成。这使得Canvas成为创建图形和游戏非常有用的工具。

基本用法
首先,在HTML中定义一个元素:

<canvas id="myCanvas" width="200" height="100" style="border:1px solid #000;"></canvas>

接下来,通过JavaScript来绘制图形:

// 获取canvas元素
var canvas = document.getElementById('myCanvas');
// 获取绘图上下文
var ctx = canvas.getContext('2d');

// 绘制一个填充的矩形
ctx.fillStyle = '#FF0000';
ctx.fillRect(0, 0, 150, 75);

Canvas的API
Canvas API提供了丰富的功能来绘制各种图形。以下是一些基本的API:

绘制矩形:

fillRect(x, y, width, height):绘制一个填充的矩形。
strokeRect(x, y, width, height):绘制一个矩形的边框。
clearRect(x, y, width, height):清除指定矩形区域,使其完全透明。
绘制路径:

beginPath():新建一条路径。
moveTo(x, y):将笔触移动到指定的坐标x以及y上。
lineTo(x, y):绘制一条从当前位置到指定x以及y位置的直线。
arc(x, y, radius, startAngle, endAngle, anticlockwise):绘制一个圆弧。
closePath():闭合路径。
stroke():绘制路径。
fill():填充路径。
样式和颜色:

fillStyle = color:设置图形的填充颜色。
strokeStyle = color:设置图形轮廓的颜色。
globalAlpha = transparencyValue:设置图形的透明度。
绘制文本:

fillText(text, x, y [, maxWidth]):在指定的位置填充文本。
strokeText(text, x, y [, maxWidth]):在指定的位置绘制文本轮廓。
绘制图像:

drawImage(image, x, y):在Canvas上绘制图像、Canvas或视频。

动画
要创建动画,通常的做法是使用window.requestAnimationFrame()来不断更新Canvas上的图形位置。

function draw() {
  // 更新图形位置
  // 清除Canvas
  ctx.clearRect(0, 0, canvas.width, canvas.height);
  // 绘制新的图形
  // ...

  // 请求下一帧
  window.requestAnimationFrame(draw);
}

// 开始绘制动画
draw();

总结
Canvas为Web开发者提供了一个强大的、基于像素的绘图工具,可以用来实现复杂的图形和动画效果,非常适合开发图形应用程序、游戏等。通过熟练使用Canvas API,你可以在网页上创建出丰富的视觉内容。

ES6

ECMAScript 6(简称ES6)是JavaScript语言的一个重要版本,它在2015年被正式发布。ES6引入了许多新的语法和特性,使得JavaScript代码更加简洁、强大和易于管理。下面是你提到的几个重要概念的简介:

箭头函数

箭头函数提供了一种更简洁的方式来写函数表达式。它不仅语法简短,而且还有其他几个特性,比如不绑定this。

// 传统的函数表达式
var add = function(a, b) {
  return a + b;
};

// 箭头函数
const add = (a, b) => a + b;

面向对象

ES6引入了class关键字,让JavaScript的面向对象编程变得更加清晰和易于使用。类(Classes)是简化了的、基于原型的继承的语法糖。

class Person {
  constructor(name) {
    this.name = name;
  }

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

const person = new Person('Alice');
person.greet(); // 输出: Hello, my name is Alice

Promise

Promise是异步编程的一种解决方案,比传统的回调函数和事件更强大和灵活。Promise对象代表了一个异步操作的最终完成(或失败)及其结果值。

const promise = new Promise(function(resolve, reject) {
  // 异步操作
  if (/* 异步操作成功 */) {
    resolve(value);
  } else {
    reject(error);
  }
});

promise.then(function(value) {
  // 成功
}, function(error) {
  // 失败
});

代理和反射

Proxy and Reflect
Proxy用于创建一个对象的代理,从而实现基本操作的拦截和自定义(如属性查找、赋值、枚举、函数调用等)。

var handler = {
  get: function(target, name) {
    return name in target ? target[name] : 42;
  }
};

var p = new Proxy({}, handler);
p.a = 1;
console.log(p.a, p.b); // 输出: 1 42

Reflect对象提供了可拦截的JavaScript操作的方法。这些方法与Proxy handlers的方法相同。Reflect是用来操作对象的。

Reflect.get(target, name);

模块化

ES6模块让JavaScript支持了原生的模块化编码方式。模块让开发者可以从一个文件导出变量、函数、类等,并在另一个文件中导入它们。

// file: math.js
export const add = (a, b) => a + b;

// file: main.js
import { add } from './math.js';
console.log(add(2, 3)); // 输出: 5

作用域

在编程中,作用域是一个基本概念,它定义了变量和函数的可访问性。在JavaScript中,作用域决定了代码块中变量和其他资源的可见性。简而言之,作用域控制着变量与函数的可见性和生命周期。这有助于限制变量的访问范围,并且提供了一种将变量封装在特定区域的方法。
全局作用域
当一个变量在函数外部被声明时,它就处于全局作用域中。全局作用域中的变量可以在代码的任何地方被访问。

var globalVar = "I am global";

function testScope() {
  console.log(globalVar); // 输出: I am global
}

console.log(globalVar); // 输出: I am global

局部(函数)作用域
当变量在函数内部被声明时,它就处于局部作用域中,也称为函数作用域。这意味着它只能在该函数内部被访问。

function testScope() {
  var localVar = "I am local";
  console.log(localVar); // 输出: I am local
}

testScope();
console.log(localVar); // ReferenceError: localVar is not defined

块级作用域
ES6引入了let和const关键字,它们提供了块级作用域(block scope)。块级作用域是指变量在声明它的代码块(例如,if语句、for循环)内有效。

if (true) {
  let blockVar = "I am block scoped";
  console.log(blockVar); // 输出: I am block scoped
}

console.log(blockVar); // ReferenceError: blockVar is not defined

语法作用域

词法作用域
JavaScript采用的是词法作用域(也称为静态作用域),意味着函数的作用域在函数定义时就决定了,而不是在函数调用时。这意味着函数运行时会查找其在定义时的环境。

var outerVar = "I am from outer scope";

function outerFunc() {
  function innerFunc() {
    console.log(outerVar); // 输出: I am from outer scope
  }
  innerFunc();
}

outerFunc();

当代码在一个环境中执行时,JavaScript会查找变量的值,这个查找过程会从当前作用域开始,如果未找到,会继续到外层作用域,一直到全局作用域。这一系列的作用域组成了作用域链。

作用域是一个非常重要的概念,了解它可以帮助你写出更好、更安全的代码,避免变量命名冲突,并理解变量在不同区域代码中的可见性。

作用域提升

作用域提升(Hoisting)是JavaScript中的一种机制,指的是变量和函数声明在编译阶段被提升到它们所在作用域的顶部。这意味着无论声明它们的代码在一个作用域的哪个位置,它们都会被提升到作用域的最开始处。不过,需要注意的是,提升只适用于声明而不适用于赋值。

变量提升
使用var声明的变量会被提升。这意味着你可以在变量声明之前引用它,此时变量的值会是undefined。

console.log(myVar); // 输出: undefined
var myVar = "Hello, World!";

在这个例子中,变量myVar的声明(var myVar;)被提升到了函数或全局作用域的顶部,但它的赋值(myVar = “Hello, World!”;)留在原处。
函数提升
函数声明也会被提升,这意味着你可以在函数声明之前调用它。

helloWorld(); // 输出: Hello, World!

function helloWorld() {
  console.log("Hello, World!");
}

在这个例子中,整个函数声明,包括它的实现,都被提升到了作用域的顶部,所以在声明之前调用它是没问题的。

注意事项
使用let和const声明的变量也存在提升,但它们被提升到了块级作用域的顶部,并且不会被初始化为undefined。在声明之前访问这些变量会导致ReferenceError,这个阶段被称为“暂时性死区”(Temporal Dead Zone,TDZ)。

函数表达式和箭头函数的提升行为依赖于它们是如何声明的。如果是用var声明的函数表达式,它的变量名会被提升,但函数内容不会;如果是用let或const声明,那么它们不会被提升。

作用域提升的影响
虽然作用域提升可能在某些情况下看起来很方便,但它也可能导致代码难以理解和维护,特别是当在同一个作用域中混用声明和赋值,或者在声明之前就使用变量和函数时。因此,一个好的做法是始终在作用域的顶部声明变量和函数,这样可以使代码更清晰、更易于理解。

异步

在JavaScript中,由于其单线程的特性,异步编程模式对于处理耗时任务(如网络请求、文件操作等)至关重要,以避免阻塞代码执行。下面是JavaScript异步编程的几种主要方式:

回调函数

回调函数是最基本的异步编程模式。一个回调函数是被作为参数传递给另一个函数,并在适当的时候被调用以完成某种任务的函数。

function fetchData(callback) {
  setTimeout(() => {
    callback('Data loaded');
  }, 1000);
}

fetchData((data) => {
  console.log(data); // 输出:Data loaded
});

Promise

Promise是异步编程的一种解决方案,比传统的回调函数更强大和灵活。它表示一个异步操作的最终完成(或失败),及其结果值。

function fetchData() {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      resolve('Data loaded');
    }, 1000);
  });
}

fetchData().then((data) => {
  console.log(data); // 输出:Data loaded
}).catch((error) => {
  console.error(error);
});

优点:提供了更好的错误处理方法,并支持链式调用,解决了回调地狱的问题。

迭代生成器

生成器(Generators)
生成器函数允许一个函数执行到一半时暂停,然后在稍后继续从停止处执行。这是通过function*语法和yield关键字实现的。结合Promise,它们可以用来以同步的方式编写异步代码。

function* fetchGenerator() {
  const data = yield fetchData(); // 假设fetchData返回一个Promise
  console.log(data);
}

const generator = fetchGenerator();
const result = generator.next().value; // 获取Promise
result.then(data => generator.next(data)); // 继续执行生成器函数

生成器的使用比较复杂,现在更推荐使用async/await来处理异步操作。

async/await

async/await是基于Promise的,它提供了一种更简洁的方式来处理异步操作,让异步代码看起来像同步代码一样。

async声明的函数会返回一个Promise。
await用于等待一个Promise完成,只能在async函数内部使用。

async function fetchData() {
  return 'Data loaded';
}

async function showData() {
  const data = await fetchData();
  console.log(data); // 输出:Data loaded
}

showData();

优点:代码更加简洁清晰,易于理解和维护,同时也避免了回调地狱。

这些异步编程模式是JavaScript中非常重要的概念,理解和掌握它们对于开发现代JavaScript应用程序至关重要。随着JavaScript语言的发展,async/await因其简洁和强大而成为处理异步操作的首选方法。

在现代JavaScript开发中,框架设计、模块化、MVVM、组件化以及设计模式是五个非常重要的概念。它们共同构成了构建大型、复杂前端应用的基础。下面我会分别对它们进行简单介绍:

框架设计

框架设计是指创建一个通用的、可重用的软件环境,它为开发特定类型的应用程序提供了基础结构和支持。JavaScript框架如Angular、React和Vue.js等,通过提供一套标准化的编程模型和丰富的功能库,帮助开发者更快地开发应用、提升代码质量和维护性。

模块化

模块化是将大型程序分解为独立、小巧、可管理的部分(即模块)的过程。每个模块执行一个独立的任务,具有明确的接口和依赖声明。模块化使得代码更容易理解、测试和维护,同时也支持代码复用和懒加载。JavaScript中实现模块化的方式包括CommonJS、AMD、UMD和ES6模块。

MVVM

MVVM(Model-View-ViewModel)是一种软件架构模式,用于简化用户界面的开发。在MVVM中:

Model表示应用的数据模型;
View代表UI组件,是用户界面的表示;
ViewModel是一个同步View和Model的中介,处理逻辑和用户输入。
MVVM模式通过数据绑定(通常是双向的)将View和ViewModel连接起来,从而当数据改变时自动更新UI,而无需直接操作DOM。Vue.js是一个典型采用MVVM模式的框架。

组件化

组件化是指将UI拆分为独立、可复用的组件,每个组件都是一个封装了自己逻辑和样式的独立单位。这种方式使得开发大型应用时,能够更好地复用代码,管理状态,以及分工合作。React和Vue.js等现代前端框架都非常强调组件化开发。

JS设计模式

设计模式是解决软件设计中常见问题的可复用方案。在JavaScript中,常用的设计模式包括:

工厂模式:用函数来封装创建对象的过程。
单例模式:确保一个类仅有一个实例,并提供一个全局访问点。
观察者模式:对象间的一种一对多的依赖关系,当一个对象状态改变时,所有依赖于它的对象都得到通知并自动更新。
策略模式:定义一系列的算法,把它们一个个封装起来,并使它们可相互替换。
模块模式:使用闭包封装私有状态和组织代码,提供公共接口。
掌握这些概念和模式对于设计和开发大型、高质量的前端应用至关重要,它们可以帮助你写出更清晰、更可维护、更高效的代码。

原型链

在JavaScript中,原型链是一种实现继承的机制。每个JavaScript对象都有一个属性,称为[[Prototype]],在代码中通过__proto__属性或者Object.getPrototypeOf()方法访问。这个属性指向该对象的原型。原型本身也是一个对象,因此它也有自己的原型,这样一层层向上直到一个对象的原型为null。当尝试访问一个对象的属性或方法时,如果当前对象上不存在,就会沿着这个链向上查找,直到找到或者查找到原型链的顶端(null)。

原型
原型是一个普通的JavaScript对象,用于实现对象之间的继承。当创建一个函数时,JavaScript会为这个函数自动添加prototype属性,该属性是一个对象,包含可以被该函数的所有实例继承的属性和方法。

构造函数
在JavaScript中,构造函数用于创建特定类型的对象。当使用new关键字调用一个函数时,该函数就作为构造函数使用。构造函数的prototype属性会成为所创建对象的原型。

function Person(name) {
  this.name = name;
}

Person.prototype.greet = function() {
  console.log('Hello, my name is ' + this.name);
};

var person = new Person('Alice');
person.greet(); // 输出: Hello, my name is Alice

在这个例子中,Person是一个构造函数,person对象是其实例。person对象可以访问Person.prototype中定义的greet方法。

原型链
当你访问一个对象的属性或方法时,如果这个对象自身没有这个属性或方法,JavaScript引擎会查找这个对象的原型,如果原型中也没有,就继续查找原型的原型,这个过程会一直进行下去,直到找到这个属性或方法或到达原型链的末端(null)。

function Animal(name) {
  this.name = name;
}

Animal.prototype.eat = function() {
  console.log(this.name + ' eats.');
};

function Dog(name) {
  Animal.call(this, name); // 调用Animal构造函数
}

Dog.prototype = Object.create(Animal.prototype);
Dog.prototype.constructor = Dog;

Dog.prototype.bark = function() {
  console.log(this.name + ' barks.');
};

var dog = new Dog('Rex');
dog.eat(); // 输出: Rex eats.
dog.bark(); // 输出: Rex barks.

在这个例子中,Dog继承了Animal。通过设置Dog的prototype为Animal的实例,创建了一个原型链:dog -> Dog.prototype -> Animal.prototype -> Object.prototype -> null。

重要性
原型链是JavaScript中实现继承的基本机制。它不仅仅用于明显的继承场景,还影响到JavaScript中几乎所有对象的行为。理解原型链对于理解JavaScript的工作原理至关重要。

递归

递归是编程中的一种技术,它允许函数调用自身。这种方法非常有用于解决可以被分解为相同问题的更小版本的问题。递归函数通常有两个主要特点:一个或多个基本情况(base case)和递归步骤(recursive step)。

基本情况
基本情况是递归调用停止的条件。没有它,递归会无限进行下去,最终导致栈溢出错误(因为每个函数调用都会占用一定的内存空间)。

递归步骤
递归步骤是函数调用自身以解决问题的更小部分的过程。每次递归调用应该都在某种程度上逼近基本情况,这样递归才能最终结束。

示例:计算阶乘
阶乘是一个典型的递归示例。阶乘函数n!表示所有小于或等于n的正整数的乘积。递归的解决方案分为两部分:基本情况是0! = 1,递归步骤是n! = n * (n-1)!。

function factorial(n) {
  // 基本情况
  if (n === 0) {
    return 1;
  } else {
    // 递归步骤
    return n * factorial(n - 1);
  }
}
console.log(factorial(5)); // 输出: 120

注意事项
每个递归调用都应该逼近基本情况:确保递归调用会最终达到基本情况,否则会造成无限递归。
递归可能不是最高效的解决方案:对于某些问题,使用递归可能会比迭代解决方案更慢,因为每次函数调用都需要时间和空间(栈内存)。
堆栈溢出的风险:递归过深可能导致堆栈溢出,因为每个函数调用都占用了一部分栈内存。JavaScript引擎通常会限制调用栈的大小。
尽管递归有其局限性,但它仍然是解决诸如树遍历、图搜索、分治算法等问题的强大和优雅的工具。理解和掌握递归对于成为一名有效的程序员非常重要。

感谢大圣老师的技术路线图
感谢OpenAI的ChatGPT

https://roadmap.shengxinjing.cn/fe/javascript.html#%E6%8A%80%E6%9C%AF%E6%96%87%E6%A1%A3

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值