destroy 实例化的节点也会将原节点的组件一起删了

我不确定是不是我的操作有问题或是我的使用姿势不对导致的这个问题。
我对一个预制体进行实例化然后添加到界面上 我们对这个节点标记Node1 。
然后对Node1 动态添加两个组件 一个是button(这个不限我测试用所以加上去的) 一个是另外一个类(testCom)
我再对这个实例化出来的节点Node1进行实例化并且再添加到界面上 我们对这个新的节点标记Node2。
这时候我对node2进行destroy 结果node1中添加的(testCom)组件丢失了
image 这是以上的代码
log出来得到的是


这时候还是正常的
但是在我添加了 移除Node2 的方法之后

log出来的结果就是testCom不见了

我的理解力 实例化是深度拷贝 移除拷贝出来的节点不用改影响到原节点才对 这边就让我很费解。是不是我的理解或者我的用法不对?以上的用发是出现在滚动容器与引导里,我克隆了滚动容器的节点,滚动容器内对节点添加了组件,这时候我移除克隆的节点就导致滚动容器内添加的类丢失了
有没有大佬指点一下?

bugDemo2.zip (863.9 KB)

这是demo

又发现了一个新的问题, 我对node2进行脚本移除, 结果log 出来 node1的没了 但是node2的还在



这指针是乱了?

你是用node1实例化的node2,node2上的组件当然和1一样的

是一样的,但是我移除node2 结果node1的丢了

demo工程传错了吧

我改过了 节点名字,本身是没错的

我重新传demo了

神仙写法,所以你为什么要把testCom放在test里面呢?你把testCom单独放一个脚本,并添加注解@ccclass就正常了。所以你为什么不添加@ccclass呢?

cocos底层cc对象和js对象拷贝逻辑不一样,具体自己查源码。逆天写法导致的bug

不加注解这里返回false,不会被标记为cc对象。

有一说一,2.x的引擎源码结构相对3.x真是一坨

多谢大哥指导 我这边试一下,单独提出来一个脚本

感谢大佬!我单独拎出来一个脚本 备注@ccclass 就正常了

为什么不用 @ccclass 注解不会成为 cc 对象

核心原因: __ctors__ 属性标识

Cocos Creator 通过 __ctors__ 属性来识别一个类是否是 CCClass。关键代码在 CCClass.js 第 1034-1037 行:

CCClass._isCCClass = function (constructor) {
    return constructor &&
           constructor.hasOwnProperty('__ctors__');     // is not inherited __ctors__
};

@ccclass 的作用流程

  1. @ccclass 装饰器调用 cc.Class()

当使用 @ccclass 装饰器时,它会调用 cc.Class(proto)CCClassDecorator.js 第 283 行):

var ccclass = checkCtorArgument(function (ctor, name) {
    var base = js.getSuper(ctor);
    var proto = {
        name,
        extends: base,
        ctor,
        __ES6__: true,
    };
    // ...
    var res = cc.Class(proto);  // <-- 这里
    return res;
});
  1. cc.Class() 给类添加 __ctors__ 属性

CCClass.js 第 283 行:

js.value(fireClass, '__ctors__', ctors.length > 0 ? ctors : null, true);

这个 __ctors__ 属性是 CCClass 的身份标识。

不使用 @ccclass 的后果

如果没有 @ccclass ,类就不会被 cc.Class() 处理,因此不会有 __ctors__ 属性。这会导致引擎在多个关键位置将其视为普通对象而非 CCClass:

1. 实例化 ( instantiate.js 第 190 行)

function enumerateObject (obj, clone, parent) {
    var klass = obj.constructor;
    if (cc.Class._isCCClass(klass)) {
        enumerateCCClass(klass, obj, clone, parent);  // 只复制 __values__ 定义的属性
    }
    else {
        // 当作普通对象处理,遍历所有 own properties
        for (var key in obj) {
            if (!obj.hasOwnProperty(key) || ...) {
                continue;
            }
            // 复制属性...
        }
    }
}

影响:如果没有 @ccclass ,实例化时会遍历所有 hasOwnProperty 属性,可能复制不必要的内部属性,且不会正确处理 CCClass 的属性初始化逻辑。

2. 对象销毁后的属性重置 ( CCObject.js 第 370 行)

if (cc.Class._isCCClass(ctor)) {
    var attrs = cc.Class.Attr.getClassAttrs(ctor);
    var propList = ctor.__props__;
    for (var i = 0; i < propList.length; i++) {
        // 根据 __props__ 重置属性为默认值
    }
}

影响:没有 @ccclass ,对象池复用对象时无法正确重置属性。

3. 反序列化 ( deserialize-compiled.ts )

反序列化时需要根据类定义创建对象并设置属性。如果类不是 CCClass,引擎无法正确识别和处理其属性定义。

4. 编辑器识别

编辑器中的组件面板、属性检查器等都依赖 _isCCClass 来判断一个类是否是有效的组件类。_

总结

特性 @ccclass @ccclass
__ctors__ 属性 :white_check_mark: :x:
_isCCClass() 返回 true_ false
序列化/反序列化 :white_check_mark: 正常 :x: 失败
cc.instantiate_ :white_check_mark: 正确复制 :warning: 可能异常
编辑器识别 :white_check_mark: 正常 :x: 无法识别
属性默认值重置 :white_check_mark: 正常 :x: 失效_

结论: @ccclass 是 Cocos Creator 识别和管理类的"身份证"。没有它,引擎无法将类识别为 CCClass,导致序列化、实例化、属性管理等核心功能无法正常工作。