Deprecated: parse_url(): Passing null to parameter #1 ($url) of type string is deprecated in /www/wwwroot/blog_qqvbc_com/usr/plugins/Access/Access_Core.php on line 339

Deprecated: parse_url(): Passing null to parameter #1 ($url) of type string is deprecated in /www/wwwroot/blog_qqvbc_com/usr/plugins/Access/Access_Core.php on line 392

Deprecated: parse_url(): Passing null to parameter #1 ($url) of type string is deprecated in /www/wwwroot/blog_qqvbc_com/usr/plugins/Access/Access_Core.php on line 394
Joyber 的博客

阿奇索(Agiso)开放平台

open.agiso.com,是面向虚拟商品电商商家的API开放接口平台,和91卡券是同一套产品体系,主打多平台店铺自动发货、订单推送对接。

主要用途

  1. 多电商平台订单接收
    通过API接收淘宝、天猫、闲鱼、拼多多、抖店、快手、有赞等店铺的订单消息推送,把店铺订单同步到自己的系统/第三方货源系统。
  2. 虚拟商品自动发货对接
    专门用于卡密、兑换券、会员充值、餐饮代下单这类虚拟货源。
  3. 店铺买家下单后,把订单推送给你的货源系统;
  4. 货源返回卡密/充值链接,自动发给买家,店铺自动标记已发货,实现无人值守自动发货。
  5. 开发者自建业务系统对接
    开发者创建应用拿到AppId/AppSecret,获取订单推送回调、授权token,把阿奇索能力集成到自己开发的ERP、货源系统、自动发货软件里。
  6. 联动91卡券后台
    开放平台负责接口授权,91卡券后台做卡券库存、货源管理、发货规则配置,两者配合使用。

使用门槛

  • 需要做个人/企业资质认证(企业需上传营业执照);
  • 创建应用后,需要找客服开通接口权限;长时间不调用接口,AppId会自动封禁;
  • 适合卖虚拟权益的商家、开发自动发货工具的开发者;实物电商基本用不到。

简单流程

注册账号→资质认证→创建应用→找客服开通权限→拿到AppId/AppSecret→店铺后台授权绑定→配置订单回调地址,接收店铺订单、完成自动发货。

提示:该平台主要服务虚拟卡券、充值类电商,不适合普通实物店铺。

鱼店长

不是闲鱼官方产品
归属:厦门阿奇索(Agiso) 的第三方PC客户端,和你刚才问的阿奇索开放平台、91卡券是同一家公司的产品。

区分清楚

  1. 闲鱼官方电脑后台:鱼小铺后台 seller.goofish.com,网页版,免费,阿里官方。
  2. 闲管家:闲鱼官方合作PC工作台,阿里侧认证第三方工具。
  3. 鱼店长:阿奇索自研付费软件,不属于阿里/闲鱼官方,只是做闲鱼商家工具对接。

鱼店长能干什么

面向闲鱼虚拟商品卖家(卡密、充值会员):

  • PC端多账号登录闲鱼、集中聊天客服、批量管理商品、自动擦亮、智能回复
  • 对接91卡券货源,实现闲鱼自动发货、直充,和阿奇索开放平台打通API接口
  • 是收费工具:年费/月费,部分直充业务还要扣“奇豆”手续费

风险提醒

  1. 属于第三方登录工具,是账号密码授权登录,不是闲鱼开放API授权,有账号风控、限流、封号风险。
  2. 自动擦亮、自动回复这类自动化操作,违反闲鱼用户协议,有概率触发处罚。
  3. 官方不会维护鱼店长,一旦闲鱼更新协议/接口,工具可能直接失效。
简单记:鱼小铺=闲鱼原生;闲管家=官方合作;鱼店长=阿奇索第三方付费工具。

ES5 vs ES6(ES2015+)核心区别

ES5:2009发布;ES6正式名称ES2015,后续每年迭代ES2016~ES2025,日常统称ES6。下面梳理最常用、工作高频差异

一、变量声明

ES5

只有 var

  1. 函数作用域,存在变量提升
  2. 允许重复声明
  3. 没有块级作用域(if/for循环无法隔离变量)

    var a = 1;
    var a = 2; // 合法
    for(var i=0;i<3;i++){}
    console.log(i); // 3 泄露到外层

ES6

新增 let / const

  1. 块级作用域 { } 隔离
  2. 暂时性死区TDZ,声明前不能访问
  3. 不允许同作用域重复声明
  4. const 声明常量(引用类型可修改内部属性,不能重赋值)

    let a = 1;
    const PI = 3.14;
    {
      let b = 10
    }
    console.log(b) // 报错

二、函数

