Skip to content

Commit e370968

Browse files
authored
Merge pull request #17 from jonschlinkert/key-properties
Property keys
2 parents 12cbc0b + 393e2cb commit e370968

File tree

3 files changed

+70
-1
lines changed

3 files changed

+70
-1
lines changed

.travis.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,4 +17,5 @@ node_js:
1717
matrix:
1818
fast_finish: true
1919
allow_failures:
20+
- node_js: 'node'
2021
- node_js: '0.8'

index.js

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ module.exports = function mergeDeep(orig, objects) {
3232

3333
function merge(target, obj) {
3434
for (var key in obj) {
35-
if (key === '__proto__' || !hasOwn(obj, key)) {
35+
if (!isValidKey(key) || !hasOwn(obj, key)) {
3636
continue;
3737
}
3838

@@ -57,3 +57,7 @@ function hasOwn(obj, key) {
5757
function isObject(val) {
5858
return typeOf(val) === 'object' || typeOf(val) === 'function';
5959
}
60+
61+
function isValidKey(key) {
62+
return key !== '__proto__' && key !== 'constructor' && key !== 'prototype';
63+
}

test.js

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -134,4 +134,68 @@ describe('mergeDeep', function() {
134134
var actual = merge(fixture);
135135
assert.deepEqual(actual, fixture);
136136
});
137+
138+
it('should not clone invalid keys', function() {
139+
var obj1 = { a: { b: 1 } };
140+
var obj2 = JSON.parse('{ "a": { "c": 2 }, "constructor": { "keys": 42 } }');
141+
142+
var actual = merge({}, obj1, obj2);
143+
assert.deepEqual(actual, { a: { b: 1, c: 2 } });
144+
assert.notDeepEqual(actual.a, obj1.a);
145+
assert.notDeepEqual(actual.a, obj2.a);
146+
assert.notEqual(actual.keys, 42);
147+
assert.notEqual(actual.constructor.keys, 42);
148+
});
149+
150+
it('should allow being used for custom constructors', function() {
151+
// The following setup code is a simple way to demonstrate multiple inheritance by merging the prototype of one class onto another
152+
function Shape() {
153+
this.type = '';
154+
}
155+
156+
function Position(x, y) {
157+
this.x = x || 0;
158+
this.y = y || 0;
159+
}
160+
161+
Position.prototype.stringify = function() {
162+
return '(' + this.x + ', ' + this.y + ')';
163+
};
164+
165+
function Moveable(x, y) {
166+
Position.call(this, x, y);
167+
}
168+
169+
// By making Moveable inherit from Position, allows us to test what happens when `constructor` is passed to `isValidKey`.
170+
Moveable.prototype = Object.create(Position.prototype);
171+
Moveable.prototype.constructor = Moveable;
172+
Moveable.prototype = merge(Moveable.prototype, Position.prototype);
173+
174+
Moveable.prototype.move = function(x, y) {
175+
this.x += x;
176+
this.y += y;
177+
};
178+
179+
Moveable.prototype.position = function() {
180+
return this.stringify();
181+
};
182+
183+
function Rectangle() {
184+
Shape.call(this);
185+
Moveable.call(this);
186+
this.type = 'rectangle';
187+
}
188+
189+
// Single inheritance using Object.create
190+
Rectangle.prototype = Object.create(Shape.prototype);
191+
Rectangle.prototype.constructor = Rectangle;
192+
193+
// This is the test to ensure that `merge-deep` can be used with prototypal inheritance
194+
Rectangle.prototype = merge(Rectangle.prototype, Moveable.prototype);
195+
196+
var rectangle = new Rectangle();
197+
assert.equal(rectangle.position(), '(0, 0)');
198+
rectangle.move(10, 20);
199+
assert.equal(rectangle.position(), '(10, 20)');
200+
});
137201
});

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy