欢迎光临
我们一直在努力

js基础(2)

字符串提取方法

slice(start, end)

提取从start到end-1的字符,支持负数索引(从末尾计算)。
代码示例:

let str = "Hello World";
console.log(str.slice(0, 5)); // "Hello"
console.log(str.slice(-5)); // "World"

substring(start, end)

类似slice但不支持负数索引,自动交换start和end若start > end。
代码示例:

let str = "Hello World";
console.log(str.substring(6, 11)); // "World"
console.log(str.substring(11, 6)); // "World"(自动交换参数)

其他字符串操作方法

replace(searchValue, replaceValue)

替换匹配的字符串或正则表达式。
代码示例:

let str = "Hello World";
console.log(str.replace("World", "JavaScript")); // "Hello JavaScript"

toUpperCase() / toLowerCase()

转换大小写
代码示例:

let str = "Hello";
console.log(str.toUpperCase()); // "HELLO"
console.log(str.toLowerCase()); // "hello"

concat(str2, …, strN)

拼接字符串(通常直接用+更简洁)。
代码示例:

let str1 = "Hello";
let str2 = "World";
console.log(str1.concat(" ", str2)); // "Hello World"

String.trim()

去除首尾空格。
代码示例:

let str = " Hello ";
console.log(str.trim()); // "Hello"

字符访问方法

charAt(position)

返回指定位置的字符。
代码示例:

let str = "Hello";
console.log(str.charAt(1)); // "e"

charCodeAt(position)

返回字符的Unicode编码。
代码示例:

let str = "Hello";
console.log(str.charCodeAt(1)); // 101('e'的编码)

字符串分割

split(separator)

按分隔符拆分为数组。
代码示例:

let str = "apple,orange,banana";
console.log(str.split(",")); // ["apple", "orange", "banana"]

搜索字符串js方法

String.match()

match() 方法用于在字符串中搜索与正则表达式匹配的内容,返回一个数组或 null。

const str = "Hello, world!";
const regex = /world/;
const result = str.match(regex);
console.log(result); // ["world", index: 7, input: "Hello, world!", groups: undefined]

String.includes()

includes() 方法检查字符串是否包含指定的子字符串,返回 true 或 false。

const str = "Hello, world!";
const substring = "world";
const result = str.includes(substring);
console.log(result); // true

String.startsWith()

startsWith() 方法检查字符串是否以指定的子字符串开头,返回 true 或 false。

const str = "Hello, world!";
const prefix = "Hello";
const result = str.startsWith(prefix);
console.log(result); // true

String.endsWith()

endsWith() 方法检查字符串是否以指定的子字符串结尾,返回 true 或 false。

const str = "Hello, world!";
const suffix = "world!";
const result = str.endsWith(suffix);
console.log(result); // true

字符串模板

let firstName = "Bill";
let lastName = "Gates";

let text = `Welcome ${firstName}, ${lastName}!`;

JavaScript 数字运算

JavaScript 中浮点运算存在精度问题,这是由于 IEEE 754 标准的二进制浮点数表示方式导致的。例如:

var x = 0.2 + 0.1; // 结果为 0.30000000000000004

使用乘除法可以规避精度问题:

var x = (0.2 * 10 + 0.1 * 10) / 10; // 结果为 0.3


数据类型与运算规则

数字相加结果为算术和:

var x = 10 + 5; // 结果为 15

字符串相加结果为级联:

var x = "10" + "5"; // 结果为 "105"

数字与字符串相加会转换为字符串级联:

var x = 10 + "5"; // 结果为 "105"
var y = "5" + 10; // 结果为 "510"


减乘除运算规则

减、乘、除运算会强制将字符串转换为数字:

var x = "100" – "10"; // 结果为 90
var y = "100" * "10"; // 结果为 1000
var z = "100" / "10"; // 结果为 10


特殊数值处理

NaN(非数值)
非数字字符串运算会返回 NaN:

var x = "Hello" / 10; // 结果为 NaN

Infinity
超出数值范围或除以零会返回 Infinity:

var x = 2 / 0; // 结果为 Infinity
var y = -2 / 0; // 结果为 -Infinity

Infinity 的类型是数字:

typeof Infinity; // 返回 "number"

进阶01

函数作用域

函数内部声明的变量(包括参数)仅能在函数内部访问,外部无法直接调用。函数执行结束后,其内部变量会被销毁。不同函数之间的变量相互隔离,无法跨函数访问。

块作用域

通过 {} 包裹的代码块会形成块级作用域,其内部变量的可访问性取决于声明方式:

  • let 和 const:声明的变量或常量具有块作用域,仅在当前代码块内有效,外部无法访问。
  • var:声明的变量无视块作用域,仍可在代码块外部访问。

不同代码块之间的变量(使用 let 或 const 声明)相互隔离,无法跨块访问。

关键区别

  • 作用域范围:函数作用域针对整个函数体,块作用域仅限 {} 内的代码。
  • 变量声明影响:var 声明的变量受函数作用域约束,但不受块作用域限制;let/const 受块作用域约束。、

全局作用域的定义

全局作用域指在 script 标签或 .js 文件的最外层声明的变量或函数,它们可以在代码的任何位置被访问,包括函数内部或其他作用域。

全局变量的特点

  • 全局变量会挂载到 window 对象上(浏览器环境)。
  • 未使用任何关键字(如 var、let、const)直接赋值的变量会成为全局变量。
  • 动态为 window 对象添加的属性也会成为全局变量。

不推荐的全局变量声明方式

// 1. 动态为 window 对象添加属性(不推荐)
window.globalVar1 = "动态添加的全局变量";

// 2. 函数内部未使用关键字声明的变量(不推荐)
function setGlobalVar() {
globalVar2 = "未声明直接赋值的全局变量";
}
setGlobalVar();

console.log(globalVar1); // "动态添加的全局变量"
console.log(globalVar2); // "未声明直接赋值的全局变量"

推荐的变量声明方式

// 使用 const 或 let 声明全局变量(推荐)
const GLOBAL_CONST = "常量全局变量";
let globalLet = "可变的全局变量";

// 函数内部访问全局变量
function accessGlobal() {
console.log(GLOBAL_CONST); // "常量全局变量"
console.log(globalLet); // "可变的全局变量"
}
accessGlobal();

避免全局变量污染的方法

  • 使用模块化(如 ES6 Modules)减少全局变量。
  • 使用立即执行函数(IIFE)封装作用域。
  • 优先使用 constlet 代替 var。

// 使用 IIFE 限制作用域
(function() {
const localVar = "局部变量,不影响全局";
console.log(localVar);
})();

作用域链的核心机制

作用域链是JavaScript中变量查找的底层规则,其运行机制遵循以下原则:

当前函数作用域优先查找
函数执行时,会先在自身作用域内查找变量。若存在则直接使用,停止查找。

逐级向上查找父级作用域
若当前作用域未找到变量,会依次向上一层作用域(父级)查找,直至全局作用域。若全局作用域仍未找到,则报错。

作用域链的关键特性

嵌套串联形成链式结构
函数或块级作用域的嵌套关系会串联成链式结构,形成作用域链。例如内层函数可访问外层函数的变量。

查找规则从小到大的层级顺序
变量查找严格按照从当前作用域向父级作用域的层级顺序,不可逆向或跨级。

单向访问权限
子作用域可访问父作用域的变量,但父作用域无法访问子作用域的变量。这种单向性保证了作用域的隔离性。

内存的生命周期

JavaScript中内存的生命周期分为三个阶段:

内存分配

当变量、对象或函数被创建时,系统会自动分配内存。例如:

let obj = { name: "example" }; // 对象占用堆内存
let arr = [1, 2, 3]; // 数组占用堆内存

内存使用

分配的内存被读取或修改。例如:

obj.name = "updated"; // 修改对象属性
arr.push(4); // 修改数组

内存回收

不再使用的内存会被垃圾回收机制(Garbage Collection, GC)自动回收。

回收策略包括:

  • 标记清除(Mark-and-Sweep):从根对象(如全局变量)出发,标记所有可达对象,未被标记的内存会被回收。
  • 引用计数(Reference Counting):记录对象的引用次数,当计数归零时回收。此方式易导致循环引用问题,现代浏览器已弃用。

变量回收规则

全局变量

除非关闭页面或刷新,否则不会被回收。例如:

window.globalVar = "persistent"; // 需手动解除引用(globalVar = null)才能回收

局部变量

函数执行完毕后,若变量未被闭包或外部引用,则会被回收。例如:

function temporary() {
let localVar = "temp"; // 函数结束后可回收
}

内存泄漏的常见场景

未清理的引用

DOM 移除后仍保留引用导致内存泄漏:

let button = document.getElementById("myButton");
document.body.removeChild(button);
// 若未执行 button = null,内存可能未被释放

闭包误用

意外保留外部变量引用:

function leak() {
let largeData = new Array(1000000).fill("data");
return function() { console.log("leak"); };
// largeData 被闭包间接引用,无法回收
}

定时器或事件监听未清除

let interval = setInterval(() => {}, 1000);
clearInterval(interval); // 未清除会导致回调函数持续占用内存

 

闭包的概念理解

闭包(Closure)是 JavaScript 中函数的一种特性,指内层函数引用外层函数变量的组合。闭包的形成需要满足以下条件:

  • 存在函数嵌套(内层函数定义在外层函数内部)。
  • 内层函数引用了外层函数的变量或参数。
  • 外层函数返回内层函数(或通过其他方式使内层函数被外部调用)。

闭包的核心是内层函数可以访问外层函数的作用域,即使外层函数已经执行完毕。

闭包的作用

闭包的主要作用包括:

  • 数据私有化:通过闭包可以创建私有变量,外部无法直接访问,只能通过闭包暴露的函数间接操作。
  • 持久化局部变量:外层函数的变量在调用结束后通常会被销毁,但闭包可以使其保留。
  • 模块化开发:闭包是实现模块模式的基础,可以隐藏实现细节,仅暴露必要接口。

闭包可能引发的问题

闭包可能导致内存泄漏,因为被引用的外层函数变量不会被垃圾回收机制释放。以下是一个内存泄漏的示例代码:

function outer() {
const bigData = new Array(1000000).fill('data'); // 占用大量内存的变量
return function inner() {
console.log(bigData.length); // 内层函数引用外层变量
};
}

const leak = outer(); // 执行outer后,bigData本应被销毁,但因闭包保留
// 即使不再需要leak,bigData仍占用内存
leak(); // 调用inner时仍能访问bigData

解决方法

为避免内存泄漏,可以在不需要闭包时手动解除引用:

leak = null; // 解除对inner函数的引用,bigData会被垃圾回收

 

变量提升(Hoisting)

在 JavaScript 中,变量提升是指变量声明在代码执行前被提升到当前作用域的顶部。需要注意的是,只有声明会被提升,而赋值操作不会。

  • var 声明的变量:变量声明会被提升,初始值为 undefined

    console.log(a); // 输出 undefined
    var a = 10;

  • let 和 const 声明的变量:虽然也存在提升,但由于暂时性死区(Temporal Dead Zone, TDZ)的限制,在声明前访问会报错。

    console.log(b); // 报错:Cannot access 'b' before initialization
    let b = 20;

函数提升

函数提升是指函数声明在代码执行前被提升到当前作用域的顶部,包括函数体。函数表达式不会被提升

  • 函数声明:整个函数(包括函数体)会被提升。

    foo(); // 输出 "Hello"
    function foo() {
    console.log("Hello");
    }

  • 函数表达式:只有变量声明会被提升,函数体不会。

    bar(); // 报错:bar is not a function
    var bar = function() {
    console.log("World");
    };

