JavaScript进阶3之参数按值传递、call,apply,bind和new的实现、继承的多种方式

JavaScript基础

  • 参数按值传递
    • 按值传递
    • 共享传递
  • call、apply、bind和new的实现
    • this
      • 软绑定
      • 硬绑定
    • call的实现
      • 第一步
      • 第二步
      • 第三步
    • apply的实现
    • bind的实现
      • 返回函数的模拟实现
      • 传参的模拟实现
      • 构造函数效果的模拟实现
      • 构造函数效果的优化实现
    • new的实现
      • 初步实现
  • 继承的多种方式&优缺点
    • 原型链继承
    • 构造函数借用
    • 最常用的方式-组合继承
    • 原型继承
    • 最好的方式-寄生式继承

参数按值传递

按值传递

  1. ECMAScript中所有函数的参数都是按值传递的。
  2. 按值传递:把函数外部的值复制给函数内部的参数,就和把值从一个变量复制到另一个变量一样。
var value = 1;
function foo(v) {v = 2;console.log(v); //2
}
foo(value);
console.log(value) // 1

内存分布:
改变前:
在这里插入图片描述
改变后:
在这里插入图片描述

当传递 value 到函数 foo 中,相当于拷贝了一份 value,假设拷贝的这份叫 _value,函数中修改的都是 _value 的值,而不会影响原来的 value 值。

共享传递

按引用传递:传递对象的引用(真实的物理地址),函数内部对参数的任何改变都会影响该对象的值,因为两者引用的是同一个对象。

var obj = {value: 1
};
function foo(o) {o.value = 2;console.log(o.value); //2
}
foo(obj);
console.log(obj.value) // 2

改变前:
在这里插入图片描述
在这里插入图片描述

改变后:
在这里插入图片描述
在这里插入图片描述

var obj = {value: 1
};
function foo(o) {o = 2;console.log(o); //2
}
foo(obj);
console.log(obj.value) // 1

共享传递是指,在传递对象的时候,传递的是地址索引。
所以修改 o.value,可以通过引用找到原值,但是直接修改 o,并不会修改原值。所以上面两个例子其实都是按共享传递。
改变前:
在这里插入图片描述
在这里插入图片描述

改变后:
在这里插入图片描述
在这里插入图片描述

函数传递参数 ,传递的是参数的拷贝:

  1. 指针拷贝,拷贝的是地址索引;
  2. 常规类型拷贝,拷贝的是值 ;

call、apply、bind和new的实现

call,apply,bind方法解决的是:this指向

this

this首先需要跟执行上下文挂钩
绑定方式:软绑定,硬绑定(call、apply、bind)

软绑定

this.name="window"
function test() {console.log(this.name);
}
const zhangsan = {name: "zhangsan",test: test,
};
test()
zhangsan.test()

在这里插入图片描述

硬绑定

function test() {console.log(this.name);
}
const xiaoming={name:'xiaoming'}
//硬绑定
test.call(xiaoming)
test.apply(xiaoming)
const t=test.bind(xiaoming)
t()

在这里插入图片描述
注意两点:

  1. call 改变了 this 的指向,指向到 xiaoming;
  2. test 函数执行了;

call的实现

call() :在使用一个指定的 this 值和若干个指定的参数值的前提下调用某个函数或方法。

第一步

使用软绑定的方式实现call,

所以我们模拟的步骤可以分为:

  1. 将函数设为对象的属性;
  2. 执行该函数;
  3. 删除该函数;
// 第一步
// test 是对象的属性名,反正最后也要删除它,所以起什么都可以。
xiaoming.test = test
// 第二步
xiaoming.test()
// 第三步
delete xiaoming.test

根据上述思路,提供一版:

// 第一版
Function.prototype.call2 = function(context) {// 首先要获取调用call的函数,用this可以获取,this指向的是 barcontext.fn = this;context.fn();delete context.fn;  //卸磨杀驴
}// 测试一下let foo = {value: 1
};function bar() {console.log(this.value);
}bar.call2(foo); // 1

第二步

call除了可以指定this,还可以指定参数

var foo = {value: 1
};function bar(name, age) {console.log(name)console.log(age)console.log(this.value);
}bar.call(foo, 'kevin', 18);
// kevin
// 18
// 1

在这里插入图片描述

可以从 Arguments 对象中取值,取出第二个到最后一个参数,然后放到一个数组里。
上述代码的Arguments中取第二个到最后一个的参数

// 以上个例子为例,此时的arguments为:
// arguments = {
//      0: foo,
//      1: 'kevin',
//      2: 18,
//      length: 3
// }
// 因为arguments是类数组对象,所以可以用for循环
var args = [];
for(var i = 1, len = arguments.length; i < len; i++) {args.push('arguments[' + i + ']');
}// 执行后 args为 ["arguments[1]", "arguments[2]", "arguments[3]"]

接下来使用eval拼接成一个函数

eval('context.fn(' + args +')')

考虑到目前大部分浏览器在console中限制eval的执行,也可以使用rest
此处代码为:

// 第二版
Function.prototype.call2 = function(context) {context.fn = this;let arg = [...arguments].slice(1)  //arguments是类数组对象,将其拆分,并转为数组,然后再从第一个参数开始截取context.fn(...arg)  //arg数组拆分,逐步传入delete context.fn;
}// 测试一下
var foo = {value: 1
};function bar(name, age) {console.log(name)console.log(age)console.log(this.value);
}bar.call2(foo, 'kevin', 18); 
// kevin
// 18
// 1

在这里插入图片描述

第三步

  1. this 参数可以传 null,当为 null 的时候,视为指向 window
    举个例子:
var value = 1;function bar() {console.log(this.value);
}bar.call(null); // 1

在这里插入图片描述

  1. 针对函数,可以实现返回值
var obj = {value: 1
}function bar(name, age) {return {value: this.value,name: name,age: age}
}console.log(bar.call(obj, 'kevin', 18));
// Object {
//    value: 1,
//    name: 'kevin',
//    age: 18
// }

这里

// 第三版
Function.prototype.call2 = function (context) {var context = context || window;context.fn = this;let arg = [...arguments].slice(1)let result = context.fn(...arg)delete context.fnreturn result
}// 测试一下
var value = 2;var obj = {value: 1
}function bar(name, age) {console.log(this.value);return {value: this.value,name: name,age: age}
}bar.call2(null); // 2console.log(bar.call2(obj, 'kevin', 18));
// 1
// Object {
//    value: 1,
//    name: 'kevin',
//    age: 18
// }

这边给出最简化的写法:

Function.prototype.call2 = function(context, ...args) {// 判断是否是undefined和nullif (typeof context === 'undefined' || context === null) {context = window}//es6 Symbol:每定义的symbol都是唯一的let fnSymbol = Symbol()//确保fn不重复,是唯一的context[fnSymbol] = thislet fn = context[fnSymbol](...args)delete context[fnSymbol] return fn
}

typeof 的安全机制,比如:
typeof fasldjfalsfjkasjfklasdjfld 不会抛出错误

补充一个无关知识点:1帧=1000/60=16.666毫秒

apply的实现

apply 的实现跟 call 类似,只是入参不一样,apply为数组

const foo={value:1
}
function bar(name,age){console.log(name,age,this.value)
}bar.apply(foo,['ddd',20])

在这里插入图片描述

Function.prototype.apply = function (context, arr) {var context = Object(context) || window;context.fn = this;var result;if (!arr) {result = context.fn();}else {result = context.fn(...arr)}delete context.fnreturn result;
}

最简化版方式:

Function.prototype.apply2 = function(context, args) {// 判断是否是undefined和nullif (typeof context === 'undefined' || context === null) {context = window}let fnSymbol = Symbol()context[fnSymbol] = thislet fn = context[fnSymbol](...args)delete context[fnSymbol] return fn
}

bind的实现

bind() 方法会创建一个新函数。当这个新函数被调用时,bind() 的第一个参数将作为它运行时的 this,之后的一序列参数将会在传递的实参前传入作为它的参数。

由此我们可以首先得出 bind 函数的两个特点:

  1. 返回一个函数;
  2. 可以传入参数;

返回函数的模拟实现

var foo = {value: 1
};function bar() {console.log(this.value);
}// 返回了一个函数
var bindFoo = bar.bind(foo); bindFoo(); // 1

