mirror of
https://github.com/denoland/deno.git
synced 2025-02-01 20:25:12 -05:00
avoid prototype builtin hasOwnProperty (#2144)
This commit is contained in:
parent
2be7e44403
commit
d0cd7a39a2
6 changed files with 74 additions and 7 deletions
|
@ -1,6 +1,6 @@
|
|||
// Copyright 2018-2019 the Deno authors. All rights reserved. MIT license.
|
||||
import * as domTypes from "./dom_types";
|
||||
import { containsOnlyASCII } from "./util";
|
||||
import { containsOnlyASCII, hasOwnProperty } from "./util";
|
||||
import { TextEncoder } from "./text_encoding";
|
||||
|
||||
export const bytesSymbol = Symbol("bytes");
|
||||
|
@ -91,7 +91,7 @@ export class DenoBlob implements domTypes.Blob {
|
|||
|
||||
options = options || {};
|
||||
// Set ending property's default value to "transparent".
|
||||
if (!options.hasOwnProperty("ending")) {
|
||||
if (!hasOwnProperty(options, "ending")) {
|
||||
options.ending = "transparent";
|
||||
}
|
||||
|
||||
|
|
|
@ -32,4 +32,22 @@ test(function blobSlice() {
|
|||
assertEquals(b4.size, blob.size);
|
||||
});
|
||||
|
||||
test(function blobShouldNotThrowError() {
|
||||
let hasThrown = false;
|
||||
|
||||
try {
|
||||
const options1: object = {
|
||||
ending: "utf8",
|
||||
hasOwnProperty: "hasOwnProperty"
|
||||
};
|
||||
const options2: object = Object.create(null);
|
||||
new Blob(["Hello World"], options1);
|
||||
new Blob(["Hello World"], options2);
|
||||
} catch {
|
||||
hasThrown = true;
|
||||
}
|
||||
|
||||
assertEquals(hasThrown, false);
|
||||
});
|
||||
|
||||
// TODO(qti3e) Test the stored data in a Blob after implementing FileReader API.
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
// Forked from Node's lib/internal/cli_table.js
|
||||
|
||||
import { TextEncoder } from "./text_encoding";
|
||||
import { hasOwnProperty } from "./util";
|
||||
|
||||
const encoder = new TextEncoder();
|
||||
|
||||
|
@ -64,7 +65,7 @@ export function cliTable(head: string[], columns: string[][]): string {
|
|||
if (rows[j] === undefined) {
|
||||
rows[j] = [];
|
||||
}
|
||||
const value = (rows[j][i] = column.hasOwnProperty(j) ? column[j] : "");
|
||||
const value = (rows[j][i] = hasOwnProperty(column, j) ? column[j] : "");
|
||||
const width = columnWidths[i] || 0;
|
||||
const counted = countBytes(value);
|
||||
columnWidths[i] = Math.max(width, counted);
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
// Copyright 2018-2019 the Deno authors. All rights reserved. MIT license.
|
||||
import * as domTypes from "./dom_types";
|
||||
import { requiredArguments } from "./util";
|
||||
import { requiredArguments, hasOwnProperty } from "./util";
|
||||
|
||||
/* TODO: This is an incomplete implementation to provide functionality
|
||||
* for Event. A proper spec is still required for a proper Web API.
|
||||
|
@ -16,7 +16,7 @@ export class EventTarget implements domTypes.EventTarget {
|
|||
_options?: boolean | domTypes.AddEventListenerOptions
|
||||
): void {
|
||||
requiredArguments("EventTarget.addEventListener", arguments.length, 2);
|
||||
if (!this.listeners.hasOwnProperty(type)) {
|
||||
if (!hasOwnProperty(this.listeners, type)) {
|
||||
this.listeners[type] = [];
|
||||
}
|
||||
if (listener !== null) {
|
||||
|
@ -30,7 +30,7 @@ export class EventTarget implements domTypes.EventTarget {
|
|||
_options?: domTypes.EventListenerOptions | boolean
|
||||
): void {
|
||||
requiredArguments("EventTarget.removeEventListener", arguments.length, 2);
|
||||
if (this.listeners.hasOwnProperty(type) && callback !== null) {
|
||||
if (hasOwnProperty(this.listeners, type) && callback !== null) {
|
||||
this.listeners[type] = this.listeners[type].filter(
|
||||
listener => listener !== callback
|
||||
);
|
||||
|
@ -39,7 +39,7 @@ export class EventTarget implements domTypes.EventTarget {
|
|||
|
||||
public dispatchEvent(event: domTypes.Event): boolean {
|
||||
requiredArguments("EventTarget.dispatchEvent", arguments.length, 1);
|
||||
if (!this.listeners.hasOwnProperty(event.type)) {
|
||||
if (!hasOwnProperty(this.listeners, event.type)) {
|
||||
return true;
|
||||
}
|
||||
const stack = this.listeners[event.type].slice();
|
||||
|
|
|
@ -92,3 +92,21 @@ test(function toStringShouldBeWebCompatibility() {
|
|||
const target = new EventTarget();
|
||||
assertEquals(target.toString(), "[object EventTarget]");
|
||||
});
|
||||
|
||||
test(function dispatchEventShouldNotThrowError() {
|
||||
let hasThrown = false;
|
||||
|
||||
try {
|
||||
const target = new EventTarget();
|
||||
const event = new Event("hasOwnProperty", {
|
||||
bubbles: true,
|
||||
cancelable: false
|
||||
});
|
||||
target.addEventListener("hasOwnProperty", () => {});
|
||||
target.dispatchEvent(event);
|
||||
} catch {
|
||||
hasThrown = true;
|
||||
}
|
||||
|
||||
assertEquals(hasThrown, false);
|
||||
});
|
||||
|
|
30
js/util.ts
30
js/util.ts
|
@ -142,3 +142,33 @@ export function getPrivateValue<
|
|||
}
|
||||
throw new TypeError("Illegal invocation");
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines whether an object has a property with the specified name.
|
||||
* Avoid calling prototype builtin `hasOwnProperty` for two reasons:
|
||||
*
|
||||
* 1. `hasOwnProperty` is defined on the object as something else:
|
||||
*
|
||||
* const options = {
|
||||
* ending: 'utf8',
|
||||
* hasOwnProperty: 'foo'
|
||||
* };
|
||||
* options.hasOwnProperty('ending') // throws a TypeError
|
||||
*
|
||||
* 2. The object doesn't inherit from `Object.prototype`:
|
||||
*
|
||||
* const options = Object.create(null);
|
||||
* options.ending = 'utf8';
|
||||
* options.hasOwnProperty('ending'); // throws a TypeError
|
||||
*
|
||||
* @param obj A Object.
|
||||
* @param v A property name.
|
||||
* @see https://eslint.org/docs/rules/no-prototype-builtins
|
||||
* @internal
|
||||
*/
|
||||
export function hasOwnProperty<T>(obj: T, v: PropertyKey): boolean {
|
||||
if (obj == null) {
|
||||
return false;
|
||||
}
|
||||
return Object.prototype.hasOwnProperty.call(obj, v);
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue