Skip to content

环境检测与辅助 ​

@jiess/utils/helper 模块提供三大类辅助功能:环境检测、响应式与网络工具、动态函数构造。

typescript
// 环境检测
import { getBrowserInfo, getOSInfo, getDeviceType, initSystemInfo } from '@jiess/utils/helper'

// 响应式与网络工具
import { shallowCopy, isReactive, getQuery, throwErr } from '@jiess/utils/helper'

// 动态函数(⚠️ 有安全风险,见下方说明)
import { customFuction, customAsyncFuction } from '@jiess/utils/helper'

一、环境检测(environment.ts) ​

环境检测函数均接收 userAgent: string 参数,通常在浏览器端从 navigator.userAgent 获取,在服务端可从请求头获取。

getBrowserInfo(userAgent) ​

解析浏览器信息,返回完整的浏览器环境信息对象。

typescript
getBrowserInfo(navigator.userAgent)
// { appName, appVersion, platform, product, vendor, userAgent }
// 返回当前浏览器环境的完整信息,而非简化的 { browser, version }

getOSInfo(userAgent) ​

检测操作系统类型。

typescript
getOSInfo(navigator.userAgent)
// 'Windows' | 'MacOS' | 'iOS' | 'Android' | 'Linux' | 'UNIX' | 'Unknown OS'

// 平台适配
const os = getOSInfo(navigator.userAgent)
if (os === 'iOS' || os === 'Android') {
  applyMobileKeyboardFix()
}

getDeviceInfo(userAgent) ​

返回具体设备名称(比 getDeviceType 更精细)。

typescript
getDeviceInfo(navigator.userAgent)
// 'iPhone' | 'iPad' | 'Android Device' | 'Windows Phone' | 'BlackBerry' | 'Mobile' | 'Tablet' | 'Desktop'

getDeviceType(userAgent) ​

返回设备大类,支持检测小程序环境。

typescript
getDeviceType(navigator.userAgent)
// 'Desktop' | 'Mobile' | 'Tablet' | 'Applet'

// 按设备资源分配
switch (getDeviceType(navigator.userAgent)) {
  case 'Mobile':  reduceAnimation(); break
  case 'Tablet':  loadMdAssets();    break
  case 'Applet':  initMiniApp();     break
  default:        loadFullAssets()
}

initSystemInfo(platform, space) ​

整合设备、OS、平台、环境、工作空间信息为统一标识字符串。

typescript
initSystemInfo('web', 'production')
// "Desktop ;Windows ;web ;development ;production"

注意:

  • 环境标识(第四段)始终硬编码为 'development',不反映实际运行环境。
  • 依赖 navigator.userAgent,仅能在浏览器环境中使用。

二、响应式与网络工具(jiess.ts) ​

isReactive(o) / isRef(v) / hasProxy(v) ​

判断对象是否为 Jiess 响应式代理。

typescript
import { isReactive, isRef, hasProxy } from '@jiess/utils/helper'

isReactive({ $jiess: true })    // true
isReactive({ a: 1 })            // false

// 在响应式渲染前判断类型
function renderValue(v: any) {
  if (isReactive(v)) return renderProxy(v)
  return v
}

initValue(v) ​

提取响应式代理的原始值,非代理对象原样返回。

typescript
import { initValue } from '@jiess/utils/helper'

initValue({ $proxy: { value: 'hello' } })  // 'hello'
initValue({ a: 1 })                          // { a: 1 }

shallowCopy(data, isError?) ​

浅拷贝对象或数组。isError=true 时,非对象/数组抛出异常。

typescript
import { shallowCopy } from '@jiess/utils/helper'

const arr = [1, 2, { a: 3 }]
const copy = shallowCopy(arr)
copy[2] !== arr[2]   // true(第三层是引用共享,浅拷贝特性)

throwErr(type, msg) ​

抛出带类型标记的 Error,返回类型为 never。

typescript
import { throwErr } from '@jiess/utils/helper'

function validate(input: unknown) {
  if (!input) throwErr('ValidationError', '输入不能为空')
}

try { validate(null) }
catch (e: any) {
  e.message  // "ValidationError Error:输入不能为空"
}

getQuery() ​

解析当前页面 URL 的 query 参数。非浏览器环境返回 undefined。

⚠️ 同名参数只保留最后一个值。

typescript
import { getQuery } from '@jiess/utils/helper'

// URL: https://example.com?lang=zh&page=2
const query = getQuery()
// { lang: 'zh', page: '2' }

const lang = query?.lang || 'en'

getHostname(url) / isIPv4(host) ​

网络地址处理工具。

typescript
import { getHostname, isIPv4 } from '@jiess/utils/helper'

getHostname('https://www.example.com/path')  // 'www.example.com'
getHostname('http://localhost:3000')          // 'localhost'

isIPv4('192.168.1.1')    // true
isIPv4('256.0.0.1')      // false
isIPv4('example.com')    // false

getWorkSpace(getSpace?) / getWorkInfo(platform, errFunc?) ​

获取工作空间标识与完整工作信息。

typescript
import { getWorkSpace, getWorkInfo } from '@jiess/utils/helper'

// 从 URL 的 $space 参数获取,若无 $space 则调用 getSpace 回调
// ⚠️ 不传 getSpace 且无 $space 参数时将抛出异常
const space = getWorkSpace()  // 可能抛出 '未指定工作空间标识'
const space = getWorkSpace((params) => params.env || 'production')  // 安全写法

// 异步获取完整工作信息,依赖 localStorage 和 navigator
const info = await getWorkInfo('web')
// "Desktop ;Windows ;web ;development ;production"

getWorkSpace 在 localStorage 不可用(Node.js)时返回 undefined。


三、动态函数构造(⚠️ 高风险) ​

customFuction(...arrs) / customAsyncFuction(...arrs) ​

从字符串动态创建可执行函数。底层分别使用 new Function() 和 AsyncFunction。

⚠️ 安全警告:本质是动态 eval,传入的代码字符串若来自用户输入或不可信来源,可能被注入恶意代码。调用方必须在传入前做白名单/沙箱校验。

参数说明
...arrs最后一项为代码字符串,前面的项为参数名列表
typescript
import { customFuction, customAsyncFuction } from '@jiess/utils/helper'

// 同步:参数 "a,b" → 代码 "return a + b"
const add = customFuction('a', 'b', 'return a + b')
add(1, 2)  // 3

// 异步
const fetch = customAsyncFuction('url', `
  const res = await globalThis.fetch(url)
  return res.json()
`)
fetch('/api/data').then(console.log)

// 错误处理(代码内抛出会通过 initError 捕获并上报)
const bad = customFuction('return notDefined')
bad()  // 不抛异常,通过 initError 处理

此功能主要用于 Jiess 脚本调试和动态规则引擎等受控场景。常规业务开发中不推荐使用。


类型导出 ​

@jiess/utils/midder 同时导出以下 TypeScript 类型,用于类型注解:

类型说明
ListenerConfig监听器配置 { listener: Function, tag?: string }
DriverConfig触发器配置 { defaultValue: unknown, tag?: string }
WatchEffectParamwatchEffect 参数 { flush?, onTrack?, onTrigger? }

默认导出 ​

@jiess/utils 也支持全量默认导入(不推荐,会失去 Tree-shaking):

typescript
import utils from '@jiess/utils'
utils.$clone({ a: 1 })

边界情况 ​

函数边界行为
getDeviceType微信/支付宝/QQ/百度/字节小程序 UA 均识别为 'Applet'
getOSInfo无法识别时返回 'Unknown OS'
shallowCopyisError=true 时字符串等非容器类型抛出异常
throwErr返回类型 never,TypeScript 能正确推断后续代码不可达
getQuery非浏览器环境返回 undefined;同名 key 只保留最后值
isIPv4256.0.0.1 等非法范围返回 false
customFuction代码字符串为空的函数直接返回 undefined