IE8中是否支持JavaScript getter?

13

看看这段代码。 这是一个非常简单的JavaScript对象,使用模块模式实现的(您可以在此jsfiddle地址上查看实时示例)

var human = function() {
    var _firstName = '';
    var _lastName = ''
    return {
        get firstName() {
            return _firstName;
        }, get lastName() {
            return _lastName;
        }, set firstName(name) {
            _firstName = name;
        }, set lastName(name) {
            _lastName = name;
        }, get fullName() {
            return _firstName + ' ' + _lastName;
        }
    }
}();
human.firstName = 'Saeed';
human.lastName = 'Neamati';
alert(human.fullName);

然而,IE8不支持JavaScript中的getset关键字。你可以进行测试并查看MDN

我该怎么做才能使这个脚本在IE8下也兼容呢?

4个回答

24

如何让这个脚本在IE8上兼容?

需要完全改变它。例如,不要使用访问器属性,而是使用普通属性和函数的组合:

human.firstName = 'Saeed';
human.lastName  = 'Neamati';
alert(human.getFullName());

有人建议在IE中使用DOM对象并使用Object.defineProperty()添加属性。虽然这可能有效,但出于几个原因,我强烈建议不要采用这种方法,其中一个例子是你编写的代码可能不兼容所有浏览器:

var human = document.createElement('div');
Object.defineProperty(human, 'firstName', { ... });
Object.defineProperty(human, 'lastName',  { ... });
Object.defineProperty(human, 'children',  { value: 2 });

alert(human.children);
//-> "[object HTMLCollection]", not 2

至少在Chrome中是这样的。无论如何,编写能够跨越所有你想要支持的浏览器的代码更为安全和易于实现。尽管使用getter和setter编写代码可以带来方便,但是你所写的特定于Internet Explorer 8的额外代码已经让这种方便丧失了作用。

当然,除了性能降低之外,你还不能在对象上使用for...in循环,而且当你使用一个你认为已定义但在DOM对象上已经预先存在的属性时可能会导致混淆。


我的意思是如何使我的代码向后兼容。如何在JavaScript中实现一个模块模式,可以在IE8中工作,并且具有getter属性的解决方案是什么? - Saeed Neamati
1
@SaeedNeamati 如果你真的想要getter/setter,你可以做两件事:1)创建像.getMyValue.setMyValue这样的方法,或者2)创建接受值的方法,如果没有给出值则返回它(就像jQuery在某些方法中所做的那样-如果你提供一个值,它会设置它,如果你不提供一个值,它会获取)。 - Camilo Martin
@DontVoteMeDown:很抱歉你有这样的感受,但我相信还有更糟糕的答案。你知道,像是错误的答案;-)。 - Andy E
@BT:不,这是不正确的。我的回答表明“非DOM对象无法拥有getter和setter方法”。请告诉我你是如何发现这是错误的,因为你的回答只证明了它是正确的。 - Andy E
我想我误读了你的回答,认为它是“根本不可能”,因为它写得很差,无法传达在DOM对象上使用访问器是可能的。我的回答告诉他如何“使此脚本与IE8兼容”,但你的回答没有。 - B T
2
@BT:撇开你试图将你的阅读理解能力差归咎于我的回答措辞不当,我想指出的是,提问者对这个回答感到满意。虽然我可以推广你自己回答中所指出的不良实践,但我觉得这并不是任何有自尊心的JavaScript开发者会使用的解决方案,更不用鼓励他人使用。有时,对于每个人来说,认识到“我必须以其他方式来处理这个问题”是最好的。 - Andy E

8

您无法(如Andy所回答的那样

最接近的替代方案是

var human = function() {
    var _firstName = '';
    var _lastName = '';

    return {
        firstName: function() {
            if (arguments.length === 1) {
                _firstName = arguments[0];
            }
            else {
                return _firstName;
            }
        },
        lastName: function() {
            if (arguments.length === 1) {
                _lastName = arguments[0];
            }
            else {
                return _lastName;
            }
        },
        fullName: function() {
            return _firstName + ' ' + _lastName;
        }
    };
}();

human.firstName('Saeed');
human.lastName('Neamati');

alert(human.fullName());

演示在http://jsfiddle.net/gaby/WYjqB/2/


IE总是很烂。虽然微软有很多好的产品,但我真的讨厌微软,只因为它的IE。 - Saeed Neamati
1
@Saeed:实际上,这并不是微软的错。获取器和设置器是ECMA-262规范的最新补充。IE 9通过Object.defineProperty()支持获取器和设置器。你正在使用的实现(Mozilla的)是非标准的,并且在许多浏览器中不能保证正常工作。 - Andy E
1
但是 @Gaby,Firefox 从版本2.0开始支持此功能,Chrome从版本1开始支持,Safari从版本3.5开始支持,Opera从版本9.5开始支持。那么,为什么IE8不能支持这样的东西呢? - Saeed Neamati
3
同样的原因,Firefox不支持element.innerTextbackground-position-x或许多其他Internet Explorer专有的功能,而这些功能Chrome和其他浏览器早就支持了。 - Andy E

5

IE8支持在DOM节点上使用getter和setter,因此如果您真的想要使用getter和setter,可以这样做:

var objectForIe8 = $("<div></div>")[0];    
Object.defineProperty(objectForIe8, "querySelector", {
    get: function() {
        return this.name;
    },
    set: function(val) {
        this.name = val+", buddy";  
    }
});
// notice you can overwrite dom properties when you want to use that property name
objectForIe8.querySelector = "I'm not your guy"; 

alert(objectForIe8.querySelector);

请注意,这会显著影响性能,因此如果您需要创建成千上万个类似的对象,则不应使用此技术。但是,如果您不担心特定对象的性能,那么这将勉强可以使用。如果您不关心ie8的性能,只希望它正常工作,请仅在ie8中使用此技术即可 : )

1
这种方法存在几个问题,使其过于复杂,不值得。例如,原型继承被抛弃,你提到的对象创建性能问题,可能的命名冲突等等。它远非“黄金法则”。 - Andy E
2
虽然这并不是一个完美的解决方案(在使用IE时也很难达到),但实际上答案已经得到了回答... - B T
2
谢谢。我所需要的只是一个简洁而简单的类来存储/检索会话期间的值。这使得我在需要时能够轻松地声明和使用属性。 - gouderadrian
这是一个解决IE 8的好方法,也是在非DOM对象上实现本地getter/setter的唯一真正方式。虽然在紧急情况下效果很好,但除非您对每个浏览器使用相同的技术和相同的限制,否则它不是跨平台的。否则,您需要使用单独的“对象”和“objectForIe8”,这将破坏最初的方便尝试,而不必采用自定义的get/set函数。换句话说,任何试图以这种方式使优雅、通用函数运作的人,都没有必要了;我已经尝试过了。 - Beejor

4
请查看http://robertnyman.com/2009/05/28/getters-and-setters-with-javascript-code-samples-and-demos/了解如何通过Object.defineProperty扩展对象。这是Internet Explorer实现getter和setter的标准方法,但遗憾的是迄今为止只有Internet Explorer 8支持,在其他任何Web浏览器中都不支持。另外,IE 8仅支持在DOM节点上使用它,但将来版本计划支持在JavaScript对象上使用它。您可以在同一网站上找到测试用例:http://robertnyman.com/javascript/javascript-getters-setters.html#object-defineproperty
Object.defineProperty(document.body, "description", {
    get : function () {
        return this.desc;
    },
    set : function (val) {
        this.desc = val;
    }
});
document.body.description = "Content container";

结果:

document.body.description = "Content container"

修正了结果。 - Bob Yang

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