public function jsRender()
    {
        $namelessCount = 0;

        $res = preg_replace_callback(
            '/\[[a-z0-9_]*\]|{[a-z0-9_]*}/',
            function ($matches) use (&$namelessCount) {
                $identifier = substr($matches[0], 1, -1);

                // Allow template to contain []
                if ($identifier === '') {
                    $identifier = $namelessCount++;
                }

                if (!isset($this->args[$identifier])) {
                    throw new Exception([
                        'Tag not defined in template for jsExpression',
                        'tag'      => $identifier,
                        'template' => $this->template,
                    ]);
                }

                $value = $this->args[$identifier];

                // No escaping for {}
                if ($matches[0][0] === '{') {
                    return $value;
                }

                if (is_object($value) && $value instanceof jsExpressionable) {
                    $value = '('.$value->jsRender().')';
                } elseif (is_object($value)) {
                    $value = $this->_json_encode($value->toString());
                } else {
                    $value = $this->_json_encode($value);
                }

                return $value;
            },
            $this->template
        );

        return trim($res);
    }