JavaScript教程(四)--- 函数

函数

函数是 JavaScript 中的基本组件之一。JavaScript 中的函数类似于过程——一组执行任务或计算值的语句。但要成为函数,这个过程应该接受输入并返回与输入存在某些明显关系的输出。要使用一个函数,你必须将其定义在你希望调用它的作用域内。

定义函数

函数声明

一个函数定义(也称为函数声明,或函数语句)由 function 关键字,并跟随以下部分组成:

  • 函数名称。
  • 函数参数列表,包围在括号中并由逗号分隔。
  • 定义函数的 JavaScript 语句,用大括号括起来,{ /* … */ }

例如,以下的代码定义了一个简单的名为 square 的函数:

function square(number) {return number * number;
}

函数 square 接收一个名为 number 的参数。这个函数只有一个语句,其表示该函数将函数的参数(即 number)自乘后返回。函数的 return 语句指定了函数的返回值:number * number

参数本质上是按值传递给函数的——因此,即使函数体的代码为传递给函数的参数赋了新值,这个改变也不会反映到全局或调用该函数的代码中

如果你将对象作为参数传递,而函数改变了这个对象的属性,这样的改变对函数外部是可见的,如下面的例子所示:

function myFunc(theObject) {theObject.make = "Toyota";
}const mycar = {make: "Honda",model: "Accord",year: 1998,
};console.log(mycar.make); // "Honda"
myFunc(mycar);
console.log(mycar.make); // "Toyota"

如果你将数组作为参数传递,而函数改变了这个数组的值,这样的改变对函数外部也同样可见,如下面的例子所示:

function myFunc(theArr) {theArr[0] = 30;
}const arr = [45];console.log(arr[0]); // 45
myFunc(arr);
console.log(arr[0]); // 30

函数表达式

虽然上面的函数声明在语法上是一个语句,但函数也可以由函数表达式创建。

这样的函数可以是匿名的;它不必有一个名称。例如,函数 square 也可这样来定义:

const square = function (number) {return number * number;
};console.log(square(4)); // 16

然而,也可以为函数表达式提供名称,并且可以用于在函数内部代指其本身,或者在调试器堆栈跟踪中识别该函数:

const factorial = function fac(n) {return n < 2 ? 1 : n * fac(n - 1);
};console.log(factorial(3)); // 6

当将函数作为参数传递给另一个函数时,函数表达式很方便。下面的例子演示了一个叫 map 的函数,该函数接收函数作为第一个参数,接收数组作为第二个参数:

function map(f, a) {const result = new Array(a.length);for (let i = 0; i < a.length; i++) {result[i] = f(a[i]);}return result;
}

在以下代码中,该函数接收由函数表达式定义的函数,并对作为第二个参数接收的数组的每个元素执行该函数:

function map(f, a) {const result = new Array(a.length);for (let i = 0; i < a.length; i++) {result[i] = f(a[i]);}return result;
}const cube = function (x) {return x * x * x;
};const numbers = [0, 1, 2, 5, 10];
console.log(map(cube, numbers)); // [0, 1, 8, 125, 1000]

在 JavaScript 中,可以根据条件来定义一个函数。比如下面的代码,当 num 等于 0 的时候才会定义 myFunc

let myFunc;
if (num === 0) {myFunc = function (theObject) {theObject.make = "Toyota";};
}

除了上述的定义函数方法外,你也可以在运行时用 Function 构造函数从一个字符串创建一个函数,很像 eval() 函数。

当一个函数是一个对象的属性时,称之为方法。了解更多关于对象和方法的知识,请阅读使用对象。

调用函数

定义的函数并不会自动执行它。定义了函数仅仅是赋予函数以名称并明确函数被调用时该做些什么。

调用函数才会以给定的参数真正执行这些动作。例如,一旦你定义了函数 square,你可以像这样调用它:

square(5);

上述语句使用参数 5 来调用函数。函数执行完它的语句会返回值 25

函数一定要处于调用它们的作用域中,但是函数的声明可以被提升(出现在调用语句之后)。函数声明的范围是声明它的函数(或者,如果它是在顶层声明的,则为整个程序)之内。

函数的参数并不局限于字符串或数字。你也可以将整个对象传递给函数。函数 showProps()(其定义参见使用对象)就是一个将对象作为参数的示例。

