Skip to content

Commit 3c8a6f5

Browse files
committed
[Refactor] use __proto__ syntax instead of Object.create for null objects
1 parent 96f4d93 commit 3c8a6f5

File tree

6 files changed

+34
-28
lines changed

6 files changed

+34
-28
lines changed

README.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ assert.deepEqual(qs.parse('foo[bar]=baz'), {
4949
});
5050
```
5151

52-
When using the `plainObjects` option the parsed value is returned as a null object, created via `Object.create(null)` and as such you should be aware that prototype methods will not exist on it and a user may set those names to whatever value they like:
52+
When using the `plainObjects` option the parsed value is returned as a null object, created via `{ __proto__: null }` and as such you should be aware that prototype methods will not exist on it and a user may set those names to whatever value they like:
5353

5454
```javascript
5555
var nullObject = qs.parse('a[hasOwnProperty]=b', { plainObjects: true });

lib/parse.js

+3-3
Original file line numberDiff line numberDiff line change
@@ -132,7 +132,7 @@ var parseObject = function (chain, val, options, valuesParsed) {
132132
? []
133133
: [].concat(leaf);
134134
} else {
135-
obj = options.plainObjects ? Object.create(null) : {};
135+
obj = options.plainObjects ? { __proto__: null } : {};
136136
var cleanRoot = root.charAt(0) === '[' && root.charAt(root.length - 1) === ']' ? root.slice(1, -1) : root;
137137
var decodedRoot = options.decodeDotInKeys ? cleanRoot.replace(/%2E/g, '.') : cleanRoot;
138138
var index = parseInt(decodedRoot, 10);
@@ -274,11 +274,11 @@ module.exports = function (str, opts) {
274274
var options = normalizeParseOptions(opts);
275275

276276
if (str === '' || str === null || typeof str === 'undefined') {
277-
return options.plainObjects ? Object.create(null) : {};
277+
return options.plainObjects ? { __proto__: null } : {};
278278
}
279279

280280
var tempObj = typeof str === 'string' ? parseValues(str, options) : str;
281-
var obj = options.plainObjects ? Object.create(null) : {};
281+
var obj = options.plainObjects ? { __proto__: null } : {};
282282

283283
// Iterate over the keys and setup the new object
284284

lib/utils.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ var compactQueue = function compactQueue(queue) {
3434
};
3535

3636
var arrayToObject = function arrayToObject(source, options) {
37-
var obj = options && options.plainObjects ? Object.create(null) : {};
37+
var obj = options && options.plainObjects ? { __proto__: null } : {};
3838
for (var i = 0; i < source.length; ++i) {
3939
if (typeof source[i] !== 'undefined') {
4040
obj[i] = source[i];

package.json

+2
Original file line numberDiff line numberDiff line change
@@ -46,8 +46,10 @@
4646
"evalmd": "^0.0.19",
4747
"for-each": "^0.3.3",
4848
"glob": "=10.3.7",
49+
"has-bigints": "^1.0.2",
4950
"has-override-mistake": "^1.0.1",
5051
"has-property-descriptors": "^1.0.2",
52+
"has-proto": "^1.0.3",
5153
"has-symbols": "^1.0.3",
5254
"iconv-lite": "^0.5.1",
5355
"in-publish": "^2.0.1",

test/parse.js

+21-13
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ var SaferBuffer = require('safer-buffer').Buffer;
99
var v = require('es-value-fixtures');
1010
var inspect = require('object-inspect');
1111
var emptyTestCases = require('./empty-keys-cases').emptyTestCases;
12+
var hasProto = require('has-proto')();
1213

1314
var qs = require('../');
1415
var utils = require('../lib/utils');
@@ -691,9 +692,8 @@ test('parse()', function (t) {
691692
st.end();
692693
});
693694

694-
t.test('parses null objects correctly', { skip: !Object.create }, function (st) {
695-
var a = Object.create(null);
696-
a.b = 'c';
695+
t.test('parses null objects correctly', { skip: !hasProto }, function (st) {
696+
var a = { __proto__: null, b: 'c' };
697697

698698
st.deepEqual(qs.parse(a), { b: 'c' });
699699
var result = qs.parse({ a: a });
@@ -870,17 +870,25 @@ test('parse()', function (t) {
870870
st.end();
871871
});
872872

873-
t.test('can return null objects', { skip: !Object.create }, function (st) {
874-
var expected = Object.create(null);
875-
expected.a = Object.create(null);
876-
expected.a.b = 'c';
877-
expected.a.hasOwnProperty = 'd';
873+
t.test('can return null objects', { skip: !hasProto }, function (st) {
874+
var expected = {
875+
__proto__: null,
876+
a: {
877+
__proto__: null,
878+
b: 'c',
879+
hasOwnProperty: 'd'
880+
}
881+
};
878882
st.deepEqual(qs.parse('a[b]=c&a[hasOwnProperty]=d', { plainObjects: true }), expected);
879-
st.deepEqual(qs.parse(null, { plainObjects: true }), Object.create(null));
880-
var expectedArray = Object.create(null);
881-
expectedArray.a = Object.create(null);
882-
expectedArray.a[0] = 'b';
883-
expectedArray.a.c = 'd';
883+
st.deepEqual(qs.parse(null, { plainObjects: true }), { __proto__: null });
884+
var expectedArray = {
885+
__proto__: null,
886+
a: {
887+
__proto__: null,
888+
0: 'b',
889+
c: 'd'
890+
}
891+
};
884892
st.deepEqual(qs.parse('a[]=b&a[c]=d', { plainObjects: true }), expectedArray);
885893
st.end();
886894
});

test/stringify.js

+6-10
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,8 @@ var SaferBuffer = require('safer-buffer').Buffer;
88
var hasSymbols = require('has-symbols');
99
var mockProperty = require('mock-property');
1010
var emptyTestCases = require('./empty-keys-cases').emptyTestCases;
11-
var hasBigInt = typeof BigInt === 'function';
11+
var hasProto = require('has-proto')();
12+
var hasBigInt = require('has-bigints')();
1213

1314
test('stringify()', function (t) {
1415
t.test('stringifies a querystring object', function (st) {
@@ -650,10 +651,8 @@ test('stringify()', function (t) {
650651
st.end();
651652
});
652653

653-
t.test('stringifies a null object', { skip: !Object.create }, function (st) {
654-
var obj = Object.create(null);
655-
obj.a = 'b';
656-
st.equal(qs.stringify(obj), 'a=b');
654+
t.test('stringifies a null object', { skip: !hasProto }, function (st) {
655+
st.equal(qs.stringify({ __proto__: null, a: 'b' }), 'a=b');
657656
st.end();
658657
});
659658

@@ -665,11 +664,8 @@ test('stringify()', function (t) {
665664
st.end();
666665
});
667666

668-
t.test('stringifies an object with a null object as a child', { skip: !Object.create }, function (st) {
669-
var obj = { a: Object.create(null) };
670-
671-
obj.a.b = 'c';
672-
st.equal(qs.stringify(obj), 'a%5Bb%5D=c');
667+
t.test('stringifies an object with a null object as a child', { skip: !hasProto }, function (st) {
668+
st.equal(qs.stringify({ a: { __proto__: null, b: 'c' } }), 'a%5Bb%5D=c');
673669
st.end();
674670
});
675671

0 commit comments

Comments
 (0)