翻译日期: 2014年02月07日
翻译人员: 铁锚!!!!!!!!草稿版本的翻译完成以后,无意中搜索发现了另外一篇翻译,也是同一篇原文,比我翻译的好。 justjavac,迷渡是我很尊敬的一位前辈, 链接如下:javascript 中的 delete
虽然说花了2个星期,进度也不理想,但是至少知道自己还有很多差距,也算是值得的。
教训就是以后做翻译绝对要先搜索一些关键字.
说明: 在本文中,将 property 统一翻译为属性,而将 attribute翻译为特性. 比如eval.length,其中 length 就是 eval函数(引用)的一个属性,但是 length这个属性又拥有一些特性,比如 不可删除,不可修改等.>>> var sum = function(a, b) {return a + b;} >>> var add = sum; >>> delete sum true >>> typeof sum; "undefined"忽略缺少的分号,你能发现这段代码有什么问题吗?当然,问题是,删除 sum 变量不应该成功; delete 语句不应返回 true ,而且 typeof sum 也不应返回“undefined”.因为在 Javascript 中删除变量是不可能的.至少在这种声明方式下不能.
var o = { x: 1 }; delete o.x; // true o.x; // undefined但不能删除变量,比如以下面这种方式声明的:
var x = 1; delete x; // false x; // 1也不能删除函数,比如下面所定义的:
function x(){} delete x; // false typeof x; // "function"注意 如果某个属性不能被删除的话,delete操作会返回false.
/* 当在全局范围时, `this` 指向的就是 global object */ var GLOBAL_OBJECT = this; var foo = 1; GLOBAL_OBJECT.foo; // 1 foo === GLOBAL_OBJECT.foo; // true function bar(){} typeof GLOBAL_OBJECT.bar; // "function" GLOBAL_OBJECT.bar === bar; // trueOK,全局变量成为了全局对象的属性,但局部变量(在函数内部声明)又是如何处理的呢?实际上是非常相似的: 他们成为 Variable 对象的属性(properties).唯一的区别是,当在函数代码中时,Variable 对象并不是全局对象,而是一个称为Activation object 的对象.每次进入函数的执行上下文时都会创建一个 Activation object 对象.
(function(foo){ var bar = 2; function baz(){} /* 以抽象虚拟的说法, 专有的 `arguments` 对象成为对应函数 Activation 对象的一个属性(property): ACTIVATION_OBJECT.arguments; // Arguments 对象 ...当然,参数 `foo`也是一样的道理: ACTIVATION_OBJECT.foo; // 1 ...同时,局部变量 `bar`同样如此: ACTIVATION_OBJECT.bar; // 2 ...定义的局部函数也是如此: typeof ACTIVATION_OBJECT.baz; // "function" */ })(1);最后,在 Eval 代码内声明的变量被创建为调用上下文 Variable object 对象的属性.简言之,Eval代码在哪里被调用,内部的变量就相当于在哪里被声明:
var GLOBAL_OBJECT = this; /* 此处eval内的`foo` 被创建为 调用上下文 Variable 对象的属性, 在此处上下文对象即为全局对象 Global object */ eval(‘var foo = 1;‘); GLOBAL_OBJECT.foo; // 1 (function(){ /* `bar` 被创建为 调用上下文 Variable object 对象的一个属性, 此处 Variable object 对象是包含的function的一个 Activation 对象 */ eval(‘var bar = 1;‘); /* 以一种虚拟抽象的角度看, ACTIVATION_OBJECT.bar; // 1 */ })();
var GLOBAL_OBJECT = this; /* `foo` 是 Global object 的一个 property. 是通过变量声明创建的,因此拥有 DontDelete 标志. 这就是为什么不能被删除的原因. */ var foo = 1; delete foo; // false typeof foo; // "number" /* `bar` 是 Global object 的一个 property. 是通过 function 声明创建的,因此拥有 DontDelete 标志. 这也是为什么不能被删除的原因. */ function bar(){} delete bar; // false typeof bar; // "function" /* `baz` 同样是 Global object 的一个 property. 但是通过 property 赋值创建的,However,因此没有 DontDelete 标志. 这是为什么可以被删除的原因. */ GLOBAL_OBJECT.baz = ‘blah‘; delete GLOBAL_OBJECT.baz; // true typeof GLOBAL_OBJECT.baz; // "undefined"
(function(){ /* 不能删除 `arguments`,因为其拥有 DontDelete */ delete arguments; // false typeof arguments; // "object" /* 不能删除 function 的 `length`; it also has DontDelete */ function f(){} delete f.length; // false typeof f.length; // "number" })();对应于 function参数的 properties 创建时也被赋予了 DontDelete 标志,所以也不能被删除:
(function(foo, bar){ delete foo; // false foo; // 1 delete bar; // false bar; // ‘blah‘ })(1, ‘blah‘);
var GLOBAL_OBJECT = this; /* 通过变量声明 而创建的全局 property; 拥有 DontDelete 标志*/ var foo = 1; /* 通过未声明赋值创建的 global property; 没有 DontDelete 标志*/ bar = 2; delete foo; // false typeof foo; // "number" delete bar; // true typeof bar; // "undefined"注意, attributes 是在 property 创建期间决定的(即便什么也没有设置).以后的赋值不会修改已存在property的attributes.理解这个区别是很重要的.
/* `foo` is created as a property with DontDelete */ function foo(){} /* Later assignments do not modify attributes. DontDelete is still there! */ foo = 1; delete foo; // false typeof foo; // "number" /* But assigning to a property that doesn‘t exist, creates that property with empty attributes (因此没有 DontDelete 标志) */ this.bar = 1; delete bar; // true typeof bar; // "undefined"
eval(‘var foo = 1;‘); foo; // 1 delete foo; // true typeof foo; // "undefined"同样,当在函数内部调用Eval代码时:
(function(){ eval(‘var foo = 1;‘); foo; // 1 delete foo; // true typeof foo; // "undefined" })();
function x(){ } var x; // 只声明 typeof x; // "function" function a(){ } var a = 6; // 声明 + 赋值 typeof a; // "number"注意,函数声明优先并覆盖same-named(同名的)变量(或者,换句话说,Variable 对象的同一个property ).这是因为 function 声明在变量声明之后 实例化,并允许覆盖它们.函数声明不仅取代 property的前一个值,它也取代该 property 的特性(attributes).如果我们通过eval声明 function,该函数也应该用自己的替换该 property的attributes .由于在eval中声明的变量所创建的 properties 没有DontDelete标志,实例化这个新函数本质上应该移除property 现有的DontDelete属性,以使 移除property 可以被删除(当然,肯定也要让其指向新创建的函数).
var x = 1; /* 不能删除, `x` has DontDelete */ delete x; // false typeof x; // "number" eval(‘function x(){}‘); /* `x` property 现在指向 function, 并且没有 DontDelete 标志*/ typeof x; // "function" delete x; // 按理说应该是 `true` typeof x; // 按理说应该是 "undefined"不幸的是,在我测试的所有实现环境中,这种欺骗都不会生效.我可能在这里说错了什么东西,或这种行为太晦涩了,以至于实现者不去关注.
function foo(){} delete foo; // false (符合预期) typeof foo; // "function" (符合预期) /* 现在显示地给一个 property 赋值*/ this.foo = 1; // 错误地清除了 DontDelete 特性 delete foo; // true typeof foo; // "undefined" /* 注意当隐式地给 property 赋值时并不会发生 */ function bar(){} bar = 1; delete bar; // false typeof bar; // "number" (赋值操作替换了 property)令人惊讶的是,Internet Explorer 5.5 - 8 完全通过了测试套件的测试,除了删除非引用(例如 detele 1;)会抛出错误以外(就像在更古老的Safari中一样).但在IE中实际上有更严重的bugs,这些bug不会立即显示出来.这些缺陷是与全局对象有关的.
this.x = 1; delete x; // TypeError: Object doesn‘t support this action下面的也是一样,但是抛出了不同的异常,事情非常的有趣:
var x = 1; delete this.x; // TypeError: Cannot delete ‘this.x‘在IE中,在全局代码声明的变量好像不会创建为全局对象上的属性.通过赋值创建属性( this.x = 1; ),然后通过 delete x; 删除它将会抛出错误. 通过声明创建属性(var x = 1;),然后使用delete this.x; 删除它却会抛出另一个错误.
this.x = 1; delete this.x; // TypeError: Object doesn‘t support this action typeof x; // "number" (still exists, wasn‘t deleted as it should have been!) delete x; // TypeError: Object doesn‘t support this action typeof x; // "number" (wasn‘t deleted again)现在,与人们的预料相反,未声明的赋值(应该在全局对象上创建一个property )在IE中却创建可删除的properties:
x = 1; delete x; // true typeof x; // "undefined"但如果你想在全局代码中通过 this引用来删除这个property (delete this.x),那么一个你熟悉的错误就会冒出来:
x = 1; delete this.x; // TypeError: Cannot delete ‘this.x‘如果我们对这种行为进行推理,会发现在全局代码执行 delete this.x; 永远不会成功.当 property 是通过显式赋值创建的(this.x = 1;),delete将会抛出一个错误;当 property 是通过未声明赋值创建的(x = 1)或通过变量声明创建(var x = 1),delete将会抛出另一个错误.
换个角度来说, delete x; 只有当 property 是通过显式赋值创建时才抛出错误——this.x = 1;.如果 property 是通过变量声明创建的(var x = 1;),删除只是简单地从不执行,并且delete 正确地返回false. 如果property 是通过未声明赋值创建的(x = 1),删除按预期方式运行.
我是 在9月份反馈这个问题 的,Garrett Smith建议在IE中 “The global variable object被实现为一个 JScript 对象,并且 global object 是由 host 来实现的".Garrett 建议参考Eric Lippert的博客 .我们可以通过执行一些测试来证实了这一理论. 注意, this 和 window 指向同一个对象(我们可以采用 === 操作符来测试),但是 Variable 对象(声明函数时的那个) 与 this 引用不同.
/* in Global code */ function getBase(){ return this; } getBase() === this.getBase(); // false this.getBase() === this.getBase(); // true window.getBase() === this.getBase(); // true window.getBase() === getBase(); // false
/* "alert" 是 `window` 的一个 direct property (如果我们采信 `hasOwnProperty` 的话) */ window.hasOwnProperty(‘alert‘); // true delete window.alert; // true typeof window.alert; // "function"
var element = document.createElement(‘div‘) delete element.onclick; // throws "Object doesn‘t support this action" document.body.x = 1; delete document.body.x; // throws "Object doesn‘t support this action" // in IE8 delete XMLHttpRequest.prototype.open; // throws "Object doesn‘t support this action"
(function(foo){ "use strict"; // 在此函数内使用 strict mode var bar; function baz(){} delete foo; // SyntaxError (when deleting argument) delete bar; // SyntaxError (when deleting variable) delete baz; // SyntaxError (when deleting variable created with function declaration) /* 函数实例的 `length`属性拥有 { [[Configurable]] : false } */ delete (function(){}).length; // TypeError })();此外,删除未声明的变量(或者换句话说,未解决的引用)也会抛出语法错误:
"use strict"; delete i_dont_exist; // SyntaxError这有点类似于在严格模式下的未声明赋值的行为(除了抛出的是 ReferenceError 而不是SyntaxError以外):
"use strict"; i_dont_exist = 1; // ReferenceError你现在明白,所有这些限制的意义,给删除变量,函数声明和参数 导致了多少混乱的原因.
我希望你喜欢这个概述并学到一些新东西.一如既往地欢迎任何问题,建议和修正.
原文:http://blog.csdn.net/renfufei/article/details/18965545