提升的优先级

当变量和函数同名时,函数提升的优先级高于变量提升。

console.log(c); // 输出函数 c 的定义
function c() {}
var c = 10;

 

动态参数(arguments)

arguments是函数内部的一个内置对象,表现为伪数组(类数组对象),包含调用时传入的所有实参。
伪数组具有length属性和索引访问特性,但无法直接使用数组方法(如push、forEach)。

arguments的核心用途是动态获取函数调用时的实参,无需显式定义形参名称。
通过循环遍历arguments对象可以依次处理所有传入的实参,例如:

function showArgs() {
for (let i = 0; i < arguments.length; i++) {
console.log(arguments[i]);
}
}
showArgs(1, 'a', true); // 输出 1, 'a', true

剩余参数(…rest)

剩余参数语法使用作为前缀,将多余的实参收集到一个真数组中。
剩余参数必须作为最后一个形参,且一个函数只能有一个剩余参数。
与arguments不同,剩余参数是真正的数组,可直接使用数组方法:

function sum(…numbers) {
return numbers.reduce((acc, curr) => acc + curr, 0);
}
sum(1, 2, 3); // 返回 6

展开运算符(…)

与剩余参数语法相同,但用途相反:将数组或可迭代对象展开为独立元素。
常用于函数调用、数组拼接或对象属性拷贝:

const arr1 = [1, 2];
const arr2 = […arr1, 3]; // [1, 2, 3]
Math.max(…[10, 20, 5]); // 展开为 Math.max(10, 20, 5)

 

箭头函数的基本语法

箭头函数(Arrow Function)是ES6引入的一种简化函数定义的语法形式。其基本语法如下:

const func = (param1, param2) => {
// 函数体
return result;
};

如果函数体只有一行且需要返回结果,可以省略大括号和return:

const sum = (a, b) => a + b;

如果只有一个参数,可以省略参数的小括号:

const square = x => x * x;

箭头函数的特点

1.没有自己的this

箭头函数不会创建自己的this,而是继承外层作用域的this。这使得它在回调函数中特别有用,避免了传统函数中this指向混乱的问题。

const obj = {
name: "Alice",
greet: function() {
setTimeout(() => {
console.log(`Hello, ${this.name}!`);
}, 1000);
}
};
obj.greet(); // 输出 "Hello, Alice!"

2.没有arguments对象

箭头函数没有自己的arguments对象,但可以通过剩余参数(rest parameters)实现类似功能:

const showArgs = (…args) => console.log(args);
showArgs(1, 2, 3); // 输出 [1, 2, 3]

3.不能作为构造函数

箭头函数不能使用new调用,因为它没有prototype属性:

const Foo = () => {};
new Foo(); // 报错:Foo is not a constructor

 

注意事项

不适合用于对象方法
如果对象方法需要访问自身的this,使用传统函数更合适:

const person = {
name: "Bob",
sayName: function() {
console.log(this.name);
}
};

不能用于原型方法
箭头函数无法通过prototype扩展,因此不适合作为原型方法:

function Person(name) {
this.name = name;
}
Person.prototype.sayName = () => {
console.log(this.name); // this指向外层,而非实例
};

解构赋值

解构赋值允许从数组或对象中提取值并赋值给变量。

 需要加分号的两种情况

  • 解构赋值前有立即执行函数(IIFE):

    ;[x, y] = [1, 2] // 避免与上一行代码合并解析

  • 解构赋值以 [ 或 { 开头且不在行首:
  • 数组解构

    通过模式匹配从数组中提取值:

    const [a, b] = [1, 2]; // a=1, b=2

    let a = 1
    ;[a, b] = [2, 3] // 避免语法歧义

    多维数组解构

    嵌套解构可用于多维数组:

    const [a, [b, c]] = [1, [2, 3]]; // a=1, b=2, c=3

    对象解构

    通过属性名提取对象的值:

    const { name, age } = { name: 'Alice', age: 25 }; // name='Alice', age=25

    多级对象解构

    嵌套解构可用于多级对象:

    const { user: { id, info: { email } } } = { user: { id: 1, info: { email: 'a@b.com' } } };
    // id=1, email='a@b.com'

    遍历数组 forEach

    对数组每个元素执行函数,无返回值:

    arr.forEach((item, index, array) => { /* 操作 */ });

    筛选数组 filter

    返回满足条件的新数组:

    const newArr = arr.filter((item, index, array) => item > 2);

    数组方法语法格式

    进阶02

    创建对象的三种不同方法

    • map:返回处理后的新数组

      arr.map((item, index, array) => { return 新值 });

    • reduce:累加和

      arr.reduce((acc, item, index, array) => { return 累计值 }, 初始值);

    • find:返回第一个匹配项

      arr.find((item, index, array) => item === 目标值);

    • some/every:检测是否至少一项/全部项  满足条件

      arr.some((item) => item > 0);
      arr.every((item) => item > 0);

      e.target 属性解析

      在 JavaScript 事件处理中,e.target 是事件对象的一个关键属性,表示触发事件的 DOM 元素。以下是相关属性的详细说明和使用方法:


      获取触发事件的元素

      e.target 返回触发事件的原始元素。例如,点击按钮时,e.target 指向该按钮的 DOM 节点

      document.addEventListener('click', function(e) {
      console.log(e.target); // 输出被点击的元素
      });


      获取元素的标签名

      e.target.tagName 返回元素的标签名(大写形式)。例如,点击 <button> 会返回 "BUTTON":

      document.addEventListener('click', function(e) {
      console.log(e.target.tagName); // 如 "DIV"、"BUTTON"
      });


      访问自定义数据属性

      e.target.dataset 提供对元素上 data-* 属性的访问,返回一个对象。例如:

      <div id="item" data-id="123" data-category="example"></div>

      document.getElementById('item').addEventListener('click', function(e) {
      console.log(e.target.dataset.id); // "123"
      console.log(e.target.dataset.category); // "example"
      });

      事件委托

    • 事件委托:通过 e.target 识别子元素触发的事件。

      document.querySelector('ul').addEventListener('click', function(e) {
      if (e.target.tagName === 'LI') {
      console.log('列表项被点击');
      }
      });

    • 动态数据绑定:利用 dataset 传递数据。

      <button data-action="delete" data-item-id="42">删除</button>

      document.querySelector('button').addEventListener('click', function(e) {
      const action = e.target.dataset.action; // "delete"
      const id = e.target.dataset.itemId; // "42"
      });

    1.利用对象字面量创建对象

    对象字面量是最简单直观的创建对象的方式,直接通过键值对定义属性和方法。

    const person = {
    name: 'Alice',
    age: 25,
    greet: function() {
    console.log(`Hello, my name is ${this.name}`);
    }
    };
    person.greet(); // 输出: Hello, my name is Alice

    2.利用 new Object 创建对象

    通过 new Object() 构造函数创建空对象,再动态添加属性和方法。

    const person = new Object();
    person.name = 'Bob';
    person.age = 30;
    person.greet = function() {
    console.log(`Hi, I'm ${this.name}`);
    };
    person.greet(); // 输出: Hi, I'm Bob

    3.利用构造函数创建对象

    通过自定义构造函数批量创建具有相同结构的对象,通常构造函数名首字母大写。

    function Person(name, age) {
    this.name = name;
    this.age = age;
    this.greet = function() {
    console.log(`My name is ${this.name}, age ${this.age}`);
    };
    }
    const alice = new Person('Alice', 25);
    const bob = new Person('Bob', 30);
    alice.greet(); // 输出: My name is Alice, age 25

    构造函数的特点

    构造函数在JavaScript中用于创建对象实例。通常以大写字母开头,通过new关键字调用。构造函数内部通过this绑定属性和方法,自动返回新创建的对象实例。

    创建构造函数

    以下是一个简单的构造函数示例:

    function Person(name, age) {
    this.name = name;
    this.age = age;
    this.greet = function() {
    console.log(`Hello, my name is ${this.name}`);
    };
    }
    const person1 = new Person('Alice', 25);

    实例成员

    通过构造函数创建的对象称为实例对象,实例对象中的属性和方法称为实例成员(实例属性和实例方法)

    • 构造函数通过new调用,默认返回新对象实例(this)。

    function Person(name) {
    this.name = name; // 实例属性
    this.sayHello = function() { // 实例方法
    console.log(`Hello, ${this.name}`);
    };
    }
    const person1 = new Person('Alice');
    person1.sayHello(); // 输出:Hello, Alice

    静态成员

    构造函数的属性和方法被称为静态成员(静态属性和静态方法)

    静态成员只能构造函数来访问,静态方法中的this指向构造函数,比如Date.now() Math.PI()

      function Person() {}
      Person.species = 'Human'; // 静态属性
      Person.greet = function() { // 静态方法
      console.log(`Species: ${this.species}`);
      };
      console.log(Person.species); // 输出:Human
      Person.greet(); // 输出:Species: Human

      内置构造函数

      1.Object

      Object.keys()

      用于获取对象自身可枚举属性的键名数组,返回一个由字符串组成的数组。

      语法

      Object.keys(obj)

      示例

      const obj = { a: 1, b: 2 };
      console.log(Object.keys(obj)); // ["a", "b"]


      Object.values()

      用于获取对象自身可枚举属性的值数组,返回一个由属性值组成的数组。

      语法

      Object.values(obj)

      示例

      const obj = { a: 1, b: 2 };
      console.log(Object.values(obj)); // [1, 2]


      Object.assign()

      用于合并多个对象的属性到目标对象,返回修改后的目标对象。

      语法

      Object.assign(target, …sources)

      示例

      const target = { a: 1 };
      const source = { b: 2 };
      const result = Object.assign(target, source);
      result === target //true
      console.log(result); // { a: 1, b: 2 }

      2.Array

      forEach 方法

      数组的 forEach 方法用于遍历数组的每一项,并对每一项执行回调函数。语法如下:

      数组.forEach(function(item, index, arr) {
      // 操作逻辑
      }, thisArg);

      • item 是当前遍历的数组元素。
      • index 是当前元素的索引。
      • arr 是原数组(可选)。
      • thisArg 用于设置回调函数中的 this 指向(可选)。
      • 在严格模式(use strict)下,若不指定 thisArg,回调函数中的 this 为 undefined。

      filter 方法

      filter 方法用于过滤数组,返回满足条件的新数组。语法如下:

      const 新数组 = 数组.filter(function(item, index) {
      return 条件; // 必须返回布尔值
      });

      • item 是当前遍历的数组元素。
      • index 是当前元素的索引(可选)。
      • 回调函数必须返回布尔值,true 表示保留该元素,false 表示过滤掉该元素。

      map 方法

      map 方法用于对数组的每一项进行转换,并返回转换后的新数组。语法如下:

      const 新数组 = 数组.map(function(当前元素, 索引, 原数组) {
      return 转换逻辑; // 返回转换后的元素
      });

      • 当前元素 是当前遍历的数组元素。
      • 索引 是当前元素的索引(可选)。
      • 原数组 是调用 map 的数组(可选)。
      • 回调函数必须返回转换后的值。

      reduce 方法

      reduce 方法用于将数组中的元素聚合为单个值。语法如下:

      const 最终结果 = 数组.reduce(function(累加器, 当前元素, 索引, 原数组) {
      return 累加器和当前元素的运算逻辑; // 返回新的累加器值
      }, 初始值);

      • 累加器 是上一次回调的返回值或初始值。
      • 当前元素 是当前遍历的数组元素。
      • 索引 是当前元素的索引(可选)。
      • 原数组 是调用 reduce 的数组(可选)。
      • 初始值 是可选的,若未提供,则默认使用数组的第一个元素作为初始值。

      Array.join()

      将数组中的所有元素连接成一个字符串。可以指定分隔符,默认为逗号。

      const arr = ['a', 'b', 'c'];
      console.log(arr.join('-')); // 输出 "a-b-c"

      Array.find()

      返回数组中满足提供的测试函数的第一个元素的值。如果没有找到则返回 undefined。

      const arr = [5, 12, 8, 130, 44];
      const found = arr.find(element => element > 10);
      console.log(found); // 输出 12

      Array.every()

      测试数组中的所有元素是否都通过了提供的函数的测试。返回布尔值。

      const arr = [1, 30, 39, 29, 10, 13];
      const isBelowThreshold = arr.every(element => element < 40);
      console.log(isBelowThreshold); // 输出 true

      Array.some()

      测试数组中是否至少有一个元素通过了提供的函数的测试。返回布尔值。

      const arr = [1, 2, 3, 4, 5];
      const hasEven = arr.some(element => element % 2 === 0);
      console.log(hasEven); // 输出 true

      Array.concat()

      合并两个或多个数组,返回一个新数组,不会改变原数组。

      const arr1 = ['a', 'b', 'c'];
      const arr2 = ['d', 'e', 'f'];
      const arr3 = arr1.concat(arr2);
      console.log(arr3); // 输出 ['a', 'b', 'c', 'd', 'e', 'f']

      Array.sort()

      对数组的元素进行排序,默认排序顺序是根据字符串Unicode码点。可以提供一个比较函数来自定义排序逻辑。

      const arr = ['banana', 'apple', 'orange'];
      arr.sort();
      console.log(arr); // 输出 ['apple', 'banana', 'orange']

      const numbers = [40, 1, 5, 200];
      numbers.sort((a, b) => a – b);
      console.log(numbers); // 输出 [1, 5, 40, 200]

      Array.splice()

      通过删除或替换现有元素或者添加新元素来修改数组的内容。会改变原数组。

      const arr = ['a', 'b', 'c', 'd'];
      arr.splice(1, 2, 'x', 'y');
      console.log(arr); // 输出 ['a', 'x', 'y', 'd']

      Array.reverse()

      反转数组中元素的顺序。会改变原数组。

      const arr = ['a', 'b', 'c'];
      arr.reverse();
      console.log(arr); // 输出 ['c', 'b', 'a']

      Array.findIndex()

      返回数组中满足提供的测试函数的第一个元素的索引。如果没有找到则返回 -1。

      const arr = [5, 12, 8, 130, 44];
      const index = arr.findIndex(element => element > 10);
      console.log(index); // 输出 1

      Array.form()

      伪数组切换成真数组

      const nodeList = document.querySelectorAll('div');
      const divArray = Array.from(nodeList); // 将 NodeList 转换为数组

      3.String

      上面有

      4.Number

      返回一个字符串,表示四舍五入后的数字,保留指定的小数位数。

      let num = 123.456;

      console.log(num.toFixed()); // "123"
      console.log(num.toFixed(1)); // "123.5"
      console.log(num.toFixed(2)); // "123.46"
      console.log(num.toFixed(3)); // "123.456"
      console.log(num.toFixed(4)); // "123.4560"

      进阶03

      面向过程编程:

      分析好步骤,按照步骤解决问题

      面向对象编程:

      以对象功能来划分问题,由对象之间分工与合作

      面向对象特性:继承性,封装性,多态性

      原型

      构造函数与原型对象的关系

      构造函数通过prototype属性指向其原型对象。原型对象包含可由该构造函数创建的所有实例共享的属性和方法。

      function Person(name) {
      this.name = name; // 构造函数中的this指向实例
      }
      Person.prototype.greet = function() {
      console.log(`Hello, ${this.name}!`); // 原型方法中的this也指向实例
      };

      公共属性写在 构造函数上,公共方法写在 原型对象上

      this关键字的指向规则

      无论在构造函数内部还是原型方法中,this始终指向当前调用时的实例对象。这种设计确保属性和方法能正确访问实例数据。

      const person1 = new Person('Alice');
      person1.greet(); // 输出: Hello, Alice! (this指向person1)

      原型链的运作机制

      当访问实例属性或方法时,JavaScript引擎会:

      • 先检查实例自身是否拥有该属性
      • 若不存在,则沿着原型链查找原型对象上的属性

      console.log(person1.hasOwnProperty('name')); // true (实例自身属性)
      console.log(person1.hasOwnProperty('greet')); // false (来自原型)

      constructor 属性的作用

      在 JavaScript 中,每个原型对象(prototype)都有一个 constructor 属性,该属性指向创建当前对象的构造函数。这一机制确保了对象实例可以通过原型链回溯到其构造函数。

      默认的 constructor 关系

      当创建一个构造函数时,其原型对象会自动获得 constructor 属性并指向构造函数本身。例如:

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

      // 原型对象的 constructor 默认指向 Person
      console.log(Person.prototype.constructor === Person); // true

      const person1 = new Person('Alice');
      // 实例通过原型链访问 constructor
      console.log(person1.constructor === Person); // true

      手动修改原型时的注意事项

      如果手动覆盖原型对象(例如通过 Object.assign 或直接赋值),可能会丢失原有的 constructor 属性。此时需要显式修复:

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

      // 错误示例:直接覆盖原型会丢失 constructor
      Animal.prototype = {
      run: function() {
      console.log('Running');
      }
      };
      console.log(Animal.prototype.constructor === Animal); // false(指向 Object)

      // 正确做法:重新指定 constructor
      Animal.prototype = {
      constructor: Animal, // 显式修复
      run: function() {
      console.log('Running');
      }
      };

      proto 与 prototype 的关系

      在 JavaScript 中,实例对象通过 __proto__ 属性指向其构造函数的原型对象 prototype。这种机制构成了 JavaScript 的原型继承体系。

      • __proto__ 是实例对象的内部属性,指向其构造函数的原型对象。
      • prototype 是构造函数的属性,包含可供实例继承的属性和方法。

      原型链的工作原理

      每个对象都有一个 __proto__ 属性,指向其原型对象。原型对象本身也有 __proto__,形成一条链式结构,直到最终指向 null。

      function Person() {}
      const person = new Person();

      // 实例的 __proto__ 指向构造函数的 prototype
      console.log(person.__proto__ === Person.prototype); // true

      // 构造函数的 prototype 的 __proto__ 指向 Object.prototype
      console.log(Person.prototype.__proto__ === Object.prototype); // true

      // Object.prototype 的 __proto__ 指向 null
      console.log(Object.prototype.__proto__ === null); // true

      访问属性的查找过程

      当访问对象的属性时,JavaScript 引擎会沿着原型链向上查找:

    • 检查对象自身是否拥有该属性。
    • 如果没有,通过 __proto__ 查找原型对象。
    • 持续向上查找,直到找到属性或到达原型链末端(null)。
    • Person.prototype.sayHello = function() {
      console.log('Hello');
      };

      person.sayHello(); // 输出 "Hello"
      // person 自身没有 sayHello 方法,但通过原型链找到 Person.prototype 上的方法

      • 构造函数:通过 new 生成实例,prototype 属性指向原型对象。
      • 原型对象:包含共享方法,通过 constructor 属性反向引用构造函数。
      • 实例对象:通过 __proto__ 隐式引用原型对象,形成原型链。

       

      进阶04

       

       

      赞(0)
      未经允许不得转载:171主机测评 » js基础(2)
      分享到: 更多 (0)

      评论 抢沙发

      • 昵称 (必填)
      • 邮箱 (必填)
      • 网址