JavaScript 开发人员的 Solidity 基础知识(第一部分)

2025-05-27

JavaScript 开发人员的 Solidity 基础知识(第一部分)

随着 NFT 的热潮兴起,我恰好接到了撰写一篇关于 NFT 和无服务器的文章的任务。因此,过去三周,我深入研究了有关代币和智能合约的书籍、课程和视频。

这是一个令人兴奋的话题,我认为尽管代币经济存在缺点,但它可以成为互联网的下一步,成为我们目前面临的许多问题的解决方案。

但在这篇博文中,我不会深入探讨我的观点,也不会教你一些东西。我会解释一下用 Solidity 编写的智能合约,以及 JavaScript 的等效代码,以便更清晰地理解这些语言之间的一些主要区别。我不会在这里深入探讨;我想解释一下基础知识。

静态类型与动态类型

JavaScript 和 Solidity 之间的主要区别在于类型。Solidity 在构建时是静态类型的,而 JavaScript 是动态类型的。

原因在于,以太坊虚拟机(EVM)对计算和存储成本非常挑剔。所有费用都必须考虑在内,这样才能相应地收取费用。

JavaScript 的目标是更加易于使用。

JavaScript

let x = 10;
Enter fullscreen mode Exit fullscreen mode

Solidity

int256 x = 10;
Enter fullscreen mode Exit fullscreen mode

因此,Solidity 在这方面有点像 Java 或 C。

您还必须输入函数参数和返回值。

JavaScript

function f(a, b) {
  return a + b;
} 
Enter fullscreen mode Exit fullscreen mode

Solidity

function f(int256 a, int256 b) returns (int256) {
  return a + b;
}
Enter fullscreen mode Exit fullscreen mode

如果您有更复杂的类型,如数组或结构体,则类型系统要求您定义数据所在的内存位置。

JavaScript

function f(a, b) {
  let c = [];

  for(let i = 0; i < a.length; i++) {
    c[i] += a[i] + b;
  }

  return c;
}
Enter fullscreen mode Exit fullscreen mode

Solidity

function f(int256[] calldata a, int256 b) returns (int256[] memory) {
  int256[] memory c;

  for(uint i = 0; i < a.length; i++) {
    c[i] = a[i] + b;
  }

  return c;
}
Enter fullscreen mode Exit fullscreen mode

这里我将第一个参数定义a为一个数组,int256并表示它应该存储在该calldata位置。calldata它不是持久的,不能被修改,而且我a在函数中只读取它而从不写入它。

其他变量要么明确存储在该memory位置,要么具有不需要定义位置的基本类型。

整数与数字

两种语言之间的另一个根本区别是它们的默认数字类型。JavaScript 使用number,它始终是浮点数。Solidity 使用各种大小的int

其背后的想法是,Solidity 的核心是支付,如果你拥有一种每单位价值数千美元的货币,那么出现舍入误差的代价可能会很高,而这在 JavaScript 类型中是常态number

这有点像使用美元并使用 1234 美分作为存储类型,而不是 12,34 美元。

此外,Solidity 程序员喜欢将int256类型作为默认类型,而无法将其 1:1 映射到 JavaScript 的number。幸运的是,JavaScipt 不久前新增了一种名为 的数字类型BigInt,它可以毫无问题地存储所有 Solidity 数字。

JavaScript

let x = 9999999999999999;
// will become 10,000,000,000,000,000
// because the number type can't store that big numbers reliably

let y = 9999999999999999n;
// will become 9,999,999,999,999,999
// because the n at the end tells JS that this is a BigInt and not a number
Enter fullscreen mode Exit fullscreen mode

Solidity

int256 x = 9999999999999999;
Enter fullscreen mode Exit fullscreen mode

合同与等级

Solidity 的合约与 JavaScript 的类类似,但又有所不同。这些合约正是 Solidity 应用程序被称为智能合约的原因。

Solidity 有点像 Java,因为合约是 Solidity 应用程序的入口点。合约看起来像 JavaScript 中的类,但区别在于实例的创建方式。

在 JavaScript 中,从类创建对象相对简单。只需使用new关键字加上类名即可。

合约也可以这样做。new在合约名称中使用关键字也会将新实例部署到区块链上。

JavaScript

class MyClass {
  #value = 10;
  setValue(x) {
    this.#value = x;
  }
}
Enter fullscreen mode Exit fullscreen mode

Solidity

