无法从上下文对象继承?

2023-12-02

我试图创建一个继承自上下文对象的对象。但是在从我继承的对象调用函数时,浏览器(Chrome)声明未捕获的类型错误:非法调用。这是基本代码:

http://jsfiddle.net/adrianh/BKYfv/1/

var c = document.getElementById("myCanvas");
var ctx = c.getContext("2d");
var ctx2 = Object.create(ctx);
ctx.setTransform(1, 0, 0, 1, 0, 0); // identity -- works
alert("ctx works");
ctx2.setTransform(.5, 0, 0, .5, 0, 0); // scale by half -- fails
alert("ctx2 works");

为什么会失败?

解决方法

我写了一个makeForwardingObject()可以实现我想要的功能。可以找到here.

// makeForwardingObject(obj, funcs, attribs)
//
//        obj - the object that is being forwarded to
//      funcs - array of non enumerable function member names to forward to
//    attribs - array of non enumerable attributes to forward to
//
// Makes a forwarding object that forwards all functions calls and attribute
// requests to the forwarded object.  In this way, the original object is
// acted upon directly, while you can delete or modify members to your 
// object without interfering with the original.
//
// Access to the object being forwarded to is always available using member
// functions applyParent(), callParent(), setParentAttrib() and 
// getParentAttrib().
//
// If funcs or attribs are enumerable in the object, they are not added 
// a second time.
function makeForwardingObject(obj, funcs, attribs)
{
    var _ = { };
    Object.defineProperties(_, {
        _: { value: obj },
        // like obj.apply() except it applys to object being forwarded to.
        applyParent : { value: function applyParent(func, args)
        {
            return this._[func].apply(this._, args);
        }},
        // like obj.call() except it applys to object being forwarded to.
        callParent: { value: function callParent(func)
        {
            // FF at least doesn't understand arguments.slice(), 
            // arguments.splice() or arguments.shift().  WTF?!?!
            var args=[];
            for (i=1; i<arguments.length; ++i)
                args[i-1]=arguments[i];
            return this._[func].apply(this._, args);
        }},
        // this is for setting member of object being forwarded to.
        setParentAttrib: { value: function setParentAttrib(attrib, val)
        {
            return this._[attrib]=val;
        }},
        // this is for getting member of object being forwarded to.
        getParentAttrib: { value: function getParentAttrib(attrib, val)
        {
            return this._[attrib];
        }},
    });

    for (var key in obj)
    {
        switch (typeof obj[key])
        {
            case 'function':
                _[key] = eval("(function "+key+"() { return this._."+key+".apply(this._, arguments);  })");
                break;
            default:
                eval("Object.defineProperty(_, '"+key+"', {"+
                         "get: function "+key+"() { return this._."+key+"; },"+
                         "set: function "+key+"(v) { return this._."+key+"=v; },"+
                         "enumerable: true,"+
                     "})");
                break;
        }
    }
    for (var index in funcs)
    {
        var key = funcs[index];
        if (!_.hasOwnProperty(key))
        {
            _[key] = eval("(function "+key+"() { return this._."+key+".apply(this._, arguments);  })");
        }
    }

    for (var index in attribs)
    {
        var key = funcs[index];
        if (!_.hasOwnProperty(key))
        {
            eval("Object.defineProperty(_, '"+key+"', {"+
                 "get: function "+key+"() { return this._."+key+"; },"+
                 "set: function "+key+"(v) { return this._."+key+"=v; },"+
                 "enumerable: false,"+
                 "})");
        }
    }

    return _;
}

// Return a string of all the members in an object. Used for debugging.
function getMembers(obj)
{
    var _ = "";
    for (key in obj)
    {
        _ += key + ":" + typeof obj[key] + " = " + obj[key] +"\n";
    }
    return _;
}


var c = document.getElementById("myCanvas");
var ctx = c.getContext("2d");
var ctx2 = makeForwardingObject(ctx);
var x = { a: "" };
alert(getMembers(ctx));
alert(getMembers(ctx2));
ctx.setTransform(1, 0, 0, 1, 0, 0); // identity -- works
alert("ctx works");
ctx2.setTransform(.5, 0, 0, .5, 0, 0); // scale by half -- works!
//These are alternate ways to call the forwarded object's member functions:
//  ctx2.applyParent('setTransform', [.5, 0, 0, .5, 0, 0]); // scale by half -- works!
//  ctx2.callParent('setTransform', .5, 0, 0, .5, 0, 0); // scale by half -- works!
alert("ctx2 works");
ctx2.moveTo(0,0);
ctx2.lineTo(100, 100);
ctx2.stroke();

一个肤浅的答案是因为无法构建画布渲染上下文。使用CanvasRenderingContext2d()函数(像 DOM 中的许多其他构造函数一样)将抛出一个Type error: "Illegal constructor",因为它们应该只能从工厂函数以一种特定的方式创建。在这种情况下.getContext()画布的方法。

尽管使用 RenderingContext2d 作为原型创建了一个新对象,但您可以使用以下方法错误地创建渲染上下文

ctx2=Object.create(CanvasRenderingContext2D.prototype);

or

ctx2=Object.create(ctx.constructor.prototype);

为您提供一个完全空白的无状态(且无用)渲染上下文对象,它实际上抛出与克隆上下文相同的异常。它甚至没有分配画布。

这不起作用的原因是因为您只继承了对 RenderingContext 原型的公共方法的引用,并且在您的克隆的情况下,具有对您通过原型链创建的上下文的所有状态的引用,但是除此之外它是一个空心体。无私人var并且没有私下声明function里面声明的CanvasRenderingContext构造函数通过原型继承。

如果你好奇,你可以自己编写这种对象

function nonConstructable(factoryVar){
    if(arguments.callee.caller !== Factory){
        throw TypeError("Invalid constructor");
    }
    var privateVar = privateMethod();
    privateVar+=factoryVar;
    this.publicVar= privateVar;

    function privateMethod(){
        return 123;
    }
}
function Factory(){
    var privateFactoryVar = 321;
    return new nonConstructable(privateFactoryVar );
}

您会看到这两个对象是链接的,也是您在对象内执行操作的唯一方法nonConstructable构造函数是通过特定的构造函数来构造它Factory.

似乎做了更多研究CanvasRenderingContext2D and WebGLRenderingContext计划成为上下文的有效构造函数,它们可以渲染到任何画布,并且都应该在工作线程内工作。我不知道目前的实施情况如何,似乎人们在两年前出于某种原因完全停止写它。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

无法从上下文对象继承? 的相关文章

随机推荐

  • if 语句中多个条件的 Python 简写[重复]

    这个问题在这里已经有答案了 if x y z print x y 这是 if x y and y z 的简写吗 它在我的代码中有效 但我不确定当多个条件不都是 或 时如何解释 或者以上面的后一种形式写出 是的 如中所述文档 比较可以是任意链
  • 如何在 MATLAB 中为符号变量赋予数字?

    我尝试使用以下代码在 MATLAB 中声明一个符号变量 syms a 我对这个变量进行了计算 一切都很好 但我的问题是 我不知道如何给变量一个数字并得到数字结果 例如我的代码的答案是 answer exp 10 a 例如我想给 a 40并得
  • 当更新 sphinx.conf 中的索引时,总是需要在 sphinx 中重新启动 searchd 吗?

    如果我更新 sphinx conf 文件中的资源 我可以使用 rotate 重新索引 一切正常 如果我更新 sphinx conf 中的索引或添加新索引 rotate 不起作用 我必须重新启动 searchd 我这样做是否正确 我觉得 ro
  • 当不涉及真正的 I/O 调用时,异步链的所有级别是否都需要ConfigureAwait(false)?

    在 Azure Document Db Client SDK 之上实现可重用适配器类型的库 该库可以在任何地方运行 不仅可以在 ASP NET Core Web 服务中运行 还可以在命令行应用程序 ASP NET Web Api 等中运行
  • R 中的 Unicode 变量名称

    我正在开发一个玩具项目 并尝试使用一些 unicode 变量名称来匹配我试图实现的论文 以下代码在 Windows 上的 R 3 4 3 RStudio 版本 1 1 456 和 OSX 上的 R 3 5 1 上运行良好 gt lt fun
  • 如何将 Thunderbird 扩展与 Lightning 集成

    我目前正在为一个项目进行初步研究 如果可行的话 该项目将包含带有 Lightning 集成的 Thunderbird 扩展 我的问题是这样的 如何使用 Thunderbird 扩展以编程方式更改 Lightning 中的 CSS 具体来说
  • Rails 2.3.9 查询参数的编码

    是否可以让rails 将查询参数解码为utf8 如果我有类似 foo param 的东西 我尝试访问控制器中的参数 该参数被编码为 ASCII 8BIT 这会导致很多事情被破坏 因为我们的许多其他字符串都是用 UTF 8 编码的 而 rub
  • 获得授权属性的许可?

    我已经实现了我自己的Authorize属性 我注意到当我使用时它会查询以检查权限 Authorize 有什么方法可以获取该权限并在应用该权限的当前控制器中使用它Authorize属性而无需重写和重新查询控制器中的代码 是的你可以 如果您将
  • iOS 8 下不显示键盘

    当专注于我的应用程序的文本字段时 它们都无法调出键盘 我无法输入任何字母 不过iOS 8之前还可以 我尝试旋转屏幕 发现键盘显示在屏幕范围之外 检查视图框架 它是1024 768 似乎是正确的 最后发现是模拟器的问题 不是iOS 8的bug
  • 无法转换为尺寸:膨胀布局时类型=0x1 [重复]

    这个问题在这里已经有答案了 我的 XML 文件
  • 正则表达式 - 如何用 PHP 替换字符串的最后 3 个单词

    尝试将最后 3 个单词封装在 span tag str Lorem ipsum dolor sit amet h2 preg replace w s w s w span 1 span str 这里是 h2 preg replace w s
  • 使用 Pyspark 进行虚拟编码 [重复]

    这个问题在这里已经有答案了 我希望使用 Pyspark 语法将分类变量虚拟编码为数值变量 如下图所示 我读入这样的数据 data sqlContext read csv data txt sep header true 在 python 中
  • 是否需要通过 TCP 进行应用程序级重传和确认?

    我有以下疑问 1 TCP 是否保证数据包的传送 因此如果使用的传输协议是 TCP 则是否需要应用程序级重传 假设我已经在客户端和服务器之间建立了 TCP 连接 并且服务器向客户端发送消息 然而 客户端离线并仅在 10 小时后返回 那么 TC
  • 为管理仪表板创建私有路由时出错

    我尝试使用下面的代码来私有路由管理仪表板 我正在使用react router dom 6 2 2 我需要帮助来找出只能由管理员访问的私人路线 我尝试了 stackoverflow 中所有现有的解决方案 app js
  • 打字稿错误属性在类型上不存在

    我是 angularjs 2 和 ionic 2 的新手 我正在使用带有 Validators FormControl 和 FormGroup 的 angularjs 表单 当我使用 ionicserve lab 执行项目时 一切都很好 但
  • qt 错误:未定义对“线程 vtable”的引用

    我有代码 include
  • 如何通过 System.setProperty() 启动多个版本的 Geckodriver

    我不知道我是否在监督某些事情 但是是否可以在同一个 JVM 中使用多个 geckodriver 版本 问题在于 System setProperty webdriver gecko driver path of the geckodrive
  • 将 scrapy 项目导出到不同的文件

    我正在从 moocs 上抓取评论 就像这样one 从那里我可以获取所有课程详细信息 其中 5 个项目和每个评论本身的另外 6 个项目 这是我的课程详细信息的代码 def parse reviews self response l ItemL
  • 如何以编程方式区分箭头函数和常规函数?

    之间没有明显的区别箭头函数 and a 常规功能 toString call function object Function toString call gt object Function or console dir function
  • 无法从上下文对象继承?

    我试图创建一个继承自上下文对象的对象 但是在从我继承的对象调用函数时 浏览器 Chrome 声明未捕获的类型错误 非法调用 这是基本代码 http jsfiddle net adrianh BKYfv 1 var c document ge