函数可以调用其本身。例如,下面这个函数就是用递归计算阶乘:

function factorial(n) {if (n === 0 || n === 1) {return 1;} else {return n * factorial(n - 1);}
}

你可以这样计算 1 到 5 的阶乘:

console.log(factorial(1)); // 1
console.log(factorial(2)); // 2
console.log(factorial(3)); // 6
console.log(factorial(4)); // 24
console.log(factorial(5)); // 120

还有其他的方式来调用函数。常见的一些情形是某些地方需要动态调用函数,或者函数的实参数量是变化的,或者调用函数的上下文需要指定为在运行时确定的特定对象。

显然,函数本身就是对象,因此这些对象也有方法(参见 Function 对象)。call() 和 apply() 方法可用于实现这些目的。

函数提升

考虑以下示例:

console.log(square(5)); // 25function square(n) {return n * n;
}

尽管 square() 函数在声明之前被调用,但此代码的运行并没有任何错误。这是因为 JavaScript 解释器会将整个函数声明提升到当前作用域的顶部,因此上面的代码等价于:

// 所有函数声明实际上都位于作用域的顶部
function square(n) {return n * n;
}console.log(square(5)); // 25

函数提升仅适用于函数声明,而不适用于函数表达式。以下代码无法运行:

console.log(square(5)); // ReferenceError: Cannot access 'square' before initialization
const square = function (n) {return n * n;
};

函数作用域

在函数内定义的变量不能在函数之外的任何地方访问,因为变量仅仅在该函数的作用域内定义。相对应的,一个函数可以访问定义在其范围内的任何变量和函数。

换言之,定义在全局域中的函数可以访问所有定义在全局域中的变量。在另一个函数中定义的函数也可以访问在其父函数中定义的所有变量和父函数有权访问的任何其他变量。

// 下面的变量定义在全局作用域中
const num1 = 20;
const num2 = 3;
const name = "Chamakh";// 此函数定义在全局作用域中
function multiply() {return num1 * num2;
}console.log(multiply()); // 60// 嵌套函数示例
function getScore() {const num1 = 2;const num2 = 3;function add() {return `${name} 的得分为 ${num1 + num2}`;}return add();
}console.log(getScore()); // "Chamakh 的得分为 5"

作用域和函数栈

递归

一个函数可以指向并调用自身。有三种方法可以达到这个目的:

  1. 函数名
  2. arguments.callee
  3. 作用域内一个指向该函数的变量名

例如,思考如下的函数定义:

const foo = function bar() {// 这里编写语句
};

在这个函数体内,以下的语句是等价的:

  1. bar()
  2. arguments.callee()
  3. foo()

调用自身的函数我们称之为递归函数。在某种意义上说,递归近似于循环。两者都重复执行相同的代码,并且两者都需要一个终止条件(避免无限循环,或者在这种情况下更确切地说是无限递归)。

例如,考虑以下的循环:

let x = 0;
// “x < 10”是循环条件
while (x < 10) {// 做些什么x++;
}

可以被转化成一个递归函数声明,然后调用该函数:

function loop(x) {// “x >= 10”是退出条件(等同于“!(x < 10)”)if (x >= 10) {return;}// 做些什么loop(x + 1); // 递归调用
}
loop(0);

不过,有些算法并不能简单的用迭代来实现。例如,获取树结构(例如 DOM)中所有的节点时,使用递归实现要容易得多:

function walkTree(node) {if (node === null) {return;}// 对节点做些什么for (let i = 0; i < node.childNodes.length; i++) {walkTree(node.childNodes[i]);}
}

跟 loop 函数相比,这里每个递归调用都产生了更多的递归调用。

将递归算法转换为非递归算法是可能的,不过逻辑上通常会更加复杂,而且需要使用栈。

事实上,递归本身就使用了栈:函数栈。类似栈的行为可以在以下示例中看到:

function foo(i) {if (i < 0) {return;}console.log(`开始:${i}`);foo(i - 1);console.log(`结束:${i}`);
}
foo(3);// 打印:
// 开始:3
// 开始:2
// 开始:1
// 开始:0
// 结束:0
// 结束:1
// 结束:2
// 结束:3

嵌套函数和闭包

你可以在一个函数里面嵌套另外一个函数。嵌套(内部)函数对其容器(外部)函数是私有的。

它自身也形成了一个闭包(closure)。闭包是可以拥有独立变量以及绑定了这些变量的环境(“封闭”了表达式)的表达式(通常是函数)。

既然嵌套函数是一个闭包,就意味着一个嵌套函数可以“继承”容器函数的参数和变量。换句话说,内部函数包含外部函数的作用域。

可以总结如下:

  • 内部函数只可以在外部函数中访问。
  • 内部函数形成了一个闭包:它可以访问外部函数的参数和变量,但是外部函数却不能使用它的参数和变量。

下面的例子展示了嵌套函数:

function addSquares(a, b) {function square(x) {return x * x;}return square(a) + square(b);
}console.log(addSquares(2, 3)); // 13
console.log(addSquares(3, 4)); // 25
console.log(addSquares(4, 5)); // 41

由于内部函数形成了闭包,因此你可以调用外部函数并为外部函数和内部函数指定参数:

function outside(x) {function inside(y) {return x + y;}return inside;
}const fnInside = outside(3); // 可以这样想:给我一个可以将提供的值加上 3 的函数
console.log(fnInside(5)); // 8
console.log(outside(3)(5)); // 8

保存变量

注意到上例中 inside 被返回时 x 是怎么被保留下来的。一个闭包必须保存它可见作用域中所有参数和变量。因为每一次调用传入的参数都可能不同,每一次对外部函数的调用实际上重新创建了一遍这个闭包。只有当返回的 inside 没有再被引用时,内存才会被释放。

这与在其他对象中存储引用没什么不同,但是通常不太明显,因为并不能直接设置引用,也不能检查它们。

多层嵌套函数

函数可以被多层嵌套。例如:

  • 函数(A)可以包含函数(B),后者可以再包含函数(C)。
  • 这里的函数 B 和 C 都形成了闭包,所以 B 可以访问 AC 可以访问 B
  • 此外,因为 C 可以访问 B(而 B 可以访问 A),所以 C 也可以访问 A

因此,闭包可以包含多个作用域;它们递归地包含了所有包含它的函数作用域。这个称之为作用域链。(稍后解释它被称为“链”的原因。)

思考以下示例:

function A(x) {function B(y) {function C(z) {console.log(x + y + z);}C(3);}B(2);
}
A(1); // 打印 6(即 1 + 2 + 3)

在这个示例中,C 可以访问 B 的 y 和 A 的 x

这是因为:

  1. B 形成了一个包含 A 的闭包(即,B 可以访问 A 的参数和变量)
  2. C 形成了一个包含 B 的闭包。
  3. C 的闭包包含 B,且 B 的闭包包含 A,所以 C 的闭包也包含 A。这意味着 C 同时可以访问 B  A 的参数和变量。换言之,C 用这个顺序链接了 B 和 A 的作用域。

反过来却不是这样。A 不能访问 C,因为 A 不能访问 B 中的参数和变量,C 是 B 中的一个变量,所以 C 是 B 私有的。

命名冲突

当同一个闭包作用域下两个参数或者变量同名时,就会产生命名冲突。更近的作用域有更高的优先权,所以最近的优先级最高,最远的优先级最低。这就是作用域链。链的第一个元素就是最里面的作用域,最后一个元素便是最外层的作用域。考虑以下示例:

function outside() {const x = 5;function inside(x) {return x * 2;}return inside;
}console.log(outside()(10)); // 20(而不是 10)

命名冲突发生在语句 return x * 2 上,inside 的参数 x 和 outside 的变量 x 发生了冲突。这里的作用链域是 {insideoutside、全局对象}。因此 inside 的 x 优先于 outside 的 x,因此返回 20inside 的 x)而不是 10outside 的 x)。

闭包

闭包是 JavaScript 中最强大的特性之一。JavaScript 允许函数嵌套,并且内部函数具有定义在外部函数中的所有变量和函数(以及外部函数能访问的所有变量和函数)的完全访问权限。

但是,外部函数却不能访问定义在内部函数中的变量和函数。这给内部函数的变量提供了一种封装。

此外,由于内部函数可以访问外部函数的作用域,因此当内部函数生存周期大于外部函数时,外部函数中定义的变量和函数的生存周期将比内部函数执行的持续时间要长。当内部函数以某一种方式被任何一个外部函数之外的任何作用域访问时,就会创建闭包。

// 外部函数定义了一个名为“name”的变量
const pet = function (name) {const getName = function () {// 内部函数可以访问外部函数的“name”变量return name;};return getName; // 返回内部函数,从而将其暴露给外部作用域
};
const myPet = pet("Vivie");console.log(myPet()); // "Vivie"

实际上可能会比上面的代码复杂的多。它可以返回一个包含用于操作外部函数的内部变量的方法的对象。

const createPet = function (name) {let sex;const pet = {// 在这个上下文中:setName(newName) 等价于 setName: function (newName)setName(newName) {name = newName;},getName() {return name;},getSex() {return sex;},setSex(newSex) {if (typeof newSex === "string" &&(newSex.toLowerCase() === "male" || newSex.toLowerCase() === "female")) {sex = newSex;}},};return pet;
};const pet = createPet("Vivie");
console.log(pet.getName()); // Viviepet.setName("Oliver");
pet.setSex("male");
console.log(pet.getSex()); // male
console.log(pet.getName()); // Oliver

在上面的代码中,外部函数的 name 变量对内部函数来说是可访问的,而除了通过内部函数本身,没有其他任何方法可以取得内部的变量。内部函数的内部变量就像对外部参数和变量的保险柜。它们会为内部函数保留“稳定”而又“被封装”的数据参与运行。而这些内部函数甚至不会被分配给一个变量,或者有个名称。

const getCode = (function () {const apiCode = "0]Eal(eh&2"; // 我们不希望外部能够修改的代码......return function () {return apiCode;};
})();console.log(getCode()); // "0]Eal(eh&2"

备注: 使用闭包时需要注意许多陷阱!

如果一个闭包的函数定义了一个和外部的某个变量名称相同的变量,那么这个闭包将无法引用外部作用域中的这个变量。(内部作用域的变量“覆盖”外部作用域,直至程序退出内部作用域。可以将其视作命名冲突。)

const createPet = function (name) {// 外部函数定义了一个名为“name”的变量。return {setName(name) {// 闭包函数还定义了一个名为“name”的变量。name = name; // 我们如何访问外部函数定义的“name”?},};
};

使用 arguments 对象

函数的实际参数会被保存在一个类似数组的 arguments 对象中。在函数内,你可以按如下方式找出传入的参数:

arguments[i];

其中 i 是参数的序号,从 0 开始。所以第一个传入函数的参数会是 arguments[0]。参数的数量由 arguments.length 表示。

使用 arguments 对象,你可以处理比声明更多的参数来调用函数。这在你事先不知道会需要将多少参数传递给函数时十分有用。你可以用 arguments.length 来获得实际传递给函数的参数的数量,然后用 arguments 对象来访问每个参数。

例如,考虑有一个用来连接字符串的函数。唯一正式的参数是在连接后的字符串中用来分隔各个连接部分的字符。该函数定义如下:

function myConcat(separator) {let result = ""; // 初始化列表// 迭代 argumentsfor (let i = 1; i < arguments.length; i++) {result += arguments[i] + separator;}return result;
}

你可以给这个函数传递任意数量的参数,它会将各个参数连接成一个字符串“列表”:

console.log(myConcat("、", "红", "橙", "蓝"));
// "红、橙、蓝、"console.log(myConcat(";", "大象", "长颈鹿", "狮子", "猎豹"));
// "大象;长颈鹿;狮子;猎豹;"console.log(myConcat("。", "智者", "罗勒", "牛至", "胡椒", "香菜"));
// "智者。罗勒。牛至。胡椒。香菜。"

备注: arguments 变量只是“类数组”,而不是数组。它与数组类似,有索引编号和 length 属性。尽管如此,它并不具备 Array 对象的所有数组操作方法。

更多信息请阅读 JavaScript 参考中的 Function 对象。

函数参数

有两种特殊的参数语法:默认参数剩余参数

默认参数

在 JavaScript 中,函数参数的默认值是 undefined。然而,在某些情况下设置不同的默认值可能会很有用。这正是默认参数的作用。

在过去,用于设定默认参数的一般策略是在函数的主体中测试参数值是否为 undefined,如果是则赋予这个参数一个默认值。

在下面的示例中,如果调用函数时没有给 b 提供值,那么它的值就是 undefined,在执行 a*b 时,调用乘法通常会返回 NaN。但是,这已经被示例的第二行所避免了:

function multiply(a, b) {b = typeof b !== "undefined" ? b : 1;return a * b;
}console.log(multiply(5)); // 5

使用默认参数,在函数体的手动检查就不再必要了。现在,你可以在函数头简单地把 1 设定为 b 的默认值:

function multiply(a, b = 1) {return a * b;
}console.log(multiply(5)); // 5

见参考的默认参数,以获取详情。

剩余参数

剩余参数语法允许将不确定数量的参数表示为数组。

在下面的示例中,multiply 函数使用剩余参数收集从第二个参数开始到最后的参数。然后,该函数将它们与第一个参数相乘。

function multiply(multiplier, ...theArgs) {return theArgs.map((x) => multiplier * x);
}const arr = multiply(2, 1, 2, 3);
console.log(arr); // [2, 4, 6]

箭头函数

箭头函数表达式(也称胖箭头,以区分未来 JavaScript 中假设的 -> 语法)相比函数表达式具有较短的语法且没有它自己的 this、arguments、super 和 new.target。箭头函数总是匿名的。

有两个因素会影响对箭头函数的引入:更简洁的函数和 this 的无绑定性

更简洁的函数

在一些函数模式中,更简洁的函数很受欢迎。对比一下:

const a = ["Hydrogen", "Helium", "Lithium", "Beryllium"];const a2 = a.map(function (s) {return s.length;
});console.log(a2); // [8, 6, 7, 9]const a3 = a.map((s) => s.length);console.log(a3); // [8, 6, 7, 9]

无单独的 this

在箭头函数出现之前,每一个新函数都定义了自己的 this 值(在构造函数中是一个新的对象;在严格模式下是 undefined;在作为“对象方法”调用的函数中指向这个对象;等等)。事实证明,这对于面向对象的编程风格来说并不理想。

function Person() {// 构造函数 Person() 将 `this` 定义为自身。this.age = 0;setInterval(function growUp() {// 在非严格模式下,growUp() 函数将 `this` 定义为“全局对象”,// 这与 Person() 定义的 `this` 不同。this.age++;}, 1000);
}const p = new Person();

在 ECMAScript 3/5 中,通过把 this 的值赋值给一个变量可以修复这个问题。

function Person() {// 有的人习惯用 `that` 而不是 `self`。// 请选择一种方式,并保持前后代码的一致性const self = this;self.age = 0;setInterval(function growUp() {// 回调引用 `self` 变量,其值为预期的对象。self.age++;}, 1000);
}

另外,创建一个绑定函数可以使得 this 值被正确传递给 growUp() 函数。

箭头函数没有自己的 this,而是使用封闭执行上下文的 this 值。因此,在以下代码中,传递到 setInterval 中的函数内的 this 与闭包函数中的 this 相同:

function Person() {this.age = 0;setInterval(() => {this.age++; // 这里的 `this` 正确地指向 person 对象}, 1000);
}const p = new Person();

预定义函数

JavaScript 语言有几个顶级的内置函数:

eval()

eval() 方法执行方法计算以字符串表示的 JavaScript 代码。

isFinite()

isFinite() 全局函数判断传入的值是否是有限的数值。如果需要的话,其参数首先被转换为一个数值。

isNaN()

isNaN() 函数判断一个值是否是 NaN。注意:isNaN 函数内部的强制转换规则十分有趣。你也可以使用 Number.isNaN() 来判断该值是否为 NaN。

parseFloat()

parseFloat() 函数解析字符串参数,并返回一个浮点数。

parseInt()

parseInt() 函数解析字符串参数,并返回指定的基数(基础数学中的数制)的整数。

decodeURI()

decodeURI() 函数对先前经过 encodeURI 函数或者其他类似方法编码过的统一资源标志符(URI)进行解码。

decodeURIComponent()

decodeURIComponent() 方法对先前经过 encodeURIComponent 函数或者其他类似方法编码的统一资源标志符(URI)进行解码。

encodeURI()

encodeURI() 方法通过以表示字符的 UTF-8 编码的一个、两个、三个或四个转义序列替换统一资源标识符(URI)的某些字符来进行编码(对于由两个“代理(surrogate)”字符组成的字符,只会编码为四个转义序列)。

encodeURIComponent()

encodeURIComponent() 方法通过以表示字符的 UTF-8 编码的一个、两个、三个或四个转义序列替换统一资源标识符(URI)的某些字符来进行编码(对于由两个“代理”字符组成的字符,只会编码为四个转义序列)。

escape() 已弃用

escape() 方法生成一个新的字符串,其中的某些字符已被替换为十六进制转义序列。其已被弃用,请使用 encodeURI() 或 encodeURIComponent() 代替。

unescape() 已弃用

unescape() 方法计算生成一个新的字符串,其中的十六进制转义序列将被其表示的字符替换。上述的转义序列就像 escape 介绍的一样。其已被弃用,请使用 decodeURI() 或 decodeURIComponent() 替代。

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

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

相关文章

[xboard]real6410-6.1 移植kernel 5.4.272

文章目录 获取源码方法一方法二方法三了解S3C6410内核相关1 设备文件2 mach-文件3 plat-文件配置real6410编译镜像测试问题1获取源码 方法一 进入官网,如下界面,点击http, 再依次

IPV6的相关网络问题

问题 ​​​​​​​ 目录 问题 一.什么是NAT64转换 1.NAT64的工作原理 IPv6到IPv4转换 IPv4到IPv6的响应转换 2.NAT64的优点 3.NAT64的缺点 二.NAT64转换如何实现 1.工作原理 2.实现步骤 DNS查询转换&#xff08;DNS64&#xff09; 地址转换&#xff08;NAT64&a…

Ubuntu 20.04 永久修改 最大文件打开数量和最大线程数量

目录 一、查看设置 二、永久设置 三、验证测试 操作系统&#xff1a;Ubuntu 20.04.5 LTS 我们在Ubuntu 20.04系统上&#xff0c;永久修改“最大文件打开数量”open files和“最大线程数量”max user processes。 一、查看设置 查看当前用户的设置 ulimit -a open files 是…

掌握ChatGPT技巧:写作论文如虎添翼

ChatGPT无限次数:点击直达 掌握ChatGPT技巧&#xff1a;写作论文如虎添翼 引言 在当今信息爆炸的时代&#xff0c;论文写作成为每个研究者必不可少的重要技能。然而&#xff0c;有时候我们可能会遇到灵感枯竭、思路不清晰的困境。幸运的是&#xff0c;随着人工智能技术的不断…

BTI的启用与构建

BTI分支目标识别精讲与实践系列 思考 1、什么是代码重用攻击&#xff1f;什么是ROP攻击&#xff1f;区别与联系&#xff1f; 2、什么是JOP攻击&#xff1f;间接分支跳转指令&#xff1f; 3、JOP攻击的缓解技术&#xff1f;控制流完整性保护&#xff1f; 4、BTI下的JOP如何…

三行命令解决Ubuntu Linux联网问题

本博客中Ubuntu版本为23.10.1最新版本&#xff0c;后续发现了很多问题我无法解决&#xff0c;已经下载了另外一个版本22.04&#xff0c;此版本自带网络 一开始我找到官方文档描述可以通过命令行连接到 WiFi 网络&#xff1a;https://cn.linux-console.net/?p10334#google_vig…

Docker容器(六)网络配置与数据卷

一、高级网络配置 1.1概述 当 Docker 启动时&#xff0c;会自动在主机上创建一个 docker0 虚拟网桥&#xff0c;实际上是 Linux 的一个 bridge&#xff0c;可以理解为一个软件交换机。它会在挂载到它的网口之间进行转发。 同时&#xff0c;Docker 随机分配一个本地未占用的私有…

蓝桥杯历年真题值DFS

2020年分配口罩 【问题描述】 某市市长获得了若干批口罩&#xff0c;每一批口罩的数目如下&#xff1a;&#xff08;如果你把以下文字复制到文本文件中&#xff0c;请务必检查复制的内容是否与文档中的一致。在试题目录下有一个文件 mask.txt&#xff0c;内容与下面的文本相同…

使用二进制设计权限

学习笔记来源&#xff1a;https://www.bilibili.com/video/BV19h4y1A7Gq/?spm_id_from333.337.search-card.all.click&vd_sourcea0f31140205458776d3a4ef477cd6561 假如已知四个权限&#xff1a; const READ 1; const WRITE 2; const DELETE 3; const CREATE 4;而表示…

构建第一个ArkTS之基本语法概述

在初步了解了ArkTS语言之后&#xff0c;我们以一个具体的示例来说明ArkTS的基本组成。如下图所示&#xff0c;当开发者点击按钮时&#xff0c;文本内容从“Hello World”变为“Hello ArkUI”。 图1 示例效果图 本示例中&#xff0c;ArkTS的基本组成如下所示。 图2 ArkTS的基本…

计算机网络技术-电路交换、报文交换和分组交换的介绍+区别

目录 电路交换报文交换分组交换待续、更新中 电路交换 电路交换是由交换机负责在两个通信站点之间建立一条物理专用线路。 报文交换 报文交换是以报文为单位进行存储交换的技术&#xff0c;指的是一次通信的全部数据(报文)按存储转发的方式实现传输。 分组交换 分组交换方…

C++ 封装

1.封装 cpp认为万事万物都可以封装 封装将属性和行为作为一个整体&#xff0c;表现生活中的事物。 将属性和行为加以权限控制。 语法&#xff1a; class 类名{ 访问权限: 属性或者行为 } //学生类 class Student { public:void setName(string name) {m_name name;}vo…

人工智能技术创业机会有哪些?

&#x1f482; 个人主页: 同学来啦&#x1f91f; 版权: 本文由【同学来啦】原创、在CSDN首发、需要转载请联系博主 &#x1f4ac; 如果文章对你有帮助&#xff0c;欢迎关注、点赞、收藏和订阅专栏哦 文章目录 &#x1f96d; 一、城市治理&#x1f34e; 二、社交创新&#x1f3…

如何申请苹果个人开发者账户

1、苹果手机下载Developer APP&#xff0c;登录后&#xff0c;账户-注册-支付688 2、查看邮箱&#xff0c;会有邮件提醒上传身份证正反面&#xff0c;上传成功后会有邮件回复 3、审核时间为2天&#xff0c;如果没回复&#xff0c;及时联系客服&#xff0c;秒回复 https://de…

分享快速搭建鸿蒙应用的几种方式

鸿蒙今年快速发展&#xff0c;特别是不再兼容安卓&#xff0c;鸿蒙原生应用成为大家关注的重点。今天分享几个如何实现快速开发鸿蒙App的方法。 鸿蒙开发有多种开发模式&#xff1a;一种是使用ArkTS声明式&#xff1b;如果这种感觉还需要花时间学习的话&#xff0c;那么另一种…

为什么越来越多FP商家做独立站?独立站有什么吸引力?

如果你经常关注跨境电商领域&#xff0c;就会发现&#xff0c;近几年来越来越多的FP商家不再依赖第三方平台&#xff0c;而是自己做起了独立站。这是因为随着第三方平台的限制越来越多&#xff0c;FP商家的销售也越来越困难&#xff0c;例如经营成本上升、推广流量减少、甚至被…

离了个大谱 , 虚拟机莫名其妙的虚拟机网卡驱动启动不了,日志显示:failed

今天用xshell连接虚拟机时死活连不上&#xff0c;检查来检查去都没问题&#xff0c;结果居然是.... 1. 使用检查network.service 状态时&#xff1a; network.service - LSB: Bring up/down networkingLoaded: loaded (/etc/rc.d/init.d/network)Active: failed (Result: exit…

如何将数据(通常是张量)和模型转移到CUDA设备(即GPU)上

在PyTorch中&#xff0c;将模型和数据移到GPU上进行加速计算是深度学习训练过程中的一个常见步骤。这里将介绍如何将数据&#xff08;通常是张量&#xff09;和模型转移到CUDA设备&#xff08;即GPU&#xff09;上。 将模型转移到CUDA 对于PyTorch模型&#xff0c;你可以使用…

MySQL分库分表的方式有哪些

目录 一、为什么要分库分表 二、什么是分库分表 三、分库分表的几种方式 1.垂直拆分 2. 水平拆分 四、分库分表带来的问题 五、分库分表技术如何选型 一、为什么要分库分表 如果一个网站业务快速发展&#xff0c;那这个网站流量也会增加&#xff0c;数据的压力也会随之而…

【域适应】基于散度成分分析(SCA)的四分类任务典型方法实现

关于 SCA&#xff08;scatter component analysis&#xff09;是基于一种简单的几何测量&#xff0c;即分散&#xff0c;它在再现内核希尔伯特空间上进行操作。 SCA找到一种在最大化类的可分离性、最小化域之间的不匹配和最大化数据的可分离性之间进行权衡的表示&#xff1b;每…