contract MyContract {
  int256 private value = 10;
  function setValue(int256 x) external {
    value = x;
  }
}
Enter fullscreen mode Exit fullscreen mode

如你所见,this在契约方法中是隐含的。因此,契约的属性在所有方法中始终处于作用域内。

合约实例、对象及其数据存在于区块链上,而不仅仅是在 Solidity 应用程序内存中。

当您将合约部署到以太坊区块链时,您实际上是在实例化该合约,然后您可以从其他合约或区块链客户端(如 Ethers.js)调用它。

合约会获得一个地址,稍后您可以使用该地址与其进行交互。如果您多次部署合约,则您将拥有多个地址来与不同的实例进行交互。

JavaScript

let x = new MyClass();
x.setValue(3);
Enter fullscreen mode Exit fullscreen mode

Solidity

MyContract x = new MyContract(); // creates a new instance
x.setValue(3);

MyContract x = MyContract(contractAddress); // uses an existing instace
x.setValue();
Enter fullscreen mode Exit fullscreen mode

在 JavaScript 中,如果关闭应用程序,则创建的对象就完成了;在 Solidity 中,合约实例在区块链上是持久的。

接口

您需要合约代码才能使用已部署的合约,但这些合约并非始终可用。因此,Solidity 还提供了接口,您可以在加载现有合约时定义并使用这些接口作为类型。

Solidity

interface MyInterface  {
  function setValue(int256 x) external;
}

...

MyInterface x = MyInterface(contractAddress); // uses an existing instace
x.setValue();
Enter fullscreen mode Exit fullscreen mode

合约有许多标准化接口。例如,同质化代币和非同质化代币都是标准化的,这意味着我们可以查阅标准,复制所需的函数签名,并创建一个接口在合约中调用它们。像OpenZeppelin这样的项目也为我们提供了包含这些常用接口的库;我们无需自行创建。

用于包管理的 NPM

Solidity 使用我们已经从 JavaScript 中了解的 NPM 包管理器;这样,我们可以重用许多我们已经拥有的技能。

使用以下命令,我们将获得一个包含所有现有接口的库:

$ npm i @openzeppelin/contracts
Enter fullscreen mode Exit fullscreen mode

全局变量和payable

每个函数中都有一些隐藏的全局变量。就像windowJavaScript 中的对象一样,Solidity 中也有一个msg对象,其中包含函数调用者的数据。

下面是 JavaScript 中的一个示例,它将数据从全局window对象加载到类的私有属性中。

JavaScript

class MyClass {
  #title = null;

  constructor() {
    this.#title = window.document.title;
  }
}
Enter fullscreen mode Exit fullscreen mode

与 Solidity 相同,但这次,合约所有者将从全局变量中设置msg

Solidity

contract MyContract {
  address paybale public owner;

  constructor() payable {
    owner = payable(msg.sender);
  }
}
Enter fullscreen mode Exit fullscreen mode

msg变量包含有关消息发送者的信息。在本例中,发送者是用于部署合约的地址。

constructor当创建合约的新实例时,会自动调用此方法,只需使用 JavaScript 中类的新对象即可。由于需要有人创建该实例,因此他们的区块链地址最终会存储在msg.sender变量中。

在示例中,所有这些函数和变量都定义为payable,这意味着调用者可以向它们发送以太币。

这真是太棒了,因为它让我们能够在语言层面上为整个以太坊生态系统标准化的 Solidity 应用程序使用支付功能。JavaScript 中没有类似的功能;我们必须自己编写程序。

概括

Solidity 是一种简单的语言,其内置的支付机制可能是长期推动其发展的杀手级功能。

JavaScript 开发者应该非常熟悉大部分语法,并且少数存在的差异也能相对快速地掌握。此外,该生态系统还使用了 NPM,这对于 JavaScript 开发者来说更​​加有利。

本指南并非详尽无遗,仅涉及我所了解的一些基础知识。我并非 Solidity 的专家,因为我只使用了大约三个星期。

如果您对该方向的更多内容感兴趣,请告诉我!

另外,如果我有什么错误的话请告诉我:D

文章来源:https://dev.to/fllstck/solidity-basics-for-javascript-devs-57c
PREV
什么时候是成为开发人员的最佳时机?
NEXT
从前端到全栈!“云原生”是什么意思?这对全栈开发意味着什么?无服务器云:从前端到全栈的最短路径 想成为全栈开发者?那就去无服务器吧!