前端代码分析题(选择题、分析题)——this指向、原型链分析

  this指向

  • 普通函数this 的指向由调用方式决定,可以是全局对象、调用该函数的对象,或者显式指定的对象。
  • 箭头函数this 的指向在定义时确定,始终继承自外层函数作用域的 this,不会被调用方式影响。
var obj = {print: function() {var test = () =>  {console.log("yupi", this);}test();},rap: {doRap:() =>  {console.log(this);}}
}
var copyPrint = obj.print;
copyPrint();
obj.print();
obj.rap.doRap();//直接在 obj.rap 对象中定义,并没有包裹在任何外层函数中,会继承全局作用域的 this

var obj = {name: "yupi",func: function() {var self = this;console.log(this.name);console.log(self.name);(function() {console.log(this.name);console.log(self.name);}());}
};
obj.func();
//输出
yupi
yupi
undefined
yupi
var num = 2;
function print() {console.log(this.num);
}var obj = {num: 4,test1: print,test2: function () {print();},
};
obj.test1();
obj.test2();
var foo = obj.test1;
foo();
//输出结果
4
2
2
function test(num){this.value = num;return this;
}
var value = test(5);
var obj = test(6);console.log(value.value);
console.log(obj.value);
//输出结果
**undefined**6
function test(value) {this.num = value;
}var obj1 = {test: test,
};
obj1.test(1);
console.log(obj1.num);var obj2 = {};
obj1.test.call(obj2, 2);
console.log(obj2.num);var foo = new obj1.test(3);
console.log(obj1.num);
console.log(foo.num);//输出结果
1213function test(value){this.num = value;
}var obj1 = {};
var testBind = test.bind(obj1);
testBind(1);
console.log(obj1.num);var foo = new testBind(2);
console.log(obj1.num);
console.log(foo.num);
//输出结果
1
1
2

 优先级:new 绑定>显示绑定( apply/call/bind )>

               隐式绑定( obj.foo())>默认绑定( 独立函数调用 )

立即执行函数表达式 IIFE

什么是 IIFE(立即执行函数表达式)?

IIFE(Immediately Invoked Function Expression)是一种 JavaScript 编程模式,它使一个函数在定义时立即执行。IIFE 的格式通常如下所示:

  • (function() { // 函数体 })();
  • (() => { // 函数体 })();

立即执行函数的执行机制

  • 在上面的代码中,IIFE 是通过 (function() {...})() 形式定义的。它是一个 函数表达式并且在定义后立即执行。也就是说,IIFE 在 初始化时 执行一次,并且其作用域内的代码也只会执行一次。

对应到您的代码中的 IIFE

在您提供的代码中,IIFE 部分是:

window.num = 2;
var obj = {num: 4,test: (function(){console.log(this);this.num *= 6;return function(){console.log(this);this.num *= 8;}})()
}
var test = obj.test;
test();
obj.test();
console.log(obj.num);
console.log(window.num);//输出结果
Window 对象
Window 对象
{num: 4, test: ƒ} // obj 对象
32
96
  • 这段代码中的 IIFE 会在 定义 test 属性时立即执行console.log(this) 在 IIFE 执行时打印的是 全局对象 window,然后 this.num *= 6; 会修改 window.num 的值。
  • 该 IIFE 返回了一个匿名函数,这个匿名函数会赋值给 obj.test

总结:IIFE 是立即执行的,因此它的代码块只会执行一次,并且返回的函数会被赋给 obj.test。这个返回的函数之后会被调用,但 IIFE 本身只在定义时执行一次。

解释执行顺序

  1. 在执行到 var obj = { ... } 这一行时,IIFE 被立即执行:

    • console.log(this) 打印 window 对象。
    • this.num *= 6 修改了 window.num2 * 6 = 12)。
    • 然后,IIFE 返回一个匿名函数,该匿名函数被赋给 obj.test
  2. 之后,obj.test 就是 IIFE 返回的匿名函数,该函数在后面的调用中会执行:

    • 第一次调用 test() 时,this 指向 windowwindow.num 被修改为 96
    • 第二次调用 obj.test() 时,this 指向 objobj.num 被修改为 32

IIFE 的核心特性:

  • 只执行一次:IIFE 在定义时立即执行,并且它的作用域只会被创建一次。
  • 返回值:IIFE 可以返回任何值,在您的代码中,它返回了一个函数,这个函数被赋值给 obj.test
  • 默认this指向windows(非严格模式) 

⭐⭐进阶题

var length = 10;
function func() {console.log(this.length);
}var obj = {length: 5,test: function(func) {console.log(this.length)//5func();//相当于window.func(),被window对象调用this指向window对象//func.call(this)//这样修改this指向,this就是指向objarguments[0]();//类似于func(),但是调用方式不同,this不同,含义大不相同,这个可以看作函数被arguments对象调用,而arguments对象本省就有length属性,即为参数的个数,所以this.length输出为2(参数个数)}
};
obj.test(func, 1);

 输出为

  • 10
  • 2

刚看到一道JS面试题,关于this指向的问题

var length = 10;
function func() {
  console.log(this.length);
}

var obj = {
  length: 5,
  test: function(func) {
    console.log(this.length)//5
    func();//相当于window.func(),被window对象调用this指向window对象
    //func.call(this)//修改this指向,this就是指向obj
    arguments[0]();//类似于func(),但是调用方式不同,this不同,含义大不相同,这个可以看作函数被arguments对象调用,而arguments对象本身就有length属性,即为参数的个数,所以this.length输出为2(参数个数)
  }
};
obj.test(func, 1);
 

⭐扩展知识:词法作用域

在 JavaScript 中,**词法作用域(Lexical Scope)**是指函数的作用域(即变量的可访问范围)是根据函数定义的位置来确定的而不是根据函数调用的位置来决定的。这意味着 JavaScript 中的作用域链是静态的,它依赖于代码在编写时的结构。

1. 什么是词法作用域?

词法作用域(也叫静态作用域)是指一个函数在定义时决定了它能访问哪些变量。即,函数访问外部变量的规则与它们的定义位置有关,而与函数如何被调用时的调用位置无关。

- **函数的作用域链**是由函数定义时外部的作用域链决定的,而不是调用时的执行环境。

 2. 如何理解词法作用域?

- 在 JavaScript 中,**变量的作用域**决定了变量的可访问范围。
- **函数的作用域**决定了函数内部可以访问哪些变量。

当你定义一个函数时,它会记住外部的作用域链,并且无论何时调用它,函数总是能访问到它定义时可访问的那些变量。

举个简单的例子:

function outer() {var outerVar = 'I am from outer!';function inner() {console.log(outerVar); // 访问外部函数的变量}inner(); // 调用 inner 函数
}outer(); // 输出 "I am from outer!"

在这个例子中:
- `inner` 函数定义在 `outer` 函数内部,因此它可以访问 `outer` 函数中定义的变量 `outerVar`。
- 这就是**词法作用域**,因为 `inner` 函数的作用域是由它定义的位置(即在 `outer` 函数内部)决定的,而不是由它调用的位置决定的。

 3. 词法作用域与 `this`

在 JavaScript 中,`this` 的指向和作用域是两个不同的概念。虽然 `this` 和作用域链都与上下文相关,但它们的行为方式不同。理解词法作用域有助于理解 **箭头函数** 中 `this` 的行为。

普通函数和箭头函数的区别

- **普通函数**中的 `this` 是根据**调用时的上下文**来确定的。
- **箭头函数**中的 `this` 是在**定义时继承**外层作用域的 `this`,这就是箭头函数不同于普通函数的一大特点。

4. 箭头函数中的 `this`

箭头函数中的 `this` 绑定规则与普通函数不同。普通函数的 `this` 是动态绑定的,而箭头函数的 `this` 是静态的,指向定义时外层的 `this`。

例子:

function Outer() {this.name = 'Outer';// 普通函数this.printName = function() {console.log(this.name); // this 指向调用它的对象};// 箭头函数this.arrowPrintName = () => {console.log(this.name); // this 会继承自 Outer 函数的 this};
}var obj = new Outer();
obj.printName();      // 输出 'Outer',this 指向 obj
obj.arrowPrintName(); // 输出 'Outer',this 仍然指向 Outer 函数的 this

在上面的例子中:
- `printName` 是普通函数,它的 `this` 会根据调用时的上下文来确定。
- `arrowPrintName` 是箭头函数,它的 `this` 会继承外层 `Outer` 函数中的 `this`,即指向创建它时的 `this`,而不受 `obj` 的影响。

5. 作用域链

每个 JavaScript 函数都会创建一个作用域链,用于查找变量。当一个函数内部访问变量时,JavaScript 会沿着作用域链查找这个变量。如果函数内部没有定义某个变量,JavaScript 会查找函数外部的作用域,直到全局作用域为止

- **作用域链**是由多个作用域组成的,最里层的是当前函数的作用域,外层是它的外部作用域,一直到全局作用域。```javascript

function outer() {var outerVar = 'outer';function inner() {var innerVar = 'inner';console.log(outerVar); // 在内层函数中访问外层函数的变量}inner();
}outer(); // 输出 'outer'

在上面的例子中:
- `inner` 函数在 `outer` 函数内部定义,它访问了外层的 `outerVar`。这是因为 `inner` 函数的作用域链包含了 `outer` 函数的作用域。

6. 词法作用域和闭包

https://gisjing.blog.csdn.net/article/details/143593869?spm=1001.2014.3001.5502&ydreferer=aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L20wXzU1MDQ5NjU1P3R5cGU9YmxvZw%3D%3D

闭包是指函数能够"记住"并访问它定义时的作用域,即使这个函数在定义时的作用域已经执行完毕。`

function outer() {var outerVar = 'outer';function inner() {console.log(outerVar); // 访问 outer 的变量}return inner;
}var closure = outer(); // 返回 inner 函数
closure(); // 输出 'outer'

在这个例子中,`inner` 函数是一个闭包,因为它记住了定义时的作用域(即 `outer` 函数的作用域),即使在外部调用时,`outerVar` 仍然是可以访问的。

7. 词法作用域与变量提升

JavaScript 中的**变量提升**(hoisting)指的是在执行代码之前,所有的 `var` 声明会被提升到作用域的顶部,但它们的赋值并不会被提升。```javascript

function example() {console.log(myVar); // undefined,因为声明被提升了,但赋值在后面var myVar = 10;
}example();

在这个例子中,`myVar` 的声明被提升了,但是它的值 `10` 是在执行到那行代码时才赋值的。所以输出是 `undefined`,而不是 `10`。

♥8. 总结

- **词法作用域**决定了变量和函数的可访问范围,它是由函数的定义位置而不是调用位置来确定的。
- **作用域链**:函数查找变量时,会沿着作用域链从内到外查找,直到全局作用域。
- **箭头函数的 `this`**:箭头函数的 `this` 不是根据调用方式决定的,而是继承自它定义时的外层作用域。
- **闭包**:函数可以记住并访问它定义时的作用域,即使外层函数已经执行完毕。

原型链

Javascript原型链-CSDN博客

  • boy.prototype->undefined
  • null.__proto__->TypeError

⭐⭐⭐JS中new关键字实例化对象,具体做了什么⭐⭐⭐

  1. 创建一个空对象

    • new关键字被调用时,JavaScript引擎首先会创建一个空白的对象。这个对象没有任何属性和方法,但它会继承自构造函数的prototype属性所向的原型对指象。
  2. 设置原型链

    • 接下来,JavaScript引擎会将新创建的对象的内部原型(__proto__)设置为构造函数的prototype属性。这一步是原型链继承的关键,它允许新对象访问构造函数原型中定义的方法和属性。
  3. 绑定this并执行构造函数

    • 然后,JavaScript引擎会将构造函数作为普通函数调用,但此时this关键字的值会被设置为新创建的对象。这意味着在构造函数内部,你可以通过this来引用新对象,并向其添加属性和方法。
    • 构造函数中的代码会执行,可能会初始化对象的属性、调用其他方法等。
  4. 返回新对象

    • 最后,如果构造函数没有显式地返回一个对象(即返回的不是一个非原始值),那么new表达式会默认返回新创建的对象。如果构造函数返回了一个对象,那么new表达式会返回这个对象,而不是新创建的那个空对象。需要注意的是,这种情况下,原型链的链接会失去作用,因为返回的对象与构造函数的原型没有直接联系。
  • 创建一个新的空对象,并将这个对象的原型设置为函数的 prototype 属性。
  • 绑定函数内部的 this 到这个新对象,即在函数内 this 指向新创建的对象
  • 执行函数,将函数内部的代码与新对象的作用域绑定。
  • 返回值处理:如果函数返回一个非 null 的对象,则 new 表达式会返回这个对象;否则,它会返回创建的对象。

实现继承的几种方式

1.原型链继承

子类prototype指向父类实例。缺:所有实例共享父类属性,修改子类实例会影响到所有实例 

function Coder() {this.type = 'Coder';
}Coder.prototype.rap = function () {console.log('yo yo yo');
};function Yupi(name) {this.name = name;this.age = 18;
}// 原型链继承
Yupi.prototype = new Coder();
Yupi.prototype.constructor = Yupi;// 测试
const yupi = new Yupi('Yupi');
console.log(yupi.type); // 输出: Coder
yupi.rap(); // 输出: yo yo yo
2.构造函数

子类构造函数调用父类构造函数实现,可继承父类属性,但不能继承父类原型方法

function Coder() {this.type = 'Coder';
}Coder.prototype.rap = function () {console.log('yo yo yo');
};function Yupi(name) {Coder.call(this); // 调用父类构造函数this.name = name;this.age = 18;
}// 测试
const yupi = new Yupi('Yupi');
console.log(yupi.type); // 输出: Coder
// yupi.rap(); // 这行代码会报错,因为构造函数继承无法继承原型链上的方法
3.组合继承(组合1和2)

开销较大,两次调用父类构造函数

function Coder() {this.type = 'Coder';
}Coder.prototype.rap = function () {console.log('yo yo yo');
};function Yupi(name) {Coder.call(this); // 调用父类构造函数this.name = name;this.age = 18;
}// 组合继承
Yupi.prototype = new Coder();
Yupi.prototype.constructor = Yupi;// 测试
const yupi = new Yupi('Yupi');
console.log(yupi.type); // 输出: Coder
yupi.rap(); // 输出: yo yo yo
4.寄生组合(推荐⭐)

避免组合继承两次调用父类构造函数

function Coder() {this.type = 'Coder';
}Coder.prototype.rap = function () {console.log('yo yo yo');
};function Yupi(name) {Coder.call(this); // 调用父类构造函数this.name = name;this.age = 18;
}// 寄生组合继承
Yupi.prototype = Object.create(Coder.prototype);
Yupi.prototype.constructor = Yupi;// 测试
const yupi = new Yupi('Yupi');
console.log(yupi.type); // 输出: Coder
yupi.rap(); // 输出: yo yo yo
5.ES6 class语法
class Coder {constructor() {this.type = 'Coder';}rap() {console.log('yo yo yo');}
}class Yupi extends Coder {constructor(name) {super(); // 调用父类构造函数this.name = name;this.age = 18;}
}// 测试
const yupi = new Yupi('Yupi');
console.log(yupi.type); // 输出: Coder
yupi.rap(); // 输出: yo yo yo

**基础补充**

function Father(){this.a=11;this.b=[1,2,this.a];this.print=function(){console.log(this.a,this.b,typeof(this.b[2]));}
}
const father=new Father();
father.print();
father.a=13;
father.print();
//输出
//11 [1,2,11] number
//13 [1,2,11] number
//b中的this.a是复制a的值,类型为原始类型

自己身上没有才去原型链上找

function Obj1() {}
function Obj2(value) {this.value = value;
}
function Obj3(value) {if (value) {this.value = value;}
}Obj1.prototype.value = 1;
Obj2.prototype.value = 1;
Obj3.prototype.value = 1;console.log(new Obj1().value);
console.log(new Obj2().value);
console.log(new Obj3(666).value);1
undefined
666

函数原型与对象原型 

var FuncObj = function () {};
Object.prototype.foo = function () {console.log('foo');
};
Function.prototype.bar = function () {console.log('bar');
};
FuncObj.foo();
FuncObj.bar();var f = new FuncObj();
f.foo();
f.bar();//输出结果
foo
bar
foo
TypeError: f.bar is not a function

⭐⭐**进阶题1**⭐⭐

前端分享一经典有难度易错的Javascript题目

function Father() {this.a = 1;this.b = [1, 2, this.a];this.c = { field: 5 };this.print = function () {console.log(this.a, this.b, this.c.field);};
}function Son() {this.a = 2;this.update = function () {this.b.push(this.a);this.a = this.b.length;this.c.field = this.a++;};
}Son.prototype = new Father();
var father = new Father();
var son1 = new Son();
var son2 = new Son();
son1.a = 11;
son2.a = 12;
father.print();
son1.print();
son2.print();
son1.update();
son2.update();
father.print();
son1.print();
son2.print();
1 [ 1, 2, 1 ] 5
11 [ 1, 2, 1 ] 5
12 [ 1, 2, 1 ] 5
1 [ 1, 2, 1 ] 5
5 [ 1, 2, 1, 11, 12 ] 5
6 [ 1, 2, 1, 11, 12 ] 5

代码执行过程及结果分析

  1. 定义 FatherSon 构造函数

    • Father 构造函数初始化属性 a(值为1),b(值为 [1, 2, this.a],即 [1, 2, 1]),c(对象 { field: 5 }),以及 print 方法。
    • Son 构造函数初始化属性 a(值为2)和 update 方法。Son.prototype = new Father(); 使得 Son 的实例对象能够继承 Father 中定义的 abcprint
  2. 实例化对象

    • var father = new Father(); 创建了一个 Father 的实例 father,其属性值为 a = 1b = [1, 2, 1]c = { field: 5 }
    • var son1 = new Son();var son2 = new Son(); 创建了两个 Son 的实例 son1son2。由于继承了 Father,它们各自拥有独立的 a 值(由 Son 构造函数初始化为2)和独立的 bc 的引用(通过继承 Father 的实例化对象)。因此,son1son2 的初始属性为 a = 2b = [1, 2, 1]c = { field: 5 }
  3. 修改属性

    • son1.a = 11;son1a 属性设置为11。
    • son2.a = 12;son2a 属性设置为12。
  4. 调用 print 方法

    • father.print(); 输出 father 的属性:a = 1b = [1, 2, 1]c.field = 5。结果为:1 [1, 2, 1] 5
    • son1.print(); 输出 son1 的属性:a = 11b = [1, 2, 1]c.field = 5。结果为:11 [1, 2, 1] 5
    • son2.print(); 输出 son2 的属性:a = 12b = [1, 2, 1]c.field = 5。结果为:12 [1, 2, 1] 5
  5. 调用 update 方法

    • son1.update(); 执行以下操作:

      • this.b.push(this.a);son1.a(即11)添加到 b 中,因此 son1.b 变为 [1, 2, 1, 11]
      • this.a = this.b.length;son1.a 更新为 b 的长度(4)。
      • this.c.field = this.a++;son1.c.field 设置为 a(即4),然后自增 a 为5。
      • 更新后,son1.a = 5son1.b = [1, 2, 1, 11]son1.c = { field: 4 }
    • son2.update(); 执行以下操作:

      • this.b.push(this.a);son2.a(即12)添加到 b 中,因此 son2.b 变为 [1, 2, 1, 11, 12]
      • this.a = this.b.length;son2.a 更新为 b 的长度(5)。
      • this.c.field = this.a++;son2.c.field 设置为 a(即5),然后自增 a 为6。
      • 更新后,son2.a = 6son2.b = [1, 2, 1, 11, 12]son2.c = { field: 5 }
  6. 再次调用 print 方法

    • father.print(); 仍然输出原始的 father 属性:a = 1b = [1, 2, 1]c.field = 5。结果为:1 [1, 2, 1] 5
    • son1.print(); 输出更新后的 son1 属性:a = 5b = [1, 2, 1, 11, 12]c.field = 5。结果为:5 [1, 2, 1, 11, 12] 5
    • son2.print(); 输出更新后的 son2 属性:a = 6b = [1, 2, 1, 11, 12]c.field = 5。结果为:6 [1, 2, 1, 11, 12] 5

在这个示例中,son1son2 实例共享了 Father 原型中的 bc 引用,因此 update 方法对 b 数组的修改会影响到所有 Son 实例

⭐⭐**进阶题2**⭐⭐

function FuncObj() {print = function () {console.log(1);};//重新给print变量赋值return this;//返回了this
}FuncObj.print = function () {console.log(2);
};FuncObj.prototype.print = function () {console.log(3);
};var print = function () {console.log(4);
};function print() {console.log(5);
}FuncObj.print();
print();
FuncObj().print();//相当于调用windows.print()
print();
new FuncObj.print();//调用静态方法FuncObj.print()
new FuncObj().print();//构造方法FuncObj()实例化对象,对象的print()没找到->原型上找
new new FuncObj().print();//构造方法FuncObj()实例化对象找原型上print(),再调用此方法-》仍输出3
//输出结果
2
4(变量提升,var与函数声明同名时,var声明会在提升阶段覆盖函数声明)
1
1
2
3
3
调用和输出分析
1. FuncObj.print();
  • 这是调用 FuncObj 的静态方法 print
  • 输出:2
2. print();
  • 此时 print 是定义为 var print = function () { console.log(4); }
  • 输出:4
3. FuncObj().print();
  • 调用 FuncObj(),由于 FuncObj 返回 this(即全局对象 window),它会将 print 重新定义为 function () { console.log(1); },覆盖了全局的 print
  • 然后调用 print(),即 function () { console.log(1); }
  • 输出:1
4. print();
  • 上一步中 print 被重新赋值为 function () { console.log(1); }
  • 输出:1
5. new FuncObj.print();
  • new FuncObj.print() 调用的是 FuncObj 的静态方法 print,而非实例化 FuncObjnew 操作符在此上下文中无意义,但会正常执行【简单来讲就是不涉及原型链和this使用】
  • 输出:2

为什么 new 在这里无意义

在这个过程中,new 仅仅用来调用 FuncObj.print,并没有创建 FuncObj 的实例。它的主要效果仅是创建一个与 FuncObj 无关的空对象,作为 FuncObj.printthis,并执行了 FuncObj.print 函数体。

  • new 在此无意义,因为 FuncObj.print 并不使用 this,返回的空对象也没有用。
  • 效果等同于 FuncObj.print(),唯一的区别是返回一个空对象,但对 FuncObj.print 的执行没有任何影响。
6. new FuncObj().print();
  • new FuncObj() 创建了一个 FuncObj 的实例,该实例继承了 FuncObj.prototype.print 方法。
  • 调用实例的 print 方法,即 FuncObj.prototype.print
  • 输出:3
7. new new FuncObj().print();
  • new FuncObj() 创建了一个 FuncObj 的实例,且 new FuncObj().print 返回 FuncObj.prototype.print 方法。
  • 最外层 new 调用 FuncObj.prototype.print 方法,仍然输出 3
  • 输出:3

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

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

相关文章

Linux下进程链接结构,命令行参数,环境变量

bash 是一种 shell。在 Linux 系统中,当我们在终端输入命令时,通常是在一个 shell 环境下进行的。如果这个 shell 是 bash,那么所有命令行执行的命令都是 bash 的子进程。 1.Linux下进程链接结构 进程链接补充知识: 所有进程都…

Android studio中关于printf和print和println的区别

print:为一般输出,同样不能保留精度格式转化,也不能换行输出,输出需要加上换行符printf:常用于格式转换,但需要注意不是换行输出,只用于精度转换,跟C语言的printf一样的,输出需要加上换行符prin…

GISBox VS ArcGIS:分别适用于大型和小型项目的两款GIS软件

在现代地理信息系统(GIS)领域,有许多大家耳熟能详的GIS软件。它们各自具有独特的优势,适用于不同的行业需求和使用场景。在众多企业和开发者面前,如何选择合适的 GIS 软件成为了一个值得深入思考的问题。今天&#xff…

京准同步:GPS北斗卫星授时服务器发展趋势介绍

京准同步:GPS北斗卫星授时服务器发展趋势介绍 京准同步:GPS北斗卫星授时服务器发展趋势介绍 GPS北斗卫星授时服务器的发展趋势紧密围绕着不断提升的时间同步精度、可靠性、安全性,以及适应广泛应用场景的需求展开,以下是卫星授时…

精深之道:在专业领域迅速铸就影响力

在知识爆炸的时代专业化已成为各行各业竞争的关键词。要想在专业领域内快速实现影响力,不仅需要深厚的专业知识积累,还需要独到的见解、创新的思维以及有效的传播策略。本文旨在探讨如何在专业领域内迅速建立并扩大个人或组织的影响力,成为行…

区块链:Raft协议

Raft 协议是一种分布式共识机制,这种机制适用于网络中存在一定数量的故障节点,但不考虑“恶意”节点的情况,所以更适合作为私有链和联盟链的共识算法。 在此协议中,每个节点有三种状态: 候选者 ,可以被选…

微服务(二)

目录 1.网关路由 1.1.认识网关 1.2.快速入门 1.2.1.引入依赖 1.2.2.启动类 1.2.3.配置路由 1.3.路由过滤 2.网关登录校验 2.1.鉴权思路分析 2.2.网关过滤器 2.3.自定义过滤器 2.3.1.自定义GatewayFilter 2.3.2.自定义GlobalFilter 2.4.登录校验 2.4.1.JWT工具 …

操作系统(12) (并发(3)------哲学家进餐问题(Dining Philosophers Problem)解决方案/管程(monitor))

目录 哲学家进餐问题描述 解决方案 1: 解决方案 2:信号量实现 解决方案 3:使用 Monitor 的实现 1. 监视器的组成部分 2. 监视器的优点 3. 使用监视器解决哲学家进餐问题 4. 使用监视器的优势 5. 监视器的局限性 6. Mesa风格和Hoare风…

ESP32学习笔记_FreeRTOS(1)——Task的创建和使用

摘要(From AI): 本文是基于 FreeRTOS 和 ESP_IDF 的学习笔记,详细讲解了任务管理、优先级设置、任务堆栈监控、看门狗定时器(IWDT 和 TWDT)等关键功能。内容涵盖任务创建与删除、任务挂起与恢复、时间片轮转调度机制,以及任务看门…

95.【C语言】数据结构之双向链表的头插,头删,查找,中间插入,中间删除和销毁函数

目录 1.双向链表的头插 方法一 方法二 2.双向链表的头删 3.双向链表的销毁 4.双向链表的某个节点的数据查找 5.双向链表的中间插入 5.双向链表的中间删除 6.对比顺序表和链表 承接94.【C语言】数据结构之双向链表的初始化,尾插,打印和尾删文章 1.双向链表的头插 方法…

【Docker容器化技术】docker安装与配置、常用命令、容器数据卷、应用部署实战、Dockerfile、服务编排docker-compose、私有仓库

文章目录 一、Docker的安装与配置1、docker概述2、安装docker3、docker架构4、配置镜像加速器 二、Docker命令1、服务相关命令2、镜像相关命令3、容器相关命令 三、Docker容器数据卷1、数据卷概念及作用2、配置数据卷3、配置数据卷容器 四、Docker应用部署实战1、部署MySQL2、部…

.netCore WebAPI中字符串加密与解密

In today’s digital landscape, securing sensitive information is more critical than ever. If you’re using ASP.NET Core, you might store configuration settings in appsettings.json. However, hardcoding sensitive data like connection strings or API keys in p…

海外云手机在出海业务中的优势有哪些?

随着互联网技术的快速发展,海外云手机已在出海电商、海外媒体推广和游戏行业都拥有广泛的应用。对于国内的出海电商企业来说,短视频引流和社交平台推广是带来有效流量的重要手段。借助云手机,企业能够更高效地在新兴社交平台上推广产品和品牌…

abap 可配置通用报表字段级日志监控

文章目录 1.功能需求描述1.1 功能1.2 效果展示2.数据库表解释2.1 表介绍3.数据库表及字段3.1.应用日志数据库抬头表:ZLOG_TAB_H3.2.应用日志数据库明细表:ZLOG_TAB_P3.3.应用日志维护字段配置表:ZLOG_TAB_F4.日志封装类5.代码6.调用方式代码7.调用案例程序demo1.功能需求描述 …

OceanBase 应用实践:如何处理数据空洞,降低存储空间

问题描述 某保险行业客户的核心系统,从Oracle 迁移到OceanBase之后,发现数据存储空间出现膨胀问题,数据空间 datasize9857715.48M,实际存储占用空间17790702.00M。根据 required_mb - data_mb 值判断,数据空洞较为严重…

React diff算法和Vue diff算法的主要区别

React和Vue都是流行的前端框架,它们各自实现了diff算法来优化虚拟DOM的更新过程。以下是React diff算法和Vue diff算法的主要区别: 1. diff策略 React diff算法: React的diff算法主要采用了同层级比较的策略,即它不会跨层级比较节…

软件测试:测试用例详解

🍅 点击文末小卡片,免费获取软件测试全套资料,资料在手,涨薪更快 一、通用测试用例八要素   1、用例编号;    2、测试项目;   3、测试标题; 4、重要级别;    5、预置…

C++——左值和右值的本质区别

左值和右值好干嘛? 深入理解左值和右值可以帮助我们对代码进行优化 一、什么是左值和右值 左值:有某种存储支持的变量 右值:临时值(字面量、函数的结果) Ⅰ右值是字面量 int yy 22;22本身就是一个临时的&#xf…

centos查看硬盘资源使用情况命令大全

在 CentOS 系统中,你可以使用几个命令来查看硬盘的资源和使用情况。以下是一些常用的命令: 1. df 命令 df (disk free) 用于显示文件系统的磁盘空间占用情况。 df -h-h 参数表示以人类可读的格式(如 GB, MB)显示。输出会显示每…

【爬虫分享】

爬虫分享 1、爬虫科普 视频发送于2024-10-27 14 _50.mp4 全屏预览下载附件 所以 爬虫 其实是非常 可“刑” 可“铐” 的。 2、逆向方法 算法还原 补环境 无头浏览器(自动化) rpc 参数生成速度:算法还原 > 补环境 > rpc > 无头…