JavaScript函数的使用
前言
程序中的foo、bar、baz
在学习编程的过程中,你可能会经常看到foo、bar、baz这些名词:
- 它们通常被用来作为函数、变量、文件的
名词; - 目前已经编程了计算机编程的术语一部分;
- 但是它们本身并
没有特别的用途和意义; - 常被称之为
伪变量(metasyntactic variable)
那么它们有什么由来吗?
- 事实上,foo、bar这些名词最早从什么时候、地方流行起来的一直是由争论的;
- 一种说法是通过Digital(迪吉多,数字设备公司,成立于1957年的美国电脑公司)的手册说明流行起来的;
- 一种说法是说源自于电子学中的
反转foo信号; - 也有一种说法是foo因为出现在了一个漫画中,漫画中foo代表“好运”,与中文的福读音类似;
总之,foo、bar、baz已经是编程领域非常常用的名词。
- 我个人也比较习惯在写一些变量、函数名词时使用这些词汇,大家做一个了解;
一、认识函数
1.函数的定义
-
函数其实就是
某段代码的封装,这段代码帮助我们完成某一个功能; -
默认情况下JavaScript引擎或者浏览器会给我们提供一些已经实现好的函数;
-
我们也可以编写
属于自己的函数;
在开发程序时,使用函数可以提高编写的效率以及代码的重用;
2.函数的声明
JavaScript 有三种声明函数的方法。
2.1 function 命令
function命令声明的代码区块,就是一个函数。
function print(s) {console.log(s);
}
上面的代码命名了一个print函数,以后使用print()这种形式,就可以调用相应的代码。这叫做函数的声明(Function Declaration)
2.2 函数表达式
除了用function命令声明函数,还可以采用变量赋值的写法。
var print = function (s) {console.log(s);
};
这种写法将一个匿名函数赋值给变量。这时,这个匿名函数又称函数表达式(Function Expression),因为赋值语句的等号右侧只能放表达式。
采用函数表达式声明函数时,function命令后面不带有函数名。如果加上函数名,该函数名只在函数体内部有效,在函数体外部无效。
var print = function x(){console.log(typeof x);
};x
// ReferenceError: x is not definedprint()
// function
这种写法的用处有两个,一是可以在函数体内部调用自身,二是方便除错(除错工具显示函数调用栈时,将显示函数名,而不再显示这里是一个匿名函数)。因此,下面的形式声明函数也非常常见。
var f = function f() {};
2.3 Function 构造函数
第三种声明函数的方式是Function构造函数。
var add = new Function('x','y','return x + y'
);// 等同于
function add(x, y) {return x + y;
}
你可以传递任意数量的参数给Function构造函数,只有最后一个参数会被当做函数体,如果只有一个参数,该参数就是函数体。
var foo = new Function('return "hello world";'
);// 等同于
function foo() {return 'hello world';
}
Function构造函数可以不使用new命令,返回结果完全一样。
总的来说,这种声明函数的方式非常不直观,几乎无人使用。
3.函数的重复声明
如果同一个函数被多次声明,后面的声明就会覆盖前面的声明。
function f() {console.log(1);
}
f() // 2function f() {console.log(2);
}
f() // 2
4.函数的调用
调用函数时,要使用圆括号运算符。圆括号之中,可以加入函数的参数。
function add(x, y) {return x + y;
}add(1, 1) // 2
上面代码中,函数名后面紧跟一对圆括号,就会调用这个函数。
5.return语句
函数体内部的return语句,表示返回。JavaScript 引擎遇到return语句,就直接返回return后面的那个表达式的值,后面即使还有语句,也不会得到执行。也就是说,return语句所带的那个表达式,就是函数的返回值。return语句不是必需的,如果没有的话,该函数就不返回任何值,或者说返回undefined。
function foo() {console.log(123);
}
var result1 = foo();
console.log(result1);//undefined
6.递归
函数可以调用自身,这就是递归(recursion)。下面就是通过递归,计算斐波那契数列的代码。
function fib(num) {if (num === 0) return 0;if (num === 1) return 1;return fib(num - 2) + fib(num - 1);
}fib(6) // 8
二、函数的特性
1.头等公民
JavaScript 语言将函数看作一种值,与其它值(数值、字符串、布尔值等等)地位相同。
凡是可以使用值的地方,就能使用函数。比如,可以把函数赋值给变量和对象的属性,也可以当作参数传入其他函数,或者作为函数的结果返回。函数只是一个可以执行的值,此外并无特殊之处。
由于函数与其他数据类型地位平等,所以在 JavaScript 语言中又称函数为第一等公民。
通常我们对将函数作为头等公民的编程方式,称之为
函数式编程
function add(x, y) {return x + y;
}// 将函数赋值给一个变量
var operator = add;// 将函数作为参数和返回值
function a(op){return op;
}
a(add)(1, 1)
// 2
2.函数名的提升
JavaScript 引擎将函数名视同变量名,所以采用function命令声明函数时,整个函数会像变量声明一样,被提升到代码头部。所以,下面的代码不会报错。
f();function f() {}
表面上,上面代码好像在声明之前就调用了函数f。但是实际上,由于“变量提升”,函数f被提升到了代码头部,也就是在调用之前已经声明了。
不过这种特性只针对function命令的声明方式有效,函数表达式没有这个特性
foo();
// TypeError: undefined is not a functionvar foo = function foo() {}
上面的代码等同于下面的形式
var f;
f();
f = function () {};
上面代码第二行,调用f的时候,f只是被声明了,还没有被赋值,等于undefined,所以会报错。
注意,如果像下面例子那样,采用function命令和var赋值语句声明同一个函数,由于存在函数提升,最后会采用var赋值语句的定义。
var f = function () {console.log('1');
}function f() {console.log('2');
}f() // 1
三、函数的属性和方法
1.name属性
函数的name属性返回函数的名字。
function f1() {}
f1.name // "f1"
如果是通过变量赋值定义的函数,那么name属性返回变量名。
var f2 = function () {};
f2.name // "f2"
如果变量的值是一个具名函数,那么name属性返回function关键字之后的那个函数名。
var f3 = function myName() {};
f3.name // 'myName'
name属性始终显示函数第一个赋值的变量名
var f1 = function f2() {}function printFnName(fn) {console.log(fn.name);
}
printFnName();//f2
2.length 属性
函数的length属性返回函数预期传入的参数个数,即函数定义之中的参数个数。
function f(a, b) {}
f.length // 2
上面代码定义了空函数f,它的length属性就是定义时的参数个数。不管调用时输入了多少个参数,length属性始终等于2。
length属性提供了一种机制,判断定义时和调用时参数的差异,以便实现面向对象编程的“方法重载”(overload)。
3.toString()
函数的toString()方法返回一个字符串,内容是函数的源码。
function f() {a();b();c();
}f.toString()
// function f() {
// a();
// b();
// c();
// }
对于那些原生的函数,toString()方法返回function (){[native code]}。
Math.sqrt.toString()
// "function sqrt() { [native code] }"
函数内部的注释也可以返回。
function f() {/*这是一个多行注释
*/}f.toString()
// "function f(){/*
// 这是一个
// 多行注释
// */}"
利用这一点,可以变相实现多行字符串。
var multiline = function (fn) {var arr = fn.toString().split('\n');return arr.slice(1, arr.length - 1).join('\n');
};function f() {/*这是一个多行注释
*/}multiline(f);
// " 这是一个
// 多行注释"
四、函数的参数
1.概述
函数运行的时候,有时需要提供外部数据,不同的外部数据会得到不同的结果,这种外部数据就叫参数。
function foo(x, y) {return x + y;
}
foo(1, 2);
- 形参(参数 parameter):
定义函数时,小括号中的参数,是用来接收参数用的,在函数内部作为变量使用 - 实参(参数 argument):
调用函数时,小括号中的参数,是用来把数据传递到函数内部用的
2.参数的省略
函数参数不是必需的,JavaScript 允许省略参数。
function f(a, b) {return a;
}f(1, 2, 3) // 1
f(1) // 1
f() // undefinedf.length // 2
需要注意的是,函数的length属性与实际传入的参数个数无关,只反映函数预期传入的参数个数。
但是,没有办法只省略靠前的参数,而保留靠后的参数。如果一定要省略靠前的参数,只有显式传入undefined。
function f(a, b) {return a;
}f( , 1) // SyntaxError: Unexpected token ,(…)
f(undefined, 1) // undefined
3.传递方式
函数参数如果是原始类型的值(数值、字符串、布尔值),传递方式是值传递(passes by value)。
var p = 2;function f(p) {p = 3;
}
f(p);p // 2
如果函数参数是复合类型的值(数组、对象、其他函数),传递方式是引用传递(pass by reference)。
var obj = { p: 1 };function f(o) {o.p = 2;
}
f(obj);obj.p // 2
4.arguments 对象
4.1 定义
由于 JavaScript 允许函数有不定数目的参数,所以需要一种机制,可以在函数体内部读取所有参数。这就是arguments对象的由来。
在ES6的箭头函数中,已经将这个参数移除。用新增的可变参数写法替代了arguments
arguments对象包含了函数运行时的所有参数,arguments[0]就是第一个参数,arguments[1]就是第二个参数,以此类推。这个对象只有在函数体内部,才可以使用。
var f = function (one) {console.log(arguments[0]);console.log(arguments[1]);console.log(arguments[2]);
}f(1, 2, 3)
// 1
// 2
// 3
正常模式下,arguments对象可以在运行时修改。
var f = function(a, b) {arguments[0] = 3;arguments[1] = 2;return a + b;
}f(1, 1) // 5
严格模式下,arguments对象与函数参数不具有联动关系,不会影响到实际的函数参数。
var f = function(a, b) {'use strict'; // 开启严格模式arguments[0] = 3;arguments[1] = 2;return a + b;
}f(1, 1) // 2
通过arguments对象的length属性,可以判断函数调用时到底带几个参数。
function f() {return arguments.length;
}f(1, 2, 3) // 3
f(1) // 1
f() // 0
4.2 与数组的关系
需要注意的是,虽然arguments很像数组,但它是一个对象。数组专有的方法(比如slice和forEach),不能在arguments对象上直接使用。
如果要让arguments对象使用数组方法,真正的解决方法是将arguments转为真正的数组。下面是三种常用的转换方法:slice方法和逐一填入新数组。
// 方式一
var args = Array.prototype.slice.call(arguments);// 方式二
var args = [];
for (var i = 0; i < arguments.length; i++) {args.push(arguments[i]);
}// 方式三
var args = Array.from(arguments);
4.3 callee 属性
arguments对象带有一个callee属性,返回它所对应的原函数。
var f = function () {console.log(arguments.callee === f);
}f() // true
可以通过arguments.callee,达到调用函数自身的目的。这个属性在严格模式里面是禁用的,因此不建议使用。
5.同名参数
如果有同名的参数,则取最后出现的那个值。
function f(a, a) {console.log(a);
}f(1, 2) // 2
调用函数f()的时候,没有提供第二个参数,a的取值就变成了undefined。这时,如果要获得第一个a的值,可以使用arguments对象。
function f(a, a) {console.log(arguments[0]);//1console.log(a);//undefined
}f(1) // 1
五、函数作用域
1.定义
作用域(scope)指的是变量存在的范围。在 ES5 的规范中,JavaScript 只有两种作用域:一种是全局作用域,变量在整个程序中一直存在,所有地方都可以读取;另一种是函数作用域,变量只在函数内部存在。
对于顶层函数来说,函数外部声明的变量就是全局变量(global variable),它可以在函数内部读取。
var v = 1;function f() {console.log(v);
}f()
// 1
在函数内部定义的变量,外部无法读取,称为“局部变量”(local variable)。
function f(){var v = 1;
}v // ReferenceError: v is not defined
函数内部定义的变量,会在该作用域内覆盖同名全局变量。
var v = 1;function f(){var v = 2;console.log(v);
}f() // 2
v // 1
对于
var命令来说,局部变量只能在函数内部声明,在其他区块中声明,一律都是全局变量。
var x = 1;
if (x = 1) {var a = 10;
}
console.log(a);//undefined
2.函数变量的提升
与全局作用域一样,函数作用域内部也会产生“变量提升”现象。var命令声明的变量,不管在什么位置,变量声明都会被提升到函数体的头部。
function foo(x) {if (x > 100) {var tmp = x - 100;}
}// 等同于
function foo(x) {var tmp;if (x > 100) {tmp = x - 100;};
}
3.函数本身的作用域
函数本身也是一个值,也有自己的作用域。它的作用域与变量一样,就是其声明时所在的作用域,与其运行时所在的作用域无关。
var a = 1;
var x = function () {console.log(a);
};function f() {var a = 2;x();
}f() // 1
函数执行时所在的作用域,是定义时的作用域,而不是调用时所在的作用域。
函数体内部声明的函数,作用域绑定函数体内部。
function foo() {var x = 1;function bar() {console.log(x);}return bar;
}var x = 2;
var f = foo();
f() // 1
上面代码中,函数foo内部声明了一个函数bar,bar的作用域绑定foo。当我们在foo外部取出bar执行时,变量x指向的是foo内部的x,而不是foo外部的x。正是这种机制,构成了下文要讲解的“闭包”现象。
六、函数的其他知识点
1.立即调用的函数表达式(IIFE)
根据 JavaScript 的语法,圆括号()跟在函数名之后,表示调用该函数。比如,print()就表示调用print函数。
有时,我们需要在定义函数之后,立即调用该函数。这时,你不能在函数的定义之后加上圆括号,这会产生语法错误。
function(){ /* code */ }();
// SyntaxError: Unexpected token (
产生这个错误的原因是,function这个关键字既可以当作语句,也可以当作表达式。
// 语句
function f() {}// 表达式
var f = function f() {}
当作表达式时,函数可以定义后直接加圆括号调用。
var f = function f(){ return 1}();
f // 1
为了避免解析的歧义,JavaScript 规定,如果function关键字出现在行首,一律解释成语句。因此,引擎看到行首是function关键字之后,认为这一段都是函数的定义,不应该以圆括号结尾,所以就报错了。
函数定义后立即调用的解决方法,就是不要让function出现在行首,让引擎将其理解成一个表达式。最简单的处理,就是将其放在一个圆括号里面。
(function(){ /* code */ }());
// 或者
(function(){ /* code */ })();
上面两种写法都是以圆括号开头,引擎就会认为后面跟的是一个表达式,而不是函数定义语句,所以就避免了错误。
举一反三,任何让解释器以表达式来处理函数定义的方法,都能产生同样的效果,比如下面三种写法。
var i = function(){ return 10; }();
true && function(){ /* code */ }();
0, function(){ /* code */ }();
甚至可以这样写
!function () { /* code */ }();
~function () { /* code */ }();
-function () { /* code */ }();
+function () { /* code */ }();
通常情况下,只对
匿名函数使用这种“立即执行的函数表达式”。
作用:
- 不必为函数命名,避免了
污染全局变量; - IIFE 内部形成了一个单独的
作用域,可以封装一些外部无法读取的私有变量。
// 写法一
var tmp = newData;
processData(tmp);
storeData(tmp);// 写法二
(function () {var tmp = newData;processData(tmp);storeData(tmp);
}());
上面代码中,写法二比写法一更好,因为完全避免了污染全局变量。
2.闭包
闭包(closure)是 JavaScript 语言的一个难点,也是它的特色,很多高级应用都要依靠闭包实现。
这里将闭包放到 javascript高级 进行讲解,详情请看:
相关文章:
JavaScript函数的使用
前言 程序中的foo、bar、baz 在学习编程的过程中,你可能会经常看到foo、bar、baz这些名词: 它们通常被用来作为函数、变量、文件的名词;目前已经编程了计算机编程的术语一部分;但是它们本身并没有特别的用途和意义;…...
【算法】Java-使用数组模拟单向链表,双向链表
目录 试题1:实现一个单链表,并实现以下功能: 试题2:实现一个双链表,并实现以下功能 思路总结: 什么情况下可能涉及到用数组实现链表呢? 在学习时了解到了可以用数组模拟链表,使其…...
Nessus简单介绍与安装
Nessus简单介绍与安装 1.Nessus简介 Nessus号称是世界上最流行的漏洞扫描程序,全世界有超过75000个组织在使用它。该工具提供完整的电脑漏洞扫描服务,并随时更新其漏洞数据库。Nessus不同于传统的漏洞扫描软件,Nessus可同时在本机或远端上遥…...
【每天一道算法题】day2-认识时间复杂度
认识时间复杂度: O:读作big O,在数学上指的是上限的意思 常数时间的操作 一个操作如果和样本的数据量没有关系,每次都是固定时间内完成的操作,叫做常数操作。时间复杂度为一个算法流程中,常数操作数量的一…...
前端报错合集
error Component name “index“ should always be multi-word vue/multi-word-component-names 的解决办法 原因组件命名是 没有采用驼峰 error Component name “index“ should always be multi-word vue/multi-word-component-names 的解决办法_error component name &qu…...
Milvus以及Web UI 安装
向量数据库懂的都懂 版本数据 [rootiZ7xv7q4im4c48qen2do2bZ project]# cat /etc/redhat-release CentOS Stream release 9 [rootiZ7xv7q4im4c48qen2do2bZ project]# docker version Client: Docker Engine - CommunityVersion: 24.0.5API version: 1.43Go v…...
Go for循环中的defer
背景 写个后台程序,定时抓取服务器指标,代码逻辑如下,使用一段时间后内存不断增加 func CollectInfo() {for {// 获取服务器信息代码// ...............resp, err : http.Post("http://server", "application/json", str…...
创建开机自启的脚本
在启动许多ros节点时有多种方式,我推荐使用launch来启动所有的节点,这也是一种规范的方式。以后会慢慢向这个方向靠。 除此之外还可以通过创建的脚本来启动: 脚本位置不限,只需要: sudo gedit xxx.sh在里面添加相应的…...
学生信息系统(python实现)
#codingutf-8 import os.path filenamestudent.txtdef menm():#菜单界面print(学生管理系统)print(-----------------------------功能菜单-----------------------------)print(\t\t\t\t\t\t1.录入学生信息)print(\t\t\t\t\t\t2.查找学生信息)print(\t\t\t\t\t\t3.删除学生信息…...
管理类联考——数学——汇总篇——知识点突破——数据分析——1. 计数原理——排列组合——公式
排列组合 排列与组合的推导: 从n个不同的元素中取出m(m≤n)个元素做排列为 A n m A_n^m An...
C#,《小白学程序》第十六课:随机数(Random)第三,正态分布的随机数的计算方法与代码
1 随机数的问题 用 C# Random 类生成的随机数是平均分布的。也就是各数据段的出现的次数差不多。彩票号码属于这种随机数。 而很多很多常见的随机数,比如:成绩,却是符合正态分布的。 因而很多时候需要生成符合正态分布规律的随机数。 2 文…...
一文读懂java变量类型
前言 在学习和使用Java编程语言时,理解变量类型是至关重要的基础知识。Java是一种静态类型语言,强调变量必须先声明其类型,才能进行后续操作。因此,对于初学者来说,了解Java中不同的变量类型及其特性是迈向编程成功的…...
解决windows下git操作提示用户名密码错误的问题
当代码从一个平台切换到另一个平台的时候,需要做两步操作,第一步就是更新git的仓库地址,在项目的.git/config文件里面修改,这一步做完之后,就可以推送代码到新的仓库了,这里就是重点来了。 一般第一次推动代…...
ESP32开发:Clion配置IDF
IDF环境搭建 使用安装包安装IDF 可以通过安装包进行安装,如下图: 下载链接如下:https://dl.espressif.cn/dl/esp-idf/?idf4.4 安装好后,IDF会添加环境变量IDF_TOOLS_PATH,如果要安装多个IDF,为了防止冲…...
伦敦金的走势高低的规律
伦敦金市场是一个流动性很强的市场,其价格走势会在诸多因素的影响下,出现反复的上下波动,如果投资者能够在这些高低走势中找到一定的规律,在相对有利的时机入场和离场,就能够通过不断的交易,累积大量的财富…...
【C#-1】C#调用matlab生成的dll库
matlab打包dll 1、matlab示例程序: function untitled4(x)z peaks(x);figuresurf(z) end 2、输入deploytool打包matlab程序,具体如下: 3、拷贝 打包成功后,将生成for_redistribution_files_only文件夹中的dll文件拷贝到C#程序…...
MATLAB中pdist和pdist2的区别
一、pdist 和 pdist2 是MATLAB中用于计算距离矩阵的两个不同函数,它们的区别在于输入和输出以及一些计算选项。 pdist: pdist函数用于计算一组点之间的距离。 输入:通常接受一个矩阵,矩阵的每一行代表一个数据点,矩阵的列代表数据…...
直播平台源码开发搭建APP的DASH协议:流媒体技术其中一环
在直播平台源码APP中,有着许许多多、多种多样的功能,比如短视频功能,帮助我们去获取信息,看到全世界用户身边发生的事情或是他们的生活;又比如直播功能,为用户提供了实时的娱乐享受,还让一些用户…...
【前端】js解码base64
【前端】js解码base64 //不会乱码 function strTob(base64) {// 对base64转编码var decode atob(base64)decode escape(decode)// 编码转字符串var str decodeURIComponent(decode)return str } atob 中文乱码的解决方案 decode escape(decode) // 编码转字符串 v…...
Apipost:API开发者的协同工作神器
在当今快速发展的数字化时代,API已成为企业与开发者实现数据互通、应用集成的重要桥梁。然而,随着API数量的不断增加,API开发、调试、测试、文档等工作也变得越来越复杂。为了解决这一痛点,一款名为Apipost的API协同研发工具应运而…...
LBE-LEX系列工业语音播放器|预警播报器|喇叭蜂鸣器的上位机配置操作说明
LBE-LEX系列工业语音播放器|预警播报器|喇叭蜂鸣器专为工业环境精心打造,完美适配AGV和无人叉车。同时,集成以太网与语音合成技术,为各类高级系统(如MES、调度系统、库位管理、立库等)提供高效便捷的语音交互体验。 L…...
抖音增长新引擎:品融电商,一站式全案代运营领跑者
抖音增长新引擎:品融电商,一站式全案代运营领跑者 在抖音这个日活超7亿的流量汪洋中,品牌如何破浪前行?自建团队成本高、效果难控;碎片化运营又难成合力——这正是许多企业面临的增长困局。品融电商以「抖音全案代运营…...
在四层代理中还原真实客户端ngx_stream_realip_module
一、模块原理与价值 PROXY Protocol 回溯 第三方负载均衡(如 HAProxy、AWS NLB、阿里 SLB)发起上游连接时,将真实客户端 IP/Port 写入 PROXY Protocol v1/v2 头。Stream 层接收到头部后,ngx_stream_realip_module 从中提取原始信息…...
拉力测试cuda pytorch 把 4070显卡拉满
import torch import timedef stress_test_gpu(matrix_size16384, duration300):"""对GPU进行压力测试,通过持续的矩阵乘法来最大化GPU利用率参数:matrix_size: 矩阵维度大小,增大可提高计算复杂度duration: 测试持续时间(秒&…...
Maven 概述、安装、配置、仓库、私服详解
目录 1、Maven 概述 1.1 Maven 的定义 1.2 Maven 解决的问题 1.3 Maven 的核心特性与优势 2、Maven 安装 2.1 下载 Maven 2.2 安装配置 Maven 2.3 测试安装 2.4 修改 Maven 本地仓库的默认路径 3、Maven 配置 3.1 配置本地仓库 3.2 配置 JDK 3.3 IDEA 配置本地 Ma…...
Android第十三次面试总结(四大 组件基础)
Activity生命周期和四大启动模式详解 一、Activity 生命周期 Activity 的生命周期由一系列回调方法组成,用于管理其创建、可见性、焦点和销毁过程。以下是核心方法及其调用时机: onCreate() 调用时机:Activity 首次创建时调用。…...
sipsak:SIP瑞士军刀!全参数详细教程!Kali Linux教程!
简介 sipsak 是一个面向会话初始协议 (SIP) 应用程序开发人员和管理员的小型命令行工具。它可以用于对 SIP 应用程序和设备进行一些简单的测试。 sipsak 是一款 SIP 压力和诊断实用程序。它通过 sip-uri 向服务器发送 SIP 请求,并检查收到的响应。它以以下模式之一…...
在Ubuntu24上采用Wine打开SourceInsight
1. 安装wine sudo apt install wine 2. 安装32位库支持,SourceInsight是32位程序 sudo dpkg --add-architecture i386 sudo apt update sudo apt install wine32:i386 3. 验证安装 wine --version 4. 安装必要的字体和库(解决显示问题) sudo apt install fonts-wqy…...
Python 实现 Web 静态服务器(HTTP 协议)
目录 一、在本地启动 HTTP 服务器1. Windows 下安装 node.js1)下载安装包2)配置环境变量3)安装镜像4)node.js 的常用命令 2. 安装 http-server 服务3. 使用 http-server 开启服务1)使用 http-server2)详解 …...
基于鸿蒙(HarmonyOS5)的打车小程序
1. 开发环境准备 安装DevEco Studio (鸿蒙官方IDE)配置HarmonyOS SDK申请开发者账号和必要的API密钥 2. 项目结构设计 ├── entry │ ├── src │ │ ├── main │ │ │ ├── ets │ │ │ │ ├── pages │ │ │ │ │ ├── H…...
