New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(angular.extend) - Simple non-breaking change to support deep extend #10507

Closed
wants to merge 4 commits into
base: master
from

Conversation

Projects
None yet
7 participants
@prettycode
Copy link

prettycode commented Dec 17, 2014

People use angular.extend() as a utility function, whether or not it's designed for that purpose. It can easily be extended to support recursive merging with very very minor additions. Developers coming to Angular expect extend() to support this.

@googlebot

This comment has been minimized.

Copy link

googlebot commented Dec 17, 2014

CLAs look good, thanks!

@googlebot googlebot added the cla: yes label Dec 17, 2014

@prettycode

This comment has been minimized.

Copy link
Author

prettycode commented Dec 17, 2014

Is there a way to rerun the job that failed? It's a timeout, not an explicit (test) failure.

@lgalfaso

This comment has been minimized.

Copy link
Member

lgalfaso commented Dec 17, 2014

git commit --amend --date "`date -R`"
git push -f
@lgalfaso

This comment has been minimized.

Copy link
Member

lgalfaso commented Dec 17, 2014

also, please squash all the commits into one

var h = dst.$$hashKey;
var h = dst.$$hashKey,
argsLength = arguments.length,
isDeep = (argsLength >= 3) && (arguments[argsLength - 1] === true);

This comment has been minimized.

@caitp

caitp Dec 17, 2014

Contributor

nit: each of these declarations should have its own var for clarity


for (var i = 1, ii = arguments.length; i < ii; i++) {
if (isDeep) {
delete arguments[argsLength - 1];

This comment has been minimized.

@caitp

caitp Dec 17, 2014

Contributor

declare ii before the loop, decrement it if isDeep

This comment has been minimized.

@caitp

caitp Dec 17, 2014

Contributor

in fact you know what, argsLength is declared already, so just use that instead :)

delete arguments[argsLength - 1];
}

for (var i = 1, ii = argsLength; i < ii; i++) {

This comment has been minimized.

@caitp

caitp Dec 17, 2014

Contributor

no need for ii here, i < argsLength is fine

dst[key] = obj[key];
var key = keys[j],
src = obj[key];
dst[key] = isDeep ? extend(dst[key], src) : src;

This comment has been minimized.

@caitp

caitp Dec 17, 2014

Contributor

recursion doesn't make a lot of sense if src is a type that can't have properties

it('should perform deep extend when last argument is true', function() {
var src = { foo: { bar: 'foobar' }},
dst = { foo: { bazz: 'foobazz' }};
extend(dst, src, true);

This comment has been minimized.

@caitp

caitp Dec 17, 2014

Contributor

add a test case where dst has a primitive (non-falsy) foo property --- also a test where it has a null foo property

This comment has been minimized.

@caitp

caitp Dec 17, 2014

Contributor

also add some tests where properties have null and undefined values :>

This comment has been minimized.

@caitp

caitp Dec 17, 2014

Contributor

Please add the tests I've been asking for, and address all of the comments I've brought up --- then we can land this.

You can avoid the complicated squash in the future by just doing git commit --amend rather than adding new commits

@lgalfaso

This comment has been minimized.

Copy link
Member

lgalfaso commented Dec 17, 2014

simple question, why is it that angular.extends({}, angular.copy(foo)) not good enough? Is this just the fact that you have to also call angular.copy?

@caitp

This comment has been minimized.

Copy link
Contributor

caitp commented Dec 17, 2014

I think config = angular.extends({}, angular.copy(defaultConfig), angular.copy(config)); is a bit more verbose than it really needs to be.

I don't see a huge problem with adding this, not to say that there aren't things I dislike about it.

@caitp

This comment has been minimized.

Copy link
Contributor

caitp commented Dec 17, 2014

Oh, I should add that config = angular.extends({}, angular.copy(defaultConfig), angular.copy(config)); is semantically different from config = angular.extends({}, defaultConfig, config, true);

@caitp

This comment has been minimized.

Copy link
Contributor

caitp commented Dec 17, 2014

@petebacondarwin what's your opinion? Normally we just tell people to "use lodash", but it's not a very big change, I don't really see the harm in this one

dst[key] = obj[key];
var src = obj[key];

if (isDeep && Object.keys(src).length) {

This comment has been minimized.

@caitp

caitp Dec 17, 2014

Contributor

If the value is null or undefined, Object.keys() will throw here... Don't worry about checking the type I guess, it's fine

delete arguments[argsLength - 1];
}

for (var i = 1; i < argsLength; i++) {
var obj = arguments[i];
if (obj) {
var keys = Object.keys(obj);

This comment has been minimized.

@caitp

caitp Dec 17, 2014

Contributor

That said, I really think we should only be taking this path if isObject(obj) || isFunction(obj) --- it doesn't really make sense otherwise

This comment has been minimized.

@caitp

caitp Dec 17, 2014

Contributor

For instance:

Object.keys(4); // will return the own-enumerable-property-keys of `new Number(4);` --- that's not very useful! It won't have any own properties.

This comment has been minimized.

@caitp

caitp Dec 17, 2014

Contributor

Also, in ES5 it will throw for all non-objects, which is not very useful! So WebKit/JSC would throw here anyways. Newer browsers will take the ES6 path and convert the primitive ToObject, and do the wrong stuff with it.

@prettycode

This comment has been minimized.

Copy link
Author

prettycode commented Dec 17, 2014

I'm afraid I may be in over my head here. Tried to squash the multiple commit (sorry) into one via this, but I'm still seeing multiple commits:

git rebase -i HEAD~8
git push -f

@caitp

This comment has been minimized.

Copy link
Contributor

caitp commented Dec 17, 2014

@prettycode what do you see when you run git rebase -i HEAD~8? you should get an editor screen, and you'll want to replace the "pick" on the left side of the last 7 commits with "f" to squash it. Careful not to squash too many =)

delete arguments[argsLength - 1];
}

for (var i = 1; i < argsLength; i++) {
var obj = arguments[i];
if (obj) {

This comment has been minimized.

@caitp

caitp Dec 17, 2014

Contributor

You misunderstood me in that last commit --- I mean on line 353, the condition should not be if (obj), it should be if (isObject(obj) || isFunction(obj))

This comment has been minimized.

@caitp

caitp Dec 17, 2014

Contributor

Make this change, please.

@prettycode prettycode force-pushed the prettycode:master branch from 974c001 to 9f7f80b Dec 17, 2014

@prettycode

This comment has been minimized.

Copy link
Author

prettycode commented Dec 17, 2014

Thanks for your help, caitp! Sorry for my inexperience with git. Updating tests and the if(obj) check you referenced (the comment I misunderstood).

@petebacondarwin

This comment has been minimized.

Copy link
Member

petebacondarwin commented Dec 17, 2014

@caitp - Oh go on then :-)


for (var i = 1, ii = arguments.length; i < ii; i++) {
if (isDeep) {
delete arguments[argsLength - 1];

This comment has been minimized.

@caitp

caitp Dec 17, 2014

Contributor
if (isDeep) --argsLength;

We don't need to delete anything, it's slow, and deleting the argument doesn't really do anything meaningful (it doesn't change the length value). I said this in like the first 3 comments =)

@petebacondarwin

This comment has been minimized.

Copy link
Member

petebacondarwin commented Mar 3, 2015

Closing in favour of #10519

caitp added a commit that referenced this pull request Mar 3, 2015

hansmaad pushed a commit to hansmaad/angular.js that referenced this pull request Mar 10, 2015

netman92 added a commit to netman92/angular.js that referenced this pull request Aug 8, 2015

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment