深入浅出JavaScript继承机制:解密原型、原型链与面向对象实战攻略

在这里插入图片描述

🔥 个人主页:空白诗

在这里插入图片描述

文章目录

    • 🔥 引言
    • 🧱 原型基础
    • ⛓️ 原型链的形成
    • 🔄 修改原型的影响
    • 🏁 原型链的尽头
      • 为什么`null`标志着结束?
      • 实际意义 🌐
    • 🔄 继承的实现方式
      • 1. 原型链继承 🌀
      • 2. 构造函数继承 🏗️
      • 3. 组合继承(经典继承)👨‍👩‍👧‍👦
      • 4. ES6 Class继承 🎉
    • 🚀 实战示例:创建可扩展的动物王国
      • 1. 基础动物类 (Animal)
      • 2. 具体动物类 (Dog & Cat)
      • 3. 实战应用
    • 📚 总结
    • 🔗 相关链接

在这里插入图片描述

🔥 引言

在深入探索JavaScript编程的旅程中,理解继承机制是攀登至高技能水平的关键一步。作为这门语言的基石之一,继承不仅支撑着代码的复用性和模块化的实现,还深刻影响着对象间关系的构建与数据结构的设计。其中,原型链扮演着核心角色,它定义了对象属性和方法的查找规则,串联起JavaScript对象的血缘与能力传承。本篇讨论将详尽剖析继承的概念,从基本原理到多种实现方式,旨在为您铺设一条通向JavaScript面向对象编程高手之路的坚实桥梁。


🧱 原型基础

首先,每个JavaScript对象都有一个内置的属性叫做[[Prototype]],通常通过__proto__访问(非标准但广泛支持),它指向创建该对象的构造函数的prototype属性。构造函数的prototype本身也是一个对象,拥有自己的属性和方法。

示例代码

function Animal(name) {this.name = name;
}Animal.prototype.speak = function() {console.log('I am an animal');
};let cat = new Animal('Kitty'); // 创建Animal的实例
console.log(cat)

在这里,cat__proto__指向Animal.prototype,这意味着cat可以访问Animal.prototype上的方法,如speak
在这里插入图片描述


⛓️ 原型链的形成

当试图访问一个对象的属性或方法时,如果该对象本身没有定义,JavaScript引擎会向上查找其原型(__proto__指向的对象),这一过程会一直追溯到原型链的顶部,通常是Object.prototype。如果在那里还找不到,就会返回undefined

示例代码

console.log(cat.speak === Animal.prototype.speak); // true

这行代码确认了cat实例的speak方法确实是指向Animal.prototype上的speak方法,证实了继承关系的存在。

cat.speak(); // 输出: "I am an animal"

调用cat.speak()成功执行并打印出"I am an animal",这证明了cat实例能够正确地沿原型链访问到Animal.prototype上定义的speak方法。

console.log(cat.toString());

尽管在Animal构造函数或其原型上没有直接定义toString方法,cat.toString()仍然能够执行并按预期工作。这是因为所有JavaScript对象(除非被特殊修改)都默认从Object.prototype继承了toString方法。toString方法通常用于返回对象的字符串表示,对于普通的对象实例,默认情况下返回的是"[object Object]"

原型链是JavaScript实现继承的核心机制,它允许对象间接访问其原型链上定义的属性和方法,直至达到Object.prototype。这一机制不仅简化了代码复用,也是理解JavaScript面向对象编程的关键。通过上述示例,我们可以看到即便没有在每个对象或构造函数中显式定义所有方法,也可以通过原型链继承自上层原型或最终的Object.prototype,从而获得这些功能。


🔄 修改原型的影响

修改原型对象会影响所有通过该构造函数创建的实例。这是因为所有实例共享同一个原型对象。

Animal.prototype.speak = function() {console.log('Now I can talk too!');
};cat.speak(); // 输出变为 "Now I can talk too!"

这里,我们修改了Animal.prototype上的speak方法,所有Animal的实例调用speak时都会反映出这一变化。

由于修改原型会影响到所有通过该构造函数创建的实例,开发中应当谨慎操作,以防止原型污染。一种常见做法是使用不可变(Immutable)的设计模式,或者在必要时为每个实例单独添加方法,而不是修改原型。

function giveUniqueVoice(animal, voice) {animal.speak = function() {console.log(voice);};
}let specialCat = new Animal('Whiskers');
giveUniqueVoice(specialCat, 'Meow!');specialCat.speak(); // 输出 "Meow!"
cat.speak(); // 输出 "My behavior has been changed!"

在这个例子中,我们通过giveUniqueVoice函数为特定实例specialCat添加了一个独特的speak方法,这样做不会影响到其他Animal实例的行为。


🏁 原型链的尽头

原型链的尽头,指的是JavaScript中对象原型链层级结构的最终点,这个终点是null。在JavaScript中,每个对象(除null外)都有一个内部属性称为[[Prototype]],它指向创建该对象的原型对象。这个原型对象本身也可能是一个对象,同样拥有自己的[[Prototype]],如此形成了所谓的原型链。

当我们尝试访问一个对象的属性或方法时,如果在该对象自身找不到,JavaScript引擎会继续在其原型对象中查找,即沿着原型链向上遍历。这一过程会一直持续到遇到一个原型对象的[[Prototype]]null的点,这标志着原型链的终点。换句话说,null作为原型链的终点,表示没有更进一步的原型可以继承或查找。

Object.prototype是大多数对象原型链中倒数第二层的对象,几乎所有JavaScript对象(直接或间接)的原型链最终都会追溯到Object.prototype,而Object.prototype[[Prototype]]则为null,形成了原型链的闭环。

如下代码所示:

class Animal {name = 'Animal';speak() {console.log('I am an animal');}constructor(name) {this.name = name;}
}
class Dog extends Animal {constructor(name) {super(name); }
}
const myDog = new Dog('Rex');
console.log(myDog)

在这里插入图片描述

  1. myDog (Dog实例):

    • 直接属性:name = 'Rex',这是因为在Dog类的构造函数中,通过super(name)调用了父类Animal的构造函数,并将'Rex'作为参数传递,从而设置了实例的name属性。
    • 内部属性[[Prototype]]指向Dog.prototype
  2. Dog.prototype:

    • 这是Dog类的原型对象,默认包含一个constructor属性指向Dog构造函数自身。
    • 内部属性[[Prototype]]指向Animal.prototype,因为Dog类通过extends Animal继承了Animal类,所以其原型链会链接到Animal类的原型对象。
  3. Animal.prototype:

    • 包含了Animal类定义的方法,如speak()
    • 内部属性[[Prototype]]指向Object.prototype,这是所有JavaScript对象原型链的标准终点前一站,表明Animal类的原型也是基于基础的JavaScript对象构建的。
  4. Object.prototype:

    • 这是所有JavaScript对象的原型链最终到达的地方,包含了像toString(), valueOf()等基本方法。
    • 内部属性[[Prototype]]null,标志着原型链的终点。

综上所述,myDog的原型链路径如下:

  • myDog -> Dog.prototype -> Animal.prototype -> Object.prototype -> null

这条链展示了从myDog实例出发,逐级向上通过原型链查找属性和方法的过程,直到抵达null,即原型链的顶层。

为什么null标志着结束?

null作为Object.prototype[[Prototype]],是一个特意的设计选择,它表示这条原型链到此为止,没有更进一步的原型可供查找null既不是对象也不是函数,它是一种特殊的值,用来表示空值或者尚未赋值的状态。在原型链上下文中,它起到了终止链式查找的作用,防止无限循环查找。

实际意义 🌐

理解原型链的这一终端特性,对开发者来说有几个重要含义:

  1. 性能考量:它确保了属性查找有一个明确的终点,避免了无止境的循环搜索,从而优化了访问速度。
  2. 对象基础:揭示了所有对象共享的基本行为,强调了JavaScript中一切皆对象的原则,即使是null这样的特殊值也是对象行为逻辑的一部分。
  3. 继承体系的清晰度:有助于开发者构建清晰的继承结构,知道何时应该直接在对象上定义方法,何时通过原型链继承,以及如何避免无意中修改基础对象的行为。

原型链的尽头指向Object.prototype,其[[Prototype]]null,这一设计精巧地构建了JavaScript对象继承的基础框架。掌握这一概念,对于深入理解对象间的继承关系、避免常见的原型链错误,以及高效地设计和维护代码结构都是至关重要的。它是通往JavaScript高级编程之路上的一块基石。


🔄 继承的实现方式

1. 原型链继承 🌀

最直接的继承方式就是通过原型链。上面的例子已经展示了这一点,但我们可以更明确地设置原型链:

function Dog(name) {this.name = name;
}// 使用Animal的prototype作为Dog.prototype的原型
Dog.prototype = Object.create(Animal.prototype);
Dog.prototype.constructor = Dog; // 修复constructor指向Dog.prototype.bark = function() {console.log('Woof!');
};let myDog = new Dog('Rex');
myDog.speak(); // I am an animal
myDog.bark(); // Woof!

这段代码展示了如何使用原型链继承JavaScript中实现继承。这里是逐步解析:

  • 定义子类构造函数 Dog:

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

    Dog 构造函数接收一个参数 name,并将其作为实例的 name 属性。

  • 设置 Dog.prototype 的原型为 Animal.prototype 的副本:

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

    这行代码是关键,它使用 Object.create 方法创建了 Animal.prototype 的一个新对象,然后将其赋值给 Dog.prototype。这样一来,所有通过 Dog 构造函数创建的实例都会在其原型链上找到 Animal.prototype,从而继承了 Animal 的属性和方法。

  • . 修复 constructor 指向:

    Dog.prototype.constructor = Dog;
    

    由于我们直接改变了 Dog.prototype 的指向,原本指向 Dogconstructor 现在会指向 Animal。为了修正这一点,我们需要手动将其设置回 Dog

  • Dog.prototype 上定义 bark 方法:

    Dog.prototype.bark = function() {console.log('Woof!');
    };
    

    这为 Dog 的实例添加了一个独有的方法 bark

  • 创建 Dog 的实例并测试:

    let myDog = new Dog('Rex');
    myDog.speak(); // 输出 "I am an animal"
    myDog.bark(); // 输出 "Woof!"
    

    通过 new Dog('Rex') 创建了一个名为 “Rex” 的狗实例。由于 Dog.prototype 指向了 Animal.prototype 的副本,myDog 可以访问到 Animal 上的 speak 方法。同时,它也有自己特有的 bark 方法。

综上所述,这段代码演示了如何利用原型链实现JavaScript中的继承,让子类能够复用父类的属性和方法,同时也能够扩展自己的特性。

  • 特点:简单直接,通过将子类型的原型指向父类型的实例,实现方法的继承。
  • 优点:易于实现,节省内存(共享方法)。
  • 缺点父类的引用类型属性会被所有子类实例共享无法在构造函数中向父类传递参数

2. 构造函数继承 🏗️

另一种方式是通过在子类构造函数内部调用超类构造函数,这种方式不涉及原型链,而是直接复制属性。

function Animal(name) {this.name = name;
}function Dog(name) {Animal.call(this, name);this.species = 'Canine';
}let myDog = new Dog('Rex');
console.log(myDog.name); // Rex
console.log(myDog.species); // Canine

这段代码展示了构造函数继承的方式实现JavaScript中的继承。下面是详细的解析:

  • 定义子类构造函数 Dog:

    function Dog(name) {Animal.call(this, name);this.species = 'Canine';
    }
    
    • Dog 构造函数内部,通过 Animal.call(this, name) 调用了 Animal 构造函数。这里的 call 方法改变了 Animal 内部 this 的指向,使其指向当前 Dog 实例,从而使得 Dog 实例能够继承 Animal 的属性和方法。这就是构造函数继承的核心所在。
    • 接着,Dog 构造函数还定义了自己的属性 species,设置为 'Canine'
  • 创建 Dog 实例并检查属性:

    let myDog = new Dog('Rex');
    console.log(myDog.name); // 输出 "Rex"
    console.log(myDog.species); // 输出 "Canine"
    

    通过 new Dog('Rex') 创建了一个 Dog 的实例,并传入名字 'Rex'。由于在 Dog 构造函数中调用了 Animal.call(this, name)myDog 实例继承了 Animalname 属性,值为 'Rex'。同时,myDog 实例还有自己特有的属性 species,值为 'Canine'

总结来说,这段代码演示了如何通过在子类构造函数内部手动调用父类构造函数(并使用 callapply 方法绑定正确的 this 上下文)来实现继承,这种方式允许子类继承父类的属性,同时可以扩展自己的属性和方法。

  • 特点:通过在子类构造函数内部调用父类构造函数,实现属性的继承。
  • 优点:每个实例都有自己的属性副本,解决了原型链继承中的属性共享问题。
  • 缺点只能继承属性,无法继承方法;每次实例化都会创建方法的新副本,浪费内存。

3. 组合继承(经典继承)👨‍👩‍👧‍👦

结合原型链继承和构造函数继承,是最常用的继承模式。

function Animal(name) {this.name = name;
}Animal.prototype.speak = function() {console.log('I am an animal');
};function Dog(name) {Animal.call(this, name);this.species = 'Canine';
}// 使用Animal的prototype作为Dog.prototype的原型
Dog.prototype = Object.create(Animal.prototype);
Dog.prototype.constructor = Dog;Dog.prototype.bark = function() {console.log('Woof!');
};let myDog = new Dog('Rex');
myDog.speak(); // I am an animal
myDog.bark(); // Woof!
console.log(myDog.species); // Canine

这段代码展示了JavaScript中的一种继承模式,结合了构造函数继承原型链继承(也称作组合继承),是实现继承的常用方式之一。下面是详细的解析:

  • 定义子类构造函数 Dog:

    function Dog(name) {Animal.call(this, name);this.species = 'Canine';
    }
    

    Dog 构造函数内部,使用 Animal.call(this, name) 调用了 Animal 构造函数,实现了属性的继承(构造函数继承)。同时,它还定义了特有的属性 species

  • 设置 Dog.prototype 并修复构造函数指针:

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

    这两行代码通过 Object.create(Animal.prototype) 设置了 Dog.prototype,使得 Dog 的实例可以通过原型链访问到 Animal.prototype 上的方法,实现了方法的继承(原型链继承)。然后,修正了构造函数指针,因为默认情况下,Object.create 会将原型链上原有的构造函数指针设为 Animal

  • Dog.prototype 上定义 bark 方法:

    Dog.prototype.bark = function() {console.log('Woof!');
    };
    

    Dog 类添加了特有的方法 bark

  • 创建 Dog 实例并测试:

    let myDog = new Dog('Rex');
    myDog.speak(); // 输出 "I am an animal"
    myDog.bark(); // 输出 "Woof!"
    console.log(myDog.species); // 输出 "Canine"
    

    myDog 既是 Dog 的实例,也能够访问到 Animalspeak 方法,同时具有 Dog 特有的 bark 方法和 species 属性,展示了组合继承的特性。

这种组合继承方式综合了构造函数继承和原型链继承的优点,既能够继承实例属性,又能有效复用方法,是JavaScript中较为完善的继承实现方式之一。

  • 特点:结合了原型链继承和构造函数继承的优点,是最常用的继承模式。
  • 优点:既能继承属性也能继承方法,且每个实例都有自己的属性副本,同时方法又是共享的。
  • 缺点:构造函数中调用了两次父类构造函数(一次在子类构造函数内部,一次在原型链设定时),稍微有些冗余。

4. ES6 Class继承 🎉

ES6引入了基于class的语法糖,使得继承更加清晰易懂。

class Animal {constructor(name) {this.name = name;}speak() {console.log('I am an animal');}
}class Dog extends Animal {constructor(name) {super(name); // 调用父类构造函数this.species = 'Canine';}bark() {console.log('Woof!');}
}let myDog = new Dog('Rex');
myDog.speak(); // I am an animal
myDog.bark(); // Woof!
console.log(myDog.species); // Canine

这段代码展示了使用ES6的class语法来实现面向对象编程中的继承。下面是代码的详细解析:

  • 定义基类 Animal:

    class Animal {constructor(name) {this.name = name;}speak() {console.log('I am an animal');}
    }
    

    Animal 类通过 constructor 方法定义了一个构造器,用于初始化 name 属性,并定义了一个 speak 方法。

  • 定义子类 Dog 继承 Animal:

    class Dog extends Animal {constructor(name) {super(name); // 调用父类构造函数this.species = 'Canine';}bark() {console.log('Woof!');}
    }
    
    • extends 关键字表明 Dog 类继承自 Animal 类。
    • Dog 的构造函数中,super(name) 调用了父类的构造函数,传递了参数 name,这是继承父类属性的关键步骤。
    • 定义了 Dog 特有的属性 species 和方法 bark
  • 创建 Dog 实例并测试:

    let myDog = new Dog('Rex');
    myDog.speak(); // 输出 "I am an animal"
    myDog.bark(); // 输出 "Woof!"
    console.log(myDog.species); // 输出 "Canine"
    

    通过 new Dog('Rex') 创建了一个 Dog 的实例,它继承了 Animal 类的所有属性和方法,同时拥有自己的特有属性 species 和方法 bark

使用 class 语法实现继承简化了传统构造函数和原型链的复杂性,提供了更接近于其他面向对象语言的继承模型,使得代码更加清晰和易于理解。

  • 特点:引入了面向对象编程中的class语法,使得继承的语义更加清晰,更接近其他面向对象语言。
  • 优点:语法简洁,易于理解,支持静态方法和类属性,提高了代码的可读性和可维护性。
  • 缺点:本质上仍然是基于原型,只是语法糖,新手可能会误解为传统的类继承模型。

每种继承方式的选择应根据实际项目需求和团队习惯来决定。在ES6及以后的版本中,推荐使用class语法进行继承,它不仅代码更加优雅,而且更易于理解和维护。然而,理解背后的基本原理——原型链和构造函数——对于深入掌握JavaScript的面向对象编程是至关重要的。


🚀 实战示例:创建可扩展的动物王国

假设我们要构建一个简单的动物王国模拟器,其中包含各种动物,它们能发出不同的叫声。我们想要设计一个灵活的架构,使得新增动物种类时,无需修改现有代码,同时让每种动物都能继承通用行为(如发出叫声)和拥有特有行为。

1. 基础动物类 (Animal)

// 定义基础动物构造函数,接收一个name参数初始化动物名字
function Animal(name) {this.name = name; // 使用this关键字将传入的name赋值给新创建对象的name属性
}// 在Animal的原型对象上定义一个speak方法,模拟动物发出声音
Animal.prototype.speak = function() {console.log('Some generic sound'); // 打印通用的声音文本
};

2. 具体动物类 (Dog & Cat)

// Dog构造函数,继承Animal
function Dog(name) {Animal.call(this, name); // 使用Animal.call调用超类构造函数,确保name属性被正确初始化
}// 设置Dog的原型为Animal的原型的一个新对象实例,实现继承
Dog.prototype = Object.create(Animal.prototype);
// 修复构造函数指针,确保构造函数引用正确
Dog.prototype.constructor = Dog;// 覆盖speak方法,使Dog有特定的叫声
Dog.prototype.speak = function() {console.log('Woof!'); // 打印Dog的叫声
};// 类似的操作创建Cat类
function Cat(name) {Animal.call(this, name);
}Cat.prototype = Object.create(Animal.prototype);
Cat.prototype.constructor = Cat;Cat.prototype.speak = function() {console.log('Meow!'); // 打印Cat的叫声
};

3. 实战应用

// 创建Dog和Cat的实例
const myDog = new Dog('Rex');
const myCat = new Cat('Whiskers');// 调用各自的speak方法
myDog.speak(); // 输出: Woof!
myCat.speak(); // 输出: Meow!// 动态添加行为到Animal原型,所有子类实例都能访问
Animal.prototype.sleep = function() {console.log(`${this.name} is sleeping.`); // 打印睡觉信息,使用模板字符串插入实例的名字
};// 调用新添加的sleep方法
myDog.sleep(); // 输出: Rex is sleeping.
myCat.sleep(); // 输出: Whiskers is sleeping.

这个示例演示了如何利用原型链实现继承,保持代码的灵活性和扩展性。通过Object.create方法建立原型链关系,确保了子类能够访问父类的属性和方法,同时也能够覆盖或添加新方法以实现特有行为。动物王国的模拟展示了多态性,即不同对象对同一消息(如speak)做出不同响应的能力,以及代码的可维护性和扩展性。


📚 总结

本文全面解析了JavaScript中的继承机制,核心围绕原型链这一核心概念展开,阐述了其在对象继承中的作用与重要性,并介绍了几种主要的继承实现方式。以下是文章内容的概括:

📌 原型基础

  • 每个JavaScript对象都隐含一个[[Prototype]]属性,通常通过__proto__访问,指向创建它的构造函数的prototype对象。
  • 构造函数的prototype本身是个对象,包含可被实例共享的方法和属性。
  • 示例展示了如何通过原型链,实例能访问到构造函数原型上的方法。

📌 原型链的形成与查找规则

  • 当访问对象的属性或方法时,若对象自身未定义,则会沿其原型链向上查找,直至Object.prototype,最后到null终止。
  • 解释了所有对象共享Object.prototype上的基本方法,如toString()等。

📌 修改原型的影响

  • 修改原型对象会影响所有通过该构造函数创建的实例,因它们共享同一原型。
  • 强调需谨慎修改原型以防“原型污染”,建议采用不可变模式或针对实例单独添加方法。

📌 原型链的尽头

  • 深入探讨了Object.prototype[[Prototype]]null的意义,作为原型链的终点,保证了查找过程的终止。

📌 继承的实现方式

  1. 原型链继承:直接设置子类型的原型为父类型的实例,简单直接,共享方法,但需注意构造函数的修正。
  2. 构造函数继承:子类构造函数内部调用父类构造函数,实现属性继承,但不继承方法且方法不共享。
  3. 组合继承:结合上述两者,最常用,既继承属性也继承方法,但构造函数被调用两次。
  4. ES6 Class继承:引入class语法,简化继承表达,提供更清晰的面向对象编程风格,本质仍是基于原型。

每种继承方式都有其适用场景与优缺点,理解这些机制有助于开发者根据具体需求选择合适的继承策略,提升代码的效率与可维护性。文章强调了深入理解原型链与构造函数原理对于掌握JavaScript面向对象编程的重要性。


🔗 相关链接

  • JavaScript 中的 Class 类
  • JavaScript中call、apply与bind的区别
  • JavaScript 垃圾回收机制深度解析:内存管理的艺术

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/835183.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

数据库期末复习资料

考纲 选择 10分 简答题 25分 ER图建表 15分 建表以后的范式的分解、规范化 15分 Sql语句 35分 :关系代数,select,触发器 --------------------------------------数据库设计----------------------------------- 第一章: 1.数据…

我在洛杉矶采访到了亚马逊云全球首席信息官CISO(L11)!

在本次洛杉矶举办的亚马逊云Re:Inforce全球安全大会中,小李哥作为亚马逊大中华区开发者社区和自媒体代表,跟着亚马逊云安全产品团队采访了亚马逊云首席信息安全官(CISO)CJ Moses、亚马逊副总裁Eric Brandwine和亚马逊云首席高级安全工程师Becky Weiss。 …

安装docker镜像nginx1.26.0版本,与删除docker容器【灵异事件】

为了http3 的这个模块,所以需要升级nginx的版本,需要nginx1.26.0才有 –with-http_v3_module 这个模块 为什么记录一下?因为觉得奇怪 1:删除nginx镜像,显示镜像还被某个容器在使用 luichunluichun:~$ docker rmi ng…

文心一言 VS 讯飞星火 VS chatgpt (255)-- 算法导论18.3 1题

一、请说明依次从图18-8(f)中删除C、P和V后的结果。如果要写代码,请用go语言。 文心一言: 首先,让我们明确一点:由于您没有提供具体的图18-8(f)的内容,我只能假设它是一个数据结构(可能是图、树或列表等&…

AI模型:windows本地运行下载安装ollama运行Google CodeGemma、gemma等可离线运行数据模型【自留记录】

AI模型:windows本地运行下载安装ollama运行Google CodeGemma可离线运行数据模型【自留记录】 CodeGemma 没法直接运行,需要中间软件。下载安装ollama后,使用ollama运行CodeGemma。 类似 前端本地需要安装 node.js 才可能跑vue、react项目 1…

应用层协议之 DNS 协议

DNS 就是一个域名解析系统。域名就是网址,类似于 www.baidu.com。网络上的服务器想要访问它,就得需要它对应的 IP 地址,同时,每个域名对对应着一个 / N个 IP 地址(即对应多台服务器)。 因此,为了…

会话劫持攻击就在我们身边,我们要如何防范

会话劫持攻击(Session Hijacking)是一种网络攻击方式,攻击者通过某种手段获取到用户的会话标识(Session ID),然后使用这个会话标识冒充合法用户进行恶意操作。这种攻击方式允许攻击者以合法用户的身份访问受…

正点原子[第二期]Linux之ARM(MX6U)裸机篇学习笔记-15.4讲--ARM异常中断返回

前言: 本文是根据哔哩哔哩网站上“正点原子[第二期]Linux之ARM(MX6U)裸机篇”视频的学习笔记,在这里会记录下正点原子 I.MX6ULL 开发板的配套视频教程所作的实验和学习笔记内容。本文大量引用了正点原子教学视频和链接中的内容。…

智慧公厕解决什么问题?实现了什么样的价值?

公共厕所一直是城市管理的难题,常常面临着卫生条件不佳、管理不善以及使用体验差等问题。为了解决这些困扰城市的难题,智慧公厕应运而生。智慧公厕不仅应用了信息化和数字化技术,还通过全方位的智能化应用,彻底改变了传统公厕的面…

iframe的替代方案有吗?做页面嵌套界面套娃

UIOTOS可以了解下,uiotos.net,通过连线来代替脚本逻辑开发,复杂的交互界面,通过页面嵌套轻松解决,是个很新颖的思路,前端零代码! 蓝图连线尤其是独创的页面嵌套和属性继承技术,好家…

韩顺平0基础学Java——第8天

p155-168 数组(第六章) 数组可以存放多个同一类型的数据,数组也是一种数据类型(引用类型)。 即,数组就是一组数据~ 例:double [] hens {1,2,3,4,5,6}; 新建了一组鸡,里面有6个。…

车载电子电器架构 —— 应用软件开发(上)

车载电子电器架构 —— 应用软件开发(上) 我是穿拖鞋的汉子,魔都中坚持长期主义的汽车电子工程师。 老规矩,分享一段喜欢的文字,避免自己成为高知识低文化的工程师: 屏蔽力是信息过载时代一个人的特殊竞争力,任何消耗你的人和事,多看一眼都是你的不对。非必要不费力证明…

学习记录:AUTOSAR R20-11的阅读记录(五)【CP(5.11-5.19)】完

接上回:学习记录:AUTOSAR R20-11的阅读记录(四)【CP(5.6-5.10)】 五、CP 11、General(4个) 5.11 File Name 说明 1 AUTOSAR_EXP_ LayeredSoftwareArchitecture.pdf 描述了AUTO…

【HMWeb】HTML使用Leaflet实现本地离线地图Gis应用

下载Leaflet 官网下载&#xff1a;https://leafletjs.com/reference.html CSDN&#xff1a;https://download.csdn.net/download/hmxm6/89291989 选择版本号 添加html文件 加入代码 <!DOCTYPE html> <html lang"en"> <head><meta charset&qu…

记一次DNS故障导致用户无法充值的问题(下)

上一篇说到DNS故障导致无法充值&#xff0c;后来我们通过拨测发现业务域名的解析目标地址被解析到了【127.0.0.1】IP。 1、联系阿里云厂商&#xff0c;通过沟通&#xff0c;阿里云反馈我们的域名被XX省通管单位封禁了&#xff0c;导致解析到了不正确的地址。 2、为了解决用户问…

【hackmyvm】 Animetronic靶机

靶机测试 arp-scanporturl枚举exiftool套中套passwordsudo 提权 arp-scan arp-scan 检测局域网中活动的主机 192.168.9.203 靶机IP地址port 通过nmap扫描&#xff0c;获取目标主机的端口信息 ┌──(root㉿kali)-[/usr/share/seclists] └─# nmap -sT -sV -O 192.16…

如何在JavaScript/Vue中获取当前时间并格式化输出(精确到时分秒)

如何在JavaScript/Vue中获取当前时间并格式化输出&#xff08;精确到时分秒&#xff09; 不只是树&#xff0c;人也是一样&#xff0c;在不确定中生活的人&#xff0c;能比较经得起生活的考验&#xff0c;会锻炼出一颗独立自主的心。在不确定中&#xff0c;就能学会把很少的养分…

CTF例题和知识点

[ACTF2020 新生赛]Include 打开靶机发现一个超链接&#xff0c;点击之后出现一段话 “Can you find out the flag?” 查看源码注入&#xff0c;无果 仔细看url&#xff0c;发现有flag.php 根据题目提示&#xff0c;该题应该是文件包含漏洞&#xff0c;因此可以判断出此题是PH…

基于SpringBoot的全国风景区WebGIS按省展示实践

目录 前言 一、全国风景区信息介绍 1、全国范围内数据分布 2、全国风景区分布 3、PostGIS空间关联查询 二、后台查询的设计与实现 1、Model和Mapper层 2、业务层和控制层设计 三、WebGIS可视化 1、省份范围可视化 2、省级风景区可视化展示 3、成果展示 总结 前…

P9420 [蓝桥杯 2023 国 B] 子 2023 / 双子数

蓝桥杯2023国B A、B题 A题 分析 dp问题 根据子序列&#xff1a;2&#xff0c;20&#xff0c;202&#xff0c;2023分为4个状态&#xff1b; 当前数字为2时&#xff0c;处于dp[0]&#xff0c;或者和dp[1]结合成dp[2]&#xff1b; 当前数字为0时&#xff0c;和dp[0]结合成dp[…