1. 箭头函数 ()=>{} 【ES6新增】

ES5只有普通function

// ES5
var add = function(a,b){return a+b}
// ES6
const add = (a,b) => a + b;

箭头函数特点

  • 不绑定 this:继承外层作用域this(最常用,解决回调this指向问题)
  • 没有 arguments,可用剩余参数 ...args 替代
  • 不能作为构造函数,不能new
  • 没有 prototype

2. 函数参数增强 ES6

  • 默认参数

    // ES5
    function fn(x){x = x || 0}
    // ES6
    function fn(x = 0){}
  • 剩余参数 ...rest

    function sum(a,...rest){}
  • 参数解构

三、解构赋值(ES6新增)

快速提取数组、对象属性

// 对象解构
const user = {name:"张三",age:20}
// ES5
const name = user.name;
// ES6
const {name,age} = user;

//数组解构
const [a,b] = [10,20]

四、展开运算符 ... ES6

const arr2 = [...arr1,4,5]; //数组拷贝/合并
const obj2 = {...obj1,c:10}; //对象浅拷贝

五、字符串

  1. 模板字符串 ` (反引号) ES6

    // ES5
    var str = "name:" + name + ",age:"+age;
    // ES6
    const str = `name:${name},age:${age}`

    支持换行、插值 ${表达式}

  2. ES6新增字符串方法:includes()、startsWith()、endsWith()

六、对象字面量增强 ES6

const name = "小明"
// ES5
const obj = {name:name, say:function(){}}
// ES6 属性简写、方法简写
const obj = {
  name,
  say(){}
}
// 计算属性名
const obj = {["key"+1]:100}

七、数组新特性

  • ES6:Array.from() 类数组转数组
  • find()、findIndex()、some/every原有ES5就有
  • entries() keys() values() 迭代器

八、迭代器 & for...of(ES6新增)

  • ES5:for循环、forEach、for...in(遍历对象key,不适合数组)
  • ES6:for...of 遍历可迭代对象(数组、Set、Map、字符串)

    for(const item of arr){}
    for...in:遍历键;for...of:遍历值

九、新增数据结构 ES6

ES5仅有:Object、Array
ES6新增:

  • Set:集合,元素唯一
  • Map:键可以是任意类型(ES5对象key只能字符串/Symbol)
  • WeakSet / WeakMap 弱引用,利于GC垃圾回收
  • Symbol:唯一不可重复的值,用作私有属性标识

十、类 Class(ES6语法糖)

ES5 原型模拟面向对象

// ES5
function Person(name){this.name = name}
Person.prototype.say = function(){}

// ES6 class
class Person{
  constructor(name){
    this.name = name
  }
  say(){}
}

⚠️ class只是原型的语法糖,不是真正面向对象,不存在继承隔离;支持 extends 继承、super()

十一、模块化 Module import / export ES6

ES5没有原生模块,依靠:IIFE、RequireJS、CommonJS(Node.js)
ES6 原生ESM标准

//导出
export const a = 1;
export default fn;
//导入
import fn, {a} from './mod.js'
CommonJS:运行时加载;ESM:编译期静态导入,支持Tree-Shaking

十二、Promise 异步方案 ES6

ES5异步:回调函数 → 回调地狱
ES6 原生Promise,解决嵌套回调
后续ES2017新增 async / await(Promise语法糖)

new Promise((resolve,reject)=>{})
async function query(){
  await fetch()
}

十三、其他重要特性

  1. 赋值简写:对象解构、数组解构
  2. Promise、async/await
  3. Object.assign() 对象合并(ES6)
  4. 尾调用优化
  5. 二进制/八进制数值字面量
  6. Proxy、Reflect(ES6,实现数据劫持,Vue3底层原理)

精简对比总结表

特性ES5ES6
变量var,函数作用域let/const,块级作用域
函数function箭头函数、默认参数、rest参数
字符串字符串拼接模板字符串 `...${}`
对象基础字面量属性简写、方法简写、计算属性
循环for / forEach / for..infor...of 迭代器
异步回调函数Promise + async/await
面向对象原型手写构造函数class / extends 继承语法糖
模块无原生模块(CMD/AMD)import / export ESM
数据结构Array、ObjectSet、Map、Symbol、Weak系列
解构手动取值对象/数组解构赋值
运算符无展开语法...展开运算符

开发最需要记住的重点(面试高频)

  1. var / let / const 区别、块级作用域、暂时性死区
  2. 箭头函数this指向问题
  3. class是语法糖,底层依旧原型
  4. ESM 和 CommonJS 的差异
  5. Promise解决回调地狱,async await简化Promise
  6. 解构、模板字符串、展开运算符日常使用最多

JsonOb 响应式:数据劫持 + 变化监听完整技术细节

Screenshot_20260729_085722_tv_danmaku_bili_UnitedBizDetailsActivity.jpg

先纠正PPT笔误: Object.Defefirbairty  →  Object.defineProperty 
这套方案是Vue2 同源响应式方案,也是很多游戏引擎、小程序自研状态库 JsonOb 的底层实现。

一、整体流程对照PPT架构

plaintext

原始JS对象

Object.defineProperty 深度劫持(get/set)【数据拦截】

数据发生修改 → set触发 → 发送变更信号

信号广播系统(订阅发布模式)

通知所有依赖当前字段的UI组件,执行UI更新
 

二、核心1:Object.defineProperty 数据劫持原理

  1. API基础作用

 Object.defineProperty(obj, key, descriptor) 
对对象的指定属性重新定义,拦截 读取(get)、赋值(set)。

javascript

let rawData = { name:"test" };
// 劫持name属性
Object.defineProperty(rawData, 'name', {
get(){

// 读取时:收集当前正在执行的UI渲染函数(依赖收集)
track() 
return this._value;

},
set(newVal){

if(newVal === this._value) return; // 值无变化跳过
this._value = newVal;
// 修改时:触发信号派发,通知订阅者更新
trigger()

}
})
 

  1. 深度劫持(深层对象递归处理)

普通 defineProperty 只能劫持一层属性,嵌套对象  {a:{b:1}}  内层b不会监听。
实现方案:

1. 递归遍历对象所有属性;
2. 如果属性值依然是  Object/Array ,继续对它执行  defineProperty  包装;

这就是PPT写的【深度属性劫持】。

  1. 致命短板(defineProperty 天生缺陷)

1. 无法监听新增属性、删除属性
 obj.xxx = 1  新增字段不会触发set; delete obj.xxx  无钩子。
解决方案:框架提供  $set  /  $del  API。
2. 不能原生监听数组下标修改
 arr[2] = 999  不会触发set。

三、核心2:数组监听怎么实现(PPT第二条)

原生数组无法靠defineProperty监听下标变更,JsonOb采取 方法重写拦截:

1. 复制数组原型  Array.prototype ;
2. 重写会改变数组内容的变异方法: push pop shift unshift splice sort reverse ;
3. 当业务调用  arr.push()  时,先走重写后的包装函数:

  • 执行原生数组操作
  • 手动调用  trigger()  发送变更信号

javascript

// 伪代码思路
const rawPush = Array.prototype.push;
Array.prototype.push = function(...args){
const res = rawPush.apply(this, args);
trigger(this); // 广播数组变更
return res;
}
 

注意: arr[0] = xxx 、 arr.length = 10  依然无法被捕获,框架一般同样提供API规避。

四、核心3:依赖收集 & 信号广播(订阅发布)

劫持只是拿到“数据变化通知”,还需要知道哪些UI依赖这个字段。

  1. track() 依赖收集(get阶段)

1. UI组件执行渲染函数,读取响应式字段  data.name ;
2. 触发  get() ,执行 track ;
3. 把「当前渲染函数」存入当前属性的依赖列表。
数据结构简易模型:

plaintext

targetMap = {
对象: {

属性名: [组件更新回调1, 组件更新回调2]

}
}
 

  1. trigger() 信号广播(set阶段)

当 set 检测数值改变:

1. 获取该属性保存的所有依赖回调;
2. 批量执行回调 → UI组件执行刷新。
也就是PPT里的【信号广播】。

五、PPT重点特性:enableBatch 批量变更

场景:一帧内连续多次修改数据

plaintext

data.a = 1
data.b = 2
data.c = 3
 

不做批处理:每次赋值立刻触发UI刷新 → 3次渲染,性能浪费。
enableBatch实现逻辑:

1. 开启批量模式后, trigger 不会立刻执行更新;
2. 将所有变更任务存入队列;
3. 等到当前JS执行栈结束(下一帧/微任务时机);
4. 去重、合并所有变更,统一执行一次UI更新。

游戏引擎、前端渲染库高频修改场景极其重要,减少重绘次数。

六、内存管理(PPT最后一条)

这套响应式很容易产生内存泄漏:
对象销毁后,依赖列表依然保存UI组件引用,组件无法GC。
JsonOb处理方案:

1. 组件销毁时,主动清除对应属性的依赖回调;
2. 使用弱引用容器(WeakMap)保存targetMap;
3. 对外提供销毁API,解除对象劫持,清空订阅列表。

七、拓展对比:defineProperty vs Proxy

你这套JsonOb使用 Object.defineProperty(Vue2方案)
现代方案用  Proxy (Vue3):

1. Proxy原生支持监听新增属性、数组下标、删除;
2. 不需要递归深度劫持,可以惰性代理;
缺点:不支持低版本运行环境。
很多小游戏引擎、老框架继续沿用defineProperty实现的JsonOb。

八、完整数据流总结(对应PPT框图)

1. 开发者修改响应式数据;
2.  Object.defineProperty set  拦截赋值(数据拦截);
3. 判断值是否真正变化,避免无效通知;
4. 发送变更信号(批量模式下先入队列);
5. 信号广播遍历所有订阅该字段的UI组件;
6. 各个UI组件执行自身更新逻辑;
7. 组件卸载后自动清理依赖引用,防止内存泄露。

如果你需要,我可以写一份精简可运行的 JsonOb最小实现Demo(defineProperty版本),直观复现这套劫持+广播逻辑。

Cocos Creator 主动检测碰撞(3.8.8适用)

一、两种碰撞检测模式区分

1. 被动检测(默认):绑定碰撞组件+碰撞回调,物体接触自动触发onCollisionEnter
2. 主动检测(你要的):代码手动调用接口,任意时刻主动查询:有没有碰到、碰到哪些物体

二、2D主动碰撞检测(刚体/碰撞盒通用)

  1. 检测当前节点周围所有碰撞体(重叠查询)

typescript

import { _decorator, Component, Node, Collider2D, Physics2DManager, Rect } from 'cc';
const { ccclass, property } = _decorator;

@ccclass
export class Test extends Component {

start() {
    this.checkOverlap();
}

checkOverlap() {
    // 获取自身2D碰撞盒
    const collider = this.node.getComponent(Collider2D);
    if (!collider) return;

    // 主动查询所有和自己重叠的碰撞物体
    const resultArr = Physics2DManager.instance.queryColliders(collider.worldAABB);
    for (const coll of resultArr) {
        // 排除自己
        if (coll.node === this.node) continue;
        console.log("主动检测到碰撞目标:", coll.node.name);
    }
}

}
 

  1. 射线检测(主动发射射线探路)

适合:判断前方有没有障碍物、点击选中物体

typescript

// 从自身位置向右发射一条长射线
const origin = this.node.worldPosition;
const end = origin.add3f(200, 0, 0);
const hits = Physics2DManager.instance.raycast(origin, end);
if (hits.length > 0) {

console.log("射线碰到物体", hits[0].collider.node.name);

}
 

三、3D主动碰撞检测(软体、3D物体适用)

  1. 包围盒重叠检测

typescript

import { PhysicsSystem, Collider } from 'cc';

// 获取自身碰撞包围盒
const selfCollider = this.node.getComponent(Collider);
const box = selfCollider.worldBounds;

// 查询所有和盒子重叠的3D碰撞体
const hits = PhysicsSystem.instance.queryColliders(box);
for (const hit of hits) {

if (hit.node !== this.node) {
    console.log("主动检测碰撞3D物体:", hit.node.name);
}

}
 

  1. 3D射线检测

typescript

const start = this.node.worldPosition;
const dir = new Vec3(0, -1, 0); // 向下检测(落地判断)
const rayHit = PhysicsSystem.instance.raycastClosest(start, dir, 100);
if (rayHit) {

console.log("下方碰到地面/物体");

}
 

四、适用场景(对应你之前软体肉块需求)

1. 软体肉块掉落,主动向下射线检测:判断什么时候碰到桌子、凹凸物体
2. 肉块滑动时每帧主动查询周围碰撞体,贴合物体边缘
3. 不依赖自动碰撞回调,完全自己控制检测时机(每帧/间隔几秒检测一次)

五、关键注意点

1. 必须开启物理引擎:2D勾选 项目设置-物理2D;3D勾选物理系统
2. 所有需要被检测的物体,必须挂载对应 Collider2D / Collider 碰撞组件
3. 性能优化:

  • 不要每帧大规模查询全部碰撞体,能用射线就不用包围盒查询
  • 软体粒子多的话,隔2帧检测一次,降低消耗
    4. 区分:
  • queryColliders:检测重叠(两个物体贴在一起)
  • raycast:线段探测(预判前方物体)

六、简易落地检测示例(肉块掉桌面)

每帧向下射线,主动判断是否接触台面,接触后开启滑动软体动画:

typescript

update() {

const pos = this.node.worldPosition;
// 向下发射射线,长度50
const isHit = PhysicsSystem.instance.raycastClosest(pos, new Vec3(0,-1,0), 50);
if (isHit) {
    // 碰到物体,执行贴边滑动逻辑
}

}