Can't inherit from a context object?

I tried to create an object that inherits from the context object. But after calling the function from the object that I inherit from, the browser (Chrome) points to Uncopy TypeError: Illegal call . Here is the basic code:

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");

Why is this failing?

Bypass

I wrote a function makeForwardingObject()that does what I want. You can find it 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 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();
+3
source share
1 answer

, canvas . CanvasRenderingContext2d() ( DOM) Type error: "Illegal constructor", factory. .getContext() .

RenderingContext2d ,

ctx2=Object.create(CanvasRenderingContext2D.prototype);

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 WebGLRenderingContext , . , , , - 2 - .

+2

Source: https://habr.com/ru/post/1608406/


All Articles