JavaScript Object.create 和 IE8

6
我正在为SharePoint 2013进行软件开发。其中一部分涉及覆盖SharePoint的文件预览程序(filepreview.debug.js变成myfilepreview.debug.js)。然而,我们在IE8中遇到了问题。在IE9中,一切正常。
在IE8中抛出的错误会导致在我们自定义功能已激活的站点集合中访问任何站点时都会出现错误:"对象不支持此属性或方法"。
经过对此错误的一些研究,似乎IE8根本不支持Object.create。这篇Mozilla Developer文章似乎支持这个理论。当在引发错误的行之前添加这个polyfill代码时,问题得到了解决。
if (typeof Object.create !== 'function') {
    Object.create = function (o) {
        function F() { }
        F.prototype = o;
        return new F();
    };
}

我想这是有道理的,因为它模仿了Object.create的功能,而Object.create在IE8中似乎不受支持。
然而,这很令人困惑,因为SharePoint的文件预览javascript工作得非常好。他们的javascript也使用Object.create。更奇怪的是,我们的javascript中引发错误的代码部分甚至不是我们的代码——而是SharePoint的。直到那时,整个javascript代码实际上与SharePoint的完全相同,除了几行代码。
以下是默认内容,直到出现问题的那一行:
function $_global_filepreview() {
RegisterSod("mediaplayer.js", "_layouts/15/mediaplayer.js");
RegisterSod("sp.publishing.resources.resx", "/_layouts/15/ScriptResx.ashx?name=sp.publishing.resources&culture=" + STSHtmlEncode(Strings.STS.L_CurrentUICulture_Name));
RegisterSodDep("mediaplayer.js", "sp.publishing.resources.resx");
previewBase = (function() {
ULS7RK:
    ;
    var filePreviewUniqueId = 0;

    return {
        init: function(ctxT, listItem, extension) {
            this.fpId = ++filePreviewUniqueId;
            this.fpDomId = "FilePreviewID-" + String(this.fpId);
            this.fpCtx = ctxT;
            this.fpExtension = extension;
            this.fpListItem = listItem;
        },
        getHtml: function() {
        ULS7RK:
            ;
            return ['<div class="js-filePreview-containingElement" id=', StAttrQuote(this.fpDomId), '>', this.getInnerHtml(), '</div>'].join("");
        },
        getDomId: function() {
        ULS7RK:
            ;
            return this.fpDomId;
        },
        getContainingElement: function() {
        ULS7RK:
            ;
            var containingElement = document.getElementById(this.fpDomId);

            Sys.Debug.assert(m$.isElement(containingElement), "Containing element has not been rendered yet.");
            return containingElement;
        },
        canRender: function() {
        ULS7RK:
            ;
            return true;
        },
        getLoadingIndicatorHtml: function(customStyle) {
            if (m$.isUndefined(customStyle)) {
                customStyle = "";
            }
            return ['<div class="js-filePreview-loading-image" style="width:', this.getWidth(), 'px; height:', this.getHeight(), 'px; line-height:', this.getHeight(), 'px; text-align:center; vertical-align:middle; display: inline-block; ' + customStyle + '">', '<img src="', "/_layouts/15/images/gears_anv4.gif", '" />', '</div>'].join("");
        },

        hideLoadingIndicator: function() {
        ULS7RK:
            ;
            var containingElement = document.getElementById(this.fpDomId);

            ((m$(containingElement)).find("div.js-filePreview-loading-image")).css({
                display: "none"
            });
        },

        getInnerHtml: function() {
        ULS7RK:
            ;
            return "";
        },
        getWidth: function() {
        ULS7RK:
            ;
            return null;
        },
        getHeight: function() {
        ULS7RK:
            ;
            return null;
        },
        onPostRender: function() {
        },
        onVisible: function() {
        },
        onHidden: function() {
        }
    };
})();
//**This is where the "fix" was added originally**
blankPreview = Object.create(previewBase); <--- error is thrown here

我们的JavaScript代码(到目前为止)与上面的SharePoint JavaScript代码唯一的区别在于我们从开头删除了以下两行,但是将它们添加回去仍然无法解决问题:
RegisterSod("sp.publishing.resources.resx", "/_layouts/15/ScriptResx.ashx?name=sp.publishing.resources&culture=" + STSHtmlEncode(Strings.STS.L_CurrentUICulture_Name));
RegisterSodDep("mediaplayer.js", "sp.publishing.resources.resx");

所以我的问题是:为什么我在默认的JavaScript中使用同样的函数时没有问题,而在IE8中却出现了Object.create不支持的错误?
编辑:另一个论坛上的用户建议我尝试通过sod注册我的脚本。我已经将其添加到我的代码中,但没有效果。
RegisterSod("MyFilepreview.debug.js", "_layouts/15/MyFilepreview.debug.js");

1
好的,Sherlock Holmes 的做法是得出结论,其中一条线路导致类似的 shim 被导入页面。当然,如果这是真的,那么在添加这些行后失败(导致您拥有 完全相同 的代码)就没有意义了。因此,人们可能会质疑 那个 断言:这些是否真的是 唯一 的区别? - Pointy
@Pointy 确实是一个非常合理的问题。我已经进行了双重和三重检查,确实是到那个点为止唯一的区别。 - tnw
SharePoint服务器可能会进行浏览器嗅探,因此为不同的浏览器返回不同的JS文件。您是使用IE8还是其他浏览器保存了此JavaScript代码(或者是在服务器端找到的)? - molnarg
@JibiAbraham,你不能这样做,Object.create的第一个参数不是一个可以用new调用的构造函数,而是一个对象(通常是普通对象),它成为所创建对象的原型。 - Esailija
尝试将 Object.create(obj) 替换为 (function(){var F = function(){};F.prototype=obj;new F();}()) - xavierm02
显示剩余2条评论
2个回答

3
尝试在IE中进行调试,并在SharePoint的默认JavaScript文件中设置断点。您确定默认JavaScript文件中的Object.create实例实际上被触发了吗?

3

他们没有使用正确的参数来使用Object.create

他们使用 Object.create({name:value}),而应该使用 Object.create({name:{value:value}})

因此,他们可能定义了自己的Object.create,并且他们的代码在你的代码之后运行,所以当他们的代码运行时,你已经设置好了你的Object.create,他们可能像你一样测试存在性,并假设存在的是他们的版本,但实际上是你的版本。

因此,请检查他们的代码中是否有Object.create的定义,并检查脚本执行的顺序。


感谢您的评论。在稍微探索一下后,我发现确实有一个SharePoint本地JavaScript文件可以执行与我相同的polyfill。使用F12调试,我可以看到它与我的文件一起加载 - 现在问题是:为什么他们的JavaScript能够识别这个文件而我的不能呢? - tnw
你有检查过在 polyfill Object.create 时它包含了什么吗?你知道它不是一个函数。试着打印一下它。或者至少打印一下它的类型。 - xavierm02
1
是第二个参数是一个属性描述符,而不是第一个。第一个是所创建对象的原型对象,Object.create({name:value}) 完全没问题。 - Esailija

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接