delete-basic.js 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243
  1. test("deleting object properties", () => {
  2. const o = {};
  3. o.x = 1;
  4. o.y = 2;
  5. o.z = 3;
  6. expect(Object.getOwnPropertyNames(o)).toHaveLength(3);
  7. expect(delete o.x).toBeTrue();
  8. expect(o.hasOwnProperty("x")).toBeFalse();
  9. expect(o.hasOwnProperty("y")).toBeTrue();
  10. expect(o.hasOwnProperty("z")).toBeTrue();
  11. expect(Object.getOwnPropertyNames(o)).toHaveLength(2);
  12. expect(delete o.y).toBeTrue();
  13. expect(o.hasOwnProperty("x")).toBeFalse();
  14. expect(o.hasOwnProperty("y")).toBeFalse();
  15. expect(o.hasOwnProperty("z")).toBeTrue();
  16. expect(Object.getOwnPropertyNames(o)).toHaveLength(1);
  17. expect(delete o.z).toBeTrue();
  18. expect(o.hasOwnProperty("x")).toBeFalse();
  19. expect(o.hasOwnProperty("y")).toBeFalse();
  20. expect(o.hasOwnProperty("z")).toBeFalse();
  21. expect(Object.getOwnPropertyNames(o)).toHaveLength(0);
  22. });
  23. test("deleting array indices", () => {
  24. const a = [3, 5, 7];
  25. expect(Object.getOwnPropertyNames(a)).toHaveLength(4);
  26. expect(delete a[0]).toBeTrue();
  27. expect(a.hasOwnProperty(0)).toBeFalse();
  28. expect(a.hasOwnProperty(1)).toBeTrue();
  29. expect(a.hasOwnProperty(2)).toBeTrue();
  30. expect(Object.getOwnPropertyNames(a)).toHaveLength(3);
  31. expect(delete a[1]).toBeTrue();
  32. expect(a.hasOwnProperty(0)).toBeFalse();
  33. expect(a.hasOwnProperty(1)).toBeFalse();
  34. expect(a.hasOwnProperty(2)).toBeTrue();
  35. expect(Object.getOwnPropertyNames(a)).toHaveLength(2);
  36. expect(delete a[2]).toBeTrue();
  37. expect(a.hasOwnProperty(0)).toBeFalse();
  38. expect(a.hasOwnProperty(1)).toBeFalse();
  39. expect(a.hasOwnProperty(2)).toBeFalse();
  40. expect(Object.getOwnPropertyNames(a)).toHaveLength(1);
  41. expect(delete a["42"]).toBeTrue();
  42. expect(Object.getOwnPropertyNames(a)).toHaveLength(1);
  43. });
  44. test("deleting non-configurable property", () => {
  45. const q = {};
  46. Object.defineProperty(q, "foo", { value: 1, writable: false, enumerable: false });
  47. expect(q.foo).toBe(1);
  48. expect(delete q.foo).toBeFalse();
  49. expect(q.hasOwnProperty("foo")).toBeTrue();
  50. });
  51. test("deleting non-configurable property throws in strict mode", () => {
  52. "use strict";
  53. const q = {};
  54. Object.defineProperty(q, "foo", { value: 1, writable: false, enumerable: false });
  55. expect(q.foo).toBe(1);
  56. expect(() => {
  57. delete q.foo;
  58. }).toThrowWithMessage(TypeError, "Cannot delete property 'foo' of [object Object]");
  59. expect(q.hasOwnProperty("foo")).toBeTrue();
  60. });
  61. test("deleting super property", () => {
  62. class A {
  63. foo() {}
  64. }
  65. class B extends A {
  66. bar() {
  67. delete super.foo;
  68. }
  69. baz() {
  70. delete super["foo"];
  71. }
  72. }
  73. const obj = new B();
  74. expect(() => {
  75. obj.bar();
  76. }).toThrowWithMessage(ReferenceError, "Can't delete a property on 'super'");
  77. expect(() => {
  78. obj.baz();
  79. }).toThrowWithMessage(ReferenceError, "Can't delete a property on 'super'");
  80. });
  81. test("deleting an object computed property coerces the object to a property key", () => {
  82. let called = false;
  83. const obj = { prop1: 1, 2: 2 };
  84. function createToPrimitiveFunction(object, valueToReturn) {
  85. return function (hint) {
  86. called = true;
  87. console.log(this, object);
  88. expect(this).toBe(object);
  89. expect(hint).toBe("string");
  90. return valueToReturn;
  91. };
  92. }
  93. const a = {
  94. [Symbol.toPrimitive]: function (hint) {
  95. called = true;
  96. expect(this).toBe(a);
  97. expect(hint).toBe("string");
  98. return "prop1";
  99. },
  100. };
  101. const b = {
  102. [Symbol.toPrimitive]: function (hint) {
  103. called = true;
  104. expect(this).toBe(b);
  105. expect(hint).toBe("string");
  106. return 2;
  107. },
  108. };
  109. const c = {
  110. [Symbol.toPrimitive]: function (hint) {
  111. called = true;
  112. expect(this).toBe(c);
  113. expect(hint).toBe("string");
  114. return {};
  115. },
  116. };
  117. expect(Object.hasOwn(obj, "prop1")).toBeTrue();
  118. expect(Object.hasOwn(obj, 2)).toBeTrue();
  119. expect(delete obj[a]).toBeTrue();
  120. expect(called).toBeTrue();
  121. expect(Object.hasOwn(obj, "prop1")).toBeFalse();
  122. expect(Object.hasOwn(obj, 2)).toBeTrue();
  123. expect(obj.prop1).toBeUndefined();
  124. expect(obj[2]).toBe(2);
  125. called = false;
  126. expect(delete obj[b]).toBeTrue();
  127. expect(called).toBeTrue();
  128. expect(Object.hasOwn(obj, "prop1")).toBeFalse();
  129. expect(Object.hasOwn(obj, 2)).toBeFalse();
  130. expect(obj.prop1).toBeUndefined();
  131. expect(obj[2]).toBeUndefined();
  132. called = false;
  133. expect(() => {
  134. delete obj[c];
  135. }).toThrowWithMessage(
  136. TypeError,
  137. `Can't convert [object Object] to primitive with hint "string", its @@toPrimitive method returned an object`
  138. );
  139. expect(called).toBeTrue();
  140. });
  141. // FIXME: This currently does not work as it trys to coerce the returned Symbol to a String. I'm not sure why this is.
  142. test.skip("deleting a symbol returned by @@toPrimitive", () => {
  143. let called = false;
  144. const obj = { [Symbol.toStringTag]: "hello world" };
  145. const a = {
  146. [Symbol.toPrimitive]: function (hint) {
  147. called = true;
  148. expect(this).toBe(a);
  149. expect(hint).toBe("string");
  150. return Symbol.toStringTag;
  151. },
  152. };
  153. expect(Object.hasOwn(obj, Symbol.toStringTag)).toBeTrue();
  154. expect(delete obj[a]).toBeTrue();
  155. expect(called).toBeTrue();
  156. expect(Object.hasOwn(obj, Symbol.toStringTag)).toBeFalse();
  157. expect(obj[Symbol.toStringTag]).toBeUndefined();
  158. });
  159. // FIXME: This currently does not work with the AST interpreter, but works with Bytecode.
  160. test.skip("delete always evaluates the lhs", () => {
  161. const obj = { prop: 1 };
  162. let called = false;
  163. function a() {
  164. called = true;
  165. return obj;
  166. }
  167. expect(delete a()).toBeTrue();
  168. expect(called).toBeTrue();
  169. expect(obj).toBeDefined();
  170. expect(Object.hasOwn(obj, "prop")).toBeTrue();
  171. expect(obj.prop).toBe(1);
  172. called = false;
  173. expect(delete a().prop).toBeTrue();
  174. expect(called).toBeTrue();
  175. expect(obj).toBeDefined();
  176. expect(Object.hasOwn(obj, "prop")).toBeFalse();
  177. expect(obj.prop).toBeUndefined();
  178. let b = 1;
  179. expect(delete ++b).toBeTrue();
  180. expect(b).toBe(2);
  181. expect(delete b++).toBeTrue();
  182. expect(b).toBe(3);
  183. let c = { d: 1 };
  184. expect(delete (b = c)).toBeTrue();
  185. expect(b).toBeDefined();
  186. expect(c).toBeDefined();
  187. expect(b).toBe(c);
  188. function d() {
  189. throw new Error("called");
  190. }
  191. expect(() => {
  192. delete d();
  193. }).toThrowWithMessage(Error, "called");
  194. expect(() => {
  195. delete d().stack;
  196. }).toThrowWithMessage(Error, "called");
  197. expect(() => {
  198. delete ~d();
  199. }).toThrowWithMessage(Error, "called");
  200. expect(() => {
  201. delete new d();
  202. }).toThrowWithMessage(Error, "called");
  203. });