---
title: SJS 语法参考
summary: "介绍 SJS 脚本语言的语法规则，包括模块导出、变量、运算符、语句及数据类型等。"
questions:
  - SJS 是什么，它与普通 JavaScript 有什么区别？
  - SJS 模块有哪些导出方式？
  - 在 TYML 中如何使用 sjs 标签引入 SJS 模块？
  - sjs 标签的 module 和 src 属性分别有什么作用？
  - SJS 中变量声明支持哪些语法？
  - SJS 支持哪些运算符？
  - SJS 中有哪些流程控制语句可以使用？
  - SJS 目前支持哪些数据类型？
  - SJS 模块的作用域规则是什么？
  - require 函数在引用 SJS 模块时有哪些注意事项？
---

# SJS 语法参考

`SJS（safe/subset javascript）` 是小程序的一套脚本语言，结合 `tyml`，可以构建出页面的结构。

## 注意事项

1. `SJS` 的运行环境和其他 `JavaScript` 代码是隔离的，`SJS` 中不能调用其他 `JavaScript` 文件中定义的函数，也不能调用小程序提供的 `API`。
2. `SJS` 与 `JavaScript` 在语法上并不和 `JavaScript` 完全一致。

- [SJS 模块](#sjs-模块)
- [变量](#变量)
- [注释](#注释)
- [运算符](#运算符)
- [语句](#语句)
- [数据类型](#数据类型)
- [基础类库](#基础类库)
- [事件响应](#事件响应)

## SJS 模块

`SJS` 代码可以编写在 `tyml` 文件中的 `<sjs>` 标签内，或以 `.sjs` 为后缀名的文件内，每一个 `.sjs` 文件和 `<sjs>` 标签都是一个单独的模块。每个模块都有自己独立的作用域。即在一个模块里面定义的变量与函数，默认为私有的，对其他模块不可见。

#### 模块导出

一个模块要想对外暴露其内部的私有变量与函数，可以通过模块化语法 `module.exports` `export default` `exports` 导出。

```js
export const message = 'hello tuya';
export const getMsg = (x) => x;

// export default
export default {
  message,
  getMsg,
};

// module.exports
module.exports = {
  message,
  getMsg,
};
```

#### require 函数

在 `.sjs` 模块中引用其他 `sjs` 文件模块，可以使用 `require` 函数。

引用的时候，要注意如下几点：

- 只能引用 `.sjs` 文件模块，且必须使用相对路径。
- `sjs` 模块均为单例，`sjs` 模块在第一次被引用时，会自动初始化为单例对象。多个页面，多个地方，多次引用，使用的都是同一个 `sjs` 模块对象。
- 如果一个 `sjs` 模块在定义之后，一直没有被引用，则该模块不会被解析与运行。

**示例代码**

```js
// /a.sjs
export const message = 'hello tuya';
```

```js
// /b.sjs
var a = require('./a.sjs');
console.log(a.message);
```

```xml
<!-- /page/index/index.tyml -->
<sjs src="./b.sjs" module="b" />
```

控制台输出：

```
hello tuya
```

#### `<sjs>` 标签

| 属性名 | 类型   | 默认值 | 说明                                                                       |
| ------ | ------ | ------ | -------------------------------------------------------------------------- |
| module | string |        | 当前 `<sjs>` 标签的模块名。必填字段。                                      |
| src    | string |        | 引用 `.sjs` 文件的相对路径。仅当本标签为单闭合标签或标签的内容为空时有效。 |

#### module 属性

`module` 属性是当前 `<sjs>` 标签的模块名。在单个 `tyml` 文件内，建议其值唯一。有重复模块名则按照先后顺序覆盖（后者覆盖前者）。不同文件之间的 `sjs` 模块名不会相互覆盖。

`module` 属性值的命名必须符合下面两个规则：

首字符必须是：字母 `（a-zA-Z）`，下划线`（_）`
剩余字符可以是：字母`（a-zA-Z）`，下划线`（_）`， 数字`（0-9）`

**示例代码：**

```xml
<!--tyml-->

<sjs module="foo">
var some_msg = "hello world";
module.exports = {
  msg : some_msg,
}
</sjs>
<view> {{foo.msg}} </view>
```

页面输出：

```
hello world
```

上面例子声明了一个名字为 `foo` 的模块，将 `some_msg` 变量暴露出来，供当前页面使用。

#### `src` 属性

`src` 属性可以用来引用其他的 `sjs` 文件模块。

引用的时候，要注意如下几点：

- 只能引用 .`sjs` 文件模块，且必须使用相对路径。
- `sjs` 模块均为单例，`sjs` 模块在第一次被引用时，会自动初始化为单例对象。多个页面，多个地方，多次引用，使用的都是同一个 `sjs` 模块对象。
- 如果一个 `sjs` 模块在定义之后，一直没有被引用，则该模块不会被解析与运行。

**示例代码：**

```js
// /pages/index/index.js

Page({
  data: {
    msg: "'hello world' from js",
  },
});
```

```xml
<!-- /pages/index/index.tyml -->

<sjs src="./../comm.sjs" module="some_comms"></sjs>
<!-- 也可以直接使用单标签闭合的写法
<sjs src="./../comm.sjs" module="some_comms" />
-->

<!-- 调用 some_comms 模块里面的 bar 函数，且参数为 some_comms 模块里面的 foo -->
<view> {{some_comms.bar(some_comms.foo)}} </view>
<!-- 调用 some_comms 模块里面的 bar 函数，且参数为 page/index/index.js 里面的 msg -->
<view> {{some_comms.bar(msg)}} </view>
```

页面输出：

```
'hello world' from comm.sjs
'hello world' from js
```

上述例子在文件 `/page/index/index.tyml` 中通过 `<sjs>` 标签引用了 /page/comm.sjs 模块。

#### 注意事项

`<sjs>` 模块只能在定义模块的 `tyml` 文件中被访问到。使用 `<include>` 或 `<import>` 时，`<sjs>` 模块不会被引入到对应的 `tyml` 文件中。
`<template>` 标签中，只能使用定义该 `<template>` 的 `tyml` 文件中定义的 `<sjs>` 模块。

## 变量

SJS 中的变量均为值的引用。

#### 语法规则

- var 与 JavaScript 中表现一致，会有变量提升。
- 支持 const 与 let，与 JavaScript 表现一致。
- 只声明变量而不赋值，默认值为 undefined。

```js
var num = 1;
var str = 'hello tuya';
var undef; // undef === undefined
const n = 2;
let s = 'string';
```

#### 变量名

##### 命名规则

变量命名必须符合下面两个规则：

- 首字符必须是：字母`（a-z,A-Z）`，下划线`（_）`
- 首字母以外的字符可以是：字母`（a-z,A-Z）`，下划线`（_）`，数字`（0-9）`

##### 保留标识符

与 `Javascript` 语法规则一致

## 注释

注释方法和 `Javascript` 一致，可以使用以下方法对 `SJS` 代码进行注释：

```js
// page.sjs
// 方法一：这是一个单行注释
/*
方法二：这是一个多行注释
中间的内容都会被注释
*/
let h = 'hello';
const w = ' tuya';
```

## 运算符

#### 算术运算符

```js
var a = 10,
  b = 20;
// 加法运算
console.log(30 === a + b); //true
// 减法运算
console.log(-10 === a - b); //true
// 乘法运算
console.log(200 === a * b); //true
// 除法运算
console.log(0.5 === a / b); //true
// 取余运算
console.log(10 === a % b); //true
```

加法 `+` 运算符可用作字符串拼接。

```js
var a = 'hello',
  b = ' tuya';
// 字符串拼接
console.log('hello tuya' === a + b); //true
```

#### 比较运算符

```js
var a = 10,
  b = 20;
// 小于
console.log(true === a < b); //true
// 大于
console.log(false === a > b); //true
// 小于等于
console.log(true === a <= b); //true
// 大于等于
console.log(false === a >= b); //true
// 等号
console.log(false === (a == b)); //true
// 非等号
console.log(true === (a != b)); //true
// 全等号
console.log(false === (a === b)); //true
// 非全等号
console.log(true === (a !== b)); //true
```

#### 二元逻辑运算符

```js
var a = 10,
  b = 20;
// 逻辑与
console.log(20 === (a && b)); //true
// 逻辑或
console.log(10 === (a || b)); //true
// 逻辑否，取反运算
console.log(false === !a); //true
```

#### 位运算符

```js
var a = 10,
  b = 20;
// 左移运算
console.log(80 === a << 3); //true
// 无符号右移运算
console.log(2 === a >> 2); //true
// 带符号右移运算
console.log(2 === a >>> 2); //true
// 与运算
console.log(2 === (a & 3)); //true
// 异或运算
console.log(9 === (a ^ 3)); //true
// 或运算
console.log(11 === (a | 3)); //true
```

#### 赋值运算符

```js
var a = 10;
a = 10;
a *= 10;
console.log(100 === a); //true
a = 10;
a /= 5;
console.log(2 === a); //true
a = 10;
a %= 7;
console.log(3 === a); //true
a = 10;
a += 5;
console.log(15 === a); //true
a = 10;
a -= 11;
console.log(-1 === a); //true
a = 10;
a <<= 10;
console.log(10240 === a); //true
a = 10;
a >>= 2;
console.log(2 === a); //true
a = 10;
a >>>= 2;
console.log(2 === a); //true
a = 10;
a &= 3;
console.log(2 === a); //true
a = 10;
a ^= 3;
console.log(9 === a); //true
a = 10;
a |= 3;
console.log(11 === a); //true
```

#### 一元运算符

```js
var a = 10,
  b = 20;
// 自增运算
console.log(10 === a++); //true
console.log(12 === ++a); //true
// 自减运算
console.log(12 === a--); //true
console.log(10 === --a); //true
// 正值运算
console.log(10 === +a); //true
// 负值运算
console.log(0 - 10 === -a); //true
// 否运算
console.log(-11 === ~a); //true
// 取反运算
console.log(false === !a); //true
// delete 运算
console.log(true === delete a.fake); //true
// void 运算
console.log(undefined === void a); //true
// typeof 运算
console.log('number' === typeof a); //true
```

#### 三元运算符

```js
var a = 10,
  b = 20;
// 条件运算符
console.log(20 === (a >= 10 ? a + 10 : b + 10)); //true
```

#### 逗号运算符

```js
var a = 10,
  b = 20;
// 逗号运算符
console.log(20 === (a, b)); //true
```

#### 运算符优先级

SJS 运算符的优先级与 Javascript 一致。

## 语句

#### if 语句

在 .sjs 文件中，可以使用以下格式的 if 语句 ：

- if (expression) statement ： 当 expression 为 true 时，执行 statement。
- if (expression) statement1 else statement2 : 当 expression 为 true 时，执行 statement1。 否则，执行 statement2。
- if ... else if ... else statementN 通过该句型，可以在 statement1 ~ statementN 之间选其中一个执行。

**示例语法：**

```javascript
// if ...
if (表达式) 语句;
if (表达式) 语句;
if (表达式) {
  代码块;
}
// if ... else
if (表达式) 语句;
else 语句;
if (表达式) 语句;
else 语句;
if (表达式) {
  代码块;
} else {
  代码块;
}
// if ... else if ... else ...
if (表达式) {
  代码块;
} else if (表达式) {
  代码块;
} else if (表达式) {
  代码块;
} else {
  代码块;
}
```

#### switch 语句

**示例语法：**

```javascript
switch (表达式) {
  case 变量:
    语句;
  case 数字:
    语句;
    break;
  case 字符串:
    语句;
  default:
    语句;
}
```

- `default` 分支可以省略不写。
- `case` 关键词后面只能使用：`变量`，`数字`，`字符串`。

**示例代码：**

```javascript
var exp = 10;
switch (exp) {
  case '10':
    console.log('string 10');
    break;
  case 10:
    console.log('number 10');
    break;
  case exp:
    console.log('var exp');
    break;
  default:
    console.log('default');
}
```

**输出：**

```
number 10
```

#### for 语句

**示例语法：**

```javascript
for (语句; 语句; 语句) 语句;
for (语句; 语句; 语句) {
  代码块;
}
```

- 支持使用 `break`，`continue` 关键词。

**示例代码：**

```javascript
for (var i = 0; i < 3; ++i) {
  console.log(i);
  if (i >= 1) break;
}
```

**输出：**

```
0
1
```

#### while 语句

**示例语法：**

```javascript
while (表达式) 语句;
while (表达式) {
  代码块;
}
do {
  代码块;
} while (表达式);
```

- 当 `表达式` 为 true 时，循环执行 `语句` 或 `代码块`。
- 支持使用 `break`，`continue` 关键词。

## 数据类型

`SJS` 目前支持的数据类型、判断类型的方式与 `JavaScript` 相同。

- 值类型(基本类型)：字符串(`String`)、数字(`Number`)、布尔(`Boolean`)、对空(`Null`)、未定义(`Undefined`)、`Symbol`。
- 引用数据类型：对象(`Object`)、数组(`Array`)、函数(`Function`)。

## 基础类库

`SJS` 目前支持的基础类库与 `JavaScript` 相同。