关于指定 this 的指向,我们可以使用 call 或者 apply 实现

// 第一版
Function.prototype.bind2 = function (context) {//context === foo//bar === this	var self = this;  // 虑到绑定函数可能是有返回值的,加上returnreturn function () {return self.apply(context);}}

传参的模拟实现

关于参数的传递

var foo = {value: 1
};function bar(name, age) {console.log(this.value);console.log(name);console.log(age);}var bindFoo = bar.bind(foo, 'daisy');
bindFoo('18');
// 1
// daisy
// 18

当需要传 name 和 age 两个参数时,可以在 bind 的时候,只传一个 name,在执行返回的函数的时候,再传另一个参数 age。
这里如果不适用rest,使用arguments进行处理:

// 第二版
Function.prototype.bind2 = function (context) {var self = this;  //记录bar// 获取bind2函数从第二个参数到最后一个参数var args = Array.prototype.slice.call(arguments, 1);return function () {// 这个时候的arguments是指bind返回的函数传入的参数var bindArgs = Array.prototype.slice.call(arguments);return self.apply(context, args.concat(bindArgs));}
}

rest方式:

Function.prototype.bind2=function(context,...args){//args=['daisy']// bind2的入参传递的const self=this  //记录barreturn function (...returnArgs){//returnArgs=['18']//18 这个函数的入参传递//[...args,...returnArgs] => ['daisy','18']return self.apply(context,[...args,...returnArgs])}
}

构造函数效果的模拟实现

bind 还有一个特点,就是
一个绑定函数也能使用new操作符创建对象:这种行为就像把原函数当成构造器。提供的 this 值被忽略,同时调用时的参数被提供给模拟函数。

也就是说当 bind 返回的函数作为构造函数的时候,bind 时指定的 this 值会失效,但传入的参数依然生效。举个例子:

var value = 2;var foo = {value: 1
};function bar(name, age) {this.habit = 'shopping';console.log(this.value);console.log(name);console.log(age);
}bar.prototype.friend = 'kevin';var bindFoo = bar.bind(foo, 'daisy');var obj = new bindFoo('18');    //bind作为构造函数使用, this会指向实例 this->obj 否则 this->context
// undefined
// daisy
// 18
console.log(obj.habit);
console.log(obj.friend);
// shopping
// kevin

尽管在全局和 foo 中都声明了 value 值,最后依然返回了 undefind,说明绑定的 this 失效了
后文中new 的模拟实现,就会知道这个时候的 this 已经指向了 obj。

// 第三版
Function.prototype.bind2 = function (context) {var self = this;var args = Array.prototype.slice.call(arguments, 1);var fBound = function () {var bindArgs = Array.prototype.slice.call(arguments);// 当作为构造函数时,this 指向实例,此时结果为 true,将绑定函数的 this 指向该实例,可以让实例获得来自绑定函数的值// 以上面的是 demo 为例,如果改成 `this instanceof fBound ? null : context`,实例只是一个空对象,将 null 改成 this ,实例会具有 habit 属性// 当作为普通函数时,this 指向 window,此时结果为 false,将绑定函数的 this 指向 contextreturn self.apply(this instanceof fBound ? this : context, args.concat(bindArgs));}// 修改返回函数的 prototype 为绑定函数的 prototype,实例就可以继承绑定函数的原型中的值fBound.prototype = this.prototype;return fBound;
}

rest方式:

Function.prototype.bind2=function(context,...args){const self=thisconst fBound=function(...returnArgs){//this->obj  obj instanceof bindFoo === this instanceof fBound ->true 则作为构造函数使用的return self.apply(this instanceof fBound?this:context,[...args,...returnArgs])}// 修改返回函数的 prototype 为绑定函数的 prototype,实例就可以继承绑定函数的原型中的值//此时,修改obj的原型 -> 等同于修改返回的构造函数的原型fBound.prototype = this.prototype;// this是obj,希望最终obj身上也有bar身上的friend属性,// bar.prototype.friend = 'kevin'; new bindFoo生成的实例上也有这个属性,bindFoo.prototype = bar.prototype => fBound.prototype=this.prototypereturn fBound
}
var value = 2;var foo = {value: 1
};function bar(name, age) {this.habit = 'shopping';console.log(this.value);console.log(name);console.log(age);
}bar.prototype.friend = 'kevin';var bindFoo = bar.bind2(foo, 'daisy');var obj = new bindFoo('18');console.log(obj)

在这里插入图片描述

构造函数效果的优化实现

但是在这个写法中,我们直接将 fBound.prototype = this.prototype,我们直接修改 fBound.prototype 的时候,也会直接修改绑定函数的 prototype。这个时候,我们可以通过一个空函数来进行中转:

// 第四版
Function.prototype.bind2 = function (context) {var self = this;var args = Array.prototype.slice.call(arguments, 1);var fNOP = function () {};   //作为中间的prototype的过度var fBound = function () {var bindArgs = Array.prototype.slice.call(arguments);return self.apply(this instanceof fNOP ? this : context, args.concat(bindArgs));}fNOP.prototype = this.prototype;  //fBound -> fNOP -> this(obj)// fBound的原型 -> fNOP的实例fBound.prototype = new fNOP();return fBound;
}

或:

Function.prototype.bind2=function(context,...args){const self=thisvar fNOP = function () {};   //作为中间的prototype的过度const fBound=function(...returnArgs){//this->obj  obj instanceof bindFoo === this instanceof fBound ->true 则作为构造函数使用的return self.apply(this instanceof fNOP?this:context,[...args,...returnArgs])}fNOP.prototype = this.prototype;  //fBound -> fNOP -> this(obj)// fBound的原型 -> fNOP的实例fBound.prototype = new fNOP();return fBound;
    var fNOP = function () {};   //作为中间的prototype的过度fNOP.prototype = this.prototype;  //fBound -> fNOP -> this(obj)// fBound的原型 -> fNOP的实例fBound.prototype = new fNOP();

在这里插入图片描述

new的实现

new 运算符创建一个用户定义的对象类型的实例或具有构造函数的内置对象类型之一
先看看 new 实现了哪些功能。

function Person (name, age) {this.name = name;this.age = age;this.habit = 'Games';
}Person.prototype.strength = 80;Person.prototype.sayYourName = function () {console.log('I am ' + this.name);
}var person = new Person('Kevin', '18');console.log(person.name) // Kevin
console.log(person.habit) // Games
console.log(person.strength) // 60person.sayYourName(); // I am Kevin

我们可以看到,实例 person 可以:

  1. 访问到 Otaku 构造函数里的属性;
  2. 访问到 Otaku.prototype 中的属性;

因为 new 是关键字,所以无法像 bind 函数一样直接覆盖,所以我们写一个函数,命名为 objectFactory,来模拟 new 的效果。用的时候是这样的:

function Person () {……
}// 使用 new
var person = new Person(……);
// 使用 objectFactory
var person = objectFactory(Person, ……)

初步实现

因为 new 的结果是一个新对象,所以在模拟实现的时候,我们也要建立一个新对象,假设这个对象叫 obj,因为 obj 会具有 Person 构造函数里的属性,我们可以使用 Person.apply(obj, arguments)来给 obj 添加新的属性。
然后,实例的 proto 属性会指向构造函数的 prototype,也正是因为建立起这样的关系,实例可以访问原型上的属性

// 第一版代码
function objectFactory() {var obj = new Object(),Constructor = [].shift.call(arguments);obj.__proto__ = Constructor.prototype;Constructor.apply(obj, arguments);return obj;};

在这一版中,我们:

  1. 用new Object() 的方式新建了一个对象 obj;
  2. 取出第一个参数,就是我们要传入的构造函数。此外因为 shift 会修改原数组,所以 arguments 会被去除第一个参数;
  3. 将 obj 的原型指向构造函数,这样 obj 就可以访问到构造函数原型中的属性;
  4. 使用 apply,改变构造函数 this 的指向到新建的对象,这样 obj 就可以访问到构造函数中的属性;
  5. 返回 obj;

测试:

function Person (name, age) {this.name = name;this.age = age;this.habit = 'Games';
}Person.prototype.strength = 60;Person.prototype.sayYourName = function () {console.log('I am ' + this.name);
}function objectFactory() {var obj = new Object(),Constructor = [].shift.call(arguments);obj.__proto__ = Constructor.prototype;Constructor.apply(obj, arguments);return obj;
};var person = objectFactory(Person, 'Kevin', '18')console.log(person.name) // Kevin
console.log(person.habit) // Games
console.log(person.strength) // 60person.sayYourName(); // I am Kevin

假如构造函数有返回值

function Person (name, age) {this.strength = 60;this.age = age;return {name: name,habit: 'Games'}
}var person = new Person('Kevin', '18');console.log(person.name) // Kevin
console.log(person.habit) // Games
console.log(person.strength) // undefined
console.log(person.age) // undefined

在这个例子中,构造函数返回了一个对象,在实例 person 中只能访问返回的对象中的属性。
而且还要注意一点,在这里我们是返回了一个对象,假如我们只是返回一个基本类型的值呢?
再举个例子:

function Person (name, age) {this.strength = 60;this.age = age;return 'handsome boy';
}var person = new Otaku('Kevin', '18');console.log(person.name) // undefined
console.log(person.habit) // undefined
console.log(person.strength) // 60
console.log(person.age) // 18

这次尽管有返回值,但是相当于没有返回值进行处理。
所以我们还需要判断返回的值是不是一个对象,如果是一个对象,我们就返回这个对象,如果没有,我们该返回什么就返回什么。

// 最终版的代码
function objectFactory() {var obj = new Object(),Constructor = [].shift.call(arguments);obj.__proto__ = Constructor.prototype;var ret = Constructor.apply(obj, arguments);return typeof ret === 'object' ? ret : obj;};

继承的多种方式&优缺点

原型链继承

function Parent () {this.names = ['xianzao', 'zaoxian'];
}function Child () {}Child.prototype = new Parent();var child1 = new Child();child1.names.push('test');console.log(child1.names); // ["xianzao", "zaoxian", "test"]var child2 = new Child();console.log(child2.names); // ["xianzao", "zaoxian", "test"]

问题:引用类型的属性被所有实例共享,数据被共享了

构造函数借用

function Parent () {this.names = ['xianzao', 'zaoxian'];
}function Child () {//this指向谁?Child实例化出来的对象Parent.call(this);
}var child1 = new Child();child1.names.push('test');console.log(child1.names); // ["xianzao", "zaoxian", "test"]var child2 = new Child();console.log(child2.names); // ["xianzao", "zaoxian"]

优点:

  1. 避免了引用类型的属性被所有实例共享;
  2. 可以在 Child 中向 Parent 传参;
function Parent (name) {this.name = name;
}function Child (name) {Parent.call(this, name);
}var child1 = new Child('xianzao');console.log(child1.name); // xianzaovar child2 = new Child('zaoxian');console.log(child2.name); // zaoxian

缺点:
方法都在构造函数中定义,每次创建实例都会创建一遍方法。(上述的Parent)

最常用的方式-组合继承

function Parent (name) {this.name = name;this.colors = ['red', 'blue', 'green'];
}Parent.prototype.getName = function () {console.log(this.name)
}function Child (name, age) {Parent.call(this, name); // 构造器借用了this.age = age;}Child.prototype = new Parent(); // 原型链继承
Child.prototype.constructor = Child; // 将构造器引用指回来var child1 = new Child('kevin', '18');child1.colors.push('black');console.log(child1.name); // kevin
console.log(child1.age); // 18
console.log(child1.colors); // ["red", "blue", "green", "black"]var child2 = new Child('daisy', '20');console.log(child2.name); // daisy
console.log(child2.age); // 20
console.log(child2.colors); // ["red", "blue", "green"]

优点:融合原型链继承和构造函数的优点,是 JavaScript 中最常用的继承模式。

原型继承

function createObj(o) {function F(){}F.prototype = o;return new F();
}

缺点:
包含引用类型的属性值始终都会共享相应的值,这点跟原型链继承一样。

var person = {name: 'kevin',friends: ['daisy', 'kelly']
}var person1 = createObj(person);
var person2 = createObj(person);person1.name = 'person1';
console.log(person2.name); // kevinperson1.friends.push('taylor');
console.log(person2.friends); // ["daisy", "kelly", "taylor"]

最好的方式-寄生式继承

创建一个仅用于封装继承过程的函数,该函数在内部以某种形式来做增强对象,最后返回对象。

function createObj (o) {var clone = Object.create(o);clone.sayName = function () {console.log('hi');}return clone;
}

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

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

相关文章

(学习日记)2024.03.09:UCOSIII第十一节:就绪列表

写在前面&#xff1a; 由于时间的不足与学习的碎片化&#xff0c;写博客变得有些奢侈。 但是对于记录学习&#xff08;忘了以后能快速复习&#xff09;的渴望一天天变得强烈。 既然如此 不如以天为单位&#xff0c;以时间为顺序&#xff0c;仅仅将博客当做一个知识学习的目录&a…

计算机网络 —— 运输层

运输层 5.1 运输层概述 运输层的主要任务是&#xff0c;如何为运行在不同主机上的应用进程提供直接的通信服务。运输层协议又称为端到端协议。 根据应用需求的不同&#xff0c;因特网的运输层为应用层提供了两种不同的运输协议&#xff0c;即面向连接的TCP和无连接的UDP 5.2…

金融需要多样性,量化需要C++!通过本文,你可以知道:1、为什么是C++

通过本文&#xff0c;你可以知道&#xff1a; 1、为什么是C 2、Python的用武之地 3、量化C岗位薪酬水平 C VS Python 量化交易系统开发语言主要用C&#xff0c;也有人用Python。 但是从经验看&#xff0c;用C开发的量化交易系统能够让在系统中程序运行的速度更快。 量化交易…

Maya为模型添加细分数

文章目录 方法1 通道盒操作注意 方法2 添加分段操作注意 方法3 平滑操作 方法1 通道盒 操作 选中物体&#xff0c;选择通道盒/输入/点一下模型的名字/细分数&#xff0c;分别为长宽高添加细分 这相当于修改模型的底层数据&#xff0c;不会平滑模型&#xff0c;只会进行细分 …

瑞熙贝通实验室物联网管理平台新升级|支持远程开门视频监控与电源控制以及环境监测

瑞熙贝通实验室智能物联网管控平台&#xff1a;利用“互联网与物联网技术”有机融合&#xff0c;对实验室的用电安全监测、实验室环境异常监测&#xff08;颗粒物监测、明火监测、可燃气体、烟雾监测、温湿度传感器、红外人体感应&#xff09;、实验室人员安全准入、万物互联等…

爬虫案例1

通过get请求直接获取电影信息 目标页面: https://spa6.scrape.center/在network中可以看到是通过Ajax发送的请求&#xff0c;这个请求在postman中也可以直接请求成功&#xff0c;这只是一个用来练习爬虫的&#xff0c;没有达到js逆向的过程&#xff0c;需要通过分析js 代码来获…

Excel判断CD两列在EF两列的列表中是否存在

需求 需要将CD两列的ID和NAME组合起来&#xff0c;查询EF两列的ID和NAME组合起来的列表中是否存在&#xff1f; 比如&#xff0c;判断第二行的“123456ABC”在EF的第二行到第四行中是否存在&#xff0c;若存在则显示Y&#xff0c;不存在则显示N 实现的计算公式 IF(ISNUMBER…

淘宝基于Nginx二次开发的Tengine服务器

最近在群里看到这样一张阿里云网关报错的截图&#xff0c;我保存下来看了下 看到下面有 Tengine提供技术支持&#xff0c;这个Tengine是什么东西呢&#xff1f;我搜索了下似乎是淘宝在nginx的基础上自己改的Web服务器 Tengine还支持OpenResty框架&#xff0c;该框架是基于Ngin…

SAR ADC学习笔记(5)

高精度比较器 一、基于开环运放的比较器 OP开环应用时不需要考虑频率特性(相位裕度那些) &#xff0c;不存在稳定性问题。 单级运放的时域响应 多级运放 二、Latch比较器 Latch比较器的速度 Latch比较器的噪声优化 三、高速高精度比较器 消除失调电压OFFSET OOS IOS

nRF52832——唯一 ID 与加密解密

nRF52832——唯一 ID 与加密解密 唯一 ID 概念唯一 ID 作用读取唯一 ID 唯一 ID 用于加密TEA 加密算法唯一 ID 的加密和解密 唯一 ID 概念 唯一 ID 作用 nRF52xx 微控制器提供一组 64 位的唯一 ID 号&#xff0c;这个唯一身份标识所提供的 ID 值对任意一个 nRF52xx 微控制器&…

展会邀约 | 加速科技将携重磅产品亮相SEMICON China 2024

SEMICON China 2024将于3月20日-3月22日在上海新国际博览中心隆重举行。展会期间&#xff0c;加速科技将携重磅产品高性能数模混合信号测试机ST2500EX、LCD Driver测试机Flex10K-L、高密度数模混合信号测试系统ST2500E、高性能数模混合信号测试系统ST2500A亮相此次行业盛会&…

WEB区块链开发组件 - KLineChart

当我们开发区块链的时候&#xff0c;实现K线可能大家会想到EChart&#xff0c;但是EChart做可能需要耗费大量工作量&#xff0c;实现出来的功能估计也是牵强着用。 这时候&#xff0c;我们可能网上会搜索到TradingView,可是这个组件虽然功能非常强大&#xff0c;但是还是要费事…

Android7.1 ANR error 弹窗处理

Android7.1 ANR error 弹窗处理 问题描述解决方法 郑重声明:本人原创博文&#xff0c;都是实战&#xff0c;均经过实际项目验证出货的 转载请标明出处:攻城狮2015 Platform: Rockchip OS:Android 7.1.2 Kernel: 3.10 问题描述 有时会用到第三方apk&#xff0c;内置到系统中&…

全国车辆识别代码信息API查询接口-VIN深度解析

我们先来介绍下什么是vin码&#xff0c;以及vin码的构成结构解析&#xff0c;汽车VIN码&#xff0c;也叫车辆识别号码&#xff0c;通俗可以理解为汽车的身份证号码。 VIN码一共分四大部分&#xff1a; 1~3位&#xff0c;是世界制造厂识别代号&#xff08;WMI&#xff09;&…

DevOps本地搭建笔记(个人开发适用)

需求和背景 win11 wsl2 armbian(玩客云矿渣&#xff09;&#xff0c;构建个人cicd流水线&#xff0c;提高迭代效率。 具体步骤 基础设施准备 硬件准备&#xff1a;一台笔记本&#xff0c;用于开发和构建部署&#xff0c;一台服务器&#xff0c;用于日常服务运行。 笔记本…

如何批量注册无数个电子邮箱

需求 最近我们需要批量注册无数个steam账号来做一些不可描述的事情&#xff0c;那么我们就需要先批量注册无数个电子邮箱Email 而且我们希望注册和接收邮件是可以通过脚本自动化的&#xff0c;最好是通过正常的API接口 什么叫正常的API接口&#xff1f;正常的API接口是指邮件…

Antd中s-table组件某字段进行排序

Antd中s-table组件某字段进行排序 提前说明&#xff0c;s-table组件包含分页等功能 <s-tableref"table":columns"columns":data"loadData"bordered:row-key"(record) > record.id"></s-table>而其中loadData为获取表数…

线性表的顺序存储实验

附 录 #include<stdio.h> #include<stdlib.h>typedef struct {double* data;int length; }Sqlist;void initSqlist(Sqlist* L, int n) {L->data (double*)malloc(n * sizeof(double)); if (L->data NULL){printf("内存分配失败\n");exit(1);}pri…

MTK安卓开发板_联发科开发板评估套件_安卓主板硬件开发

在介绍开发板之前&#xff0c;让我们先来区分一下核心板和开发板的区别。核心板是一种集成度高、功能完整的计算模块&#xff0c;搭载系统&#xff0c;简化了外围接口&#xff0c;体积尺寸相对较小&#xff0c;主要适用于嵌入式系统。而开发板由核心板底板组成&#xff0c;提供…

Python实战:采集全国5A景点名单

本文将以采集全国 5A 景点名单为例&#xff0c;详细介绍如何使用 Python 进行数据采集。 本文采集到全国340家5A景区的名单&#xff0c;包括景区名称、地区、 A级、评定年份这些字段。 一、分析数据源 为了获取权威数据&#xff0c;我们来到主管部门的官方网站&#xff0c;在右…