From 10694e906bc1721c3b6a642cd7ea13cc3a281874 Mon Sep 17 00:00:00 2001 From: Daniel Luz Date: Fri, 8 Mar 2013 01:33:57 -0300 Subject: [PATCH 1/2] fix(*): do not rely on an object's hasOwnProperty Closes #1944 --- src/Angular.js | 17 ++++++++++++----- src/angular-bootstrap.js | 2 +- src/auto/injector.js | 4 ++-- src/loader.js | 2 +- src/ng/compile.js | 6 +++--- src/ng/controller.js | 2 +- src/ng/directive/form.js | 2 +- src/ng/directive/ngRepeat.js | 4 ++-- src/ng/directive/select.js | 2 +- src/ng/parse.js | 10 +++++----- src/ng/q.js | 4 ++-- src/ngResource/resource.js | 2 +- test/AngularSpec.js | 17 +++++++++++++++++ 13 files changed, 49 insertions(+), 25 deletions(-) diff --git a/src/Angular.js b/src/Angular.js index 5d9d2e12fffe..80fe3293246e 100644 --- a/src/Angular.js +++ b/src/Angular.js @@ -2,6 +2,13 @@ //////////////////////////////////// +/** + * hasOwnProperty may be overriden by a property of the same name, or entirely + * absent from an object that does not inherit Object.prototype; this copy is + * used instead + */ +var hasOwn = Object.prototype.hasOwnProperty; + /** * @ngdoc function * @name angular.lowercase @@ -139,7 +146,7 @@ function forEach(obj, iterator, context) { if (obj) { if (isFunction(obj)){ for (key in obj) { - if (key != 'prototype' && key != 'length' && key != 'name' && obj.hasOwnProperty(key)) { + if (key != 'prototype' && key != 'length' && key != 'name' && hasOwn.call(obj, key)) { iterator.call(context, obj[key], key); } } @@ -150,7 +157,7 @@ function forEach(obj, iterator, context) { iterator.call(context, obj[key], key); } else { for (key in obj) { - if (obj.hasOwnProperty(key)) { + if (hasOwn.call(obj, key)) { iterator.call(context, obj[key], key); } } @@ -162,7 +169,7 @@ function forEach(obj, iterator, context) { function sortedKeys(obj) { var keys = []; for (var key in obj) { - if (obj.hasOwnProperty(key)) { + if (hasOwn.call(obj, key)) { keys.push(key); } } @@ -508,7 +515,7 @@ function size(obj, ownPropsOnly) { return obj.length; } else if (isObject(obj)){ for (key in obj) - if (!ownPropsOnly || obj.hasOwnProperty(key)) + if (!ownPropsOnly || hasOwn.call(obj, key)) size++; } @@ -609,7 +616,7 @@ function shallowCopy(src, dst) { dst = dst || {}; for(var key in src) { - if (src.hasOwnProperty(key) && key.substr(0, 2) !== '$$') { + if (hasOwn.call(src, key) && key.substr(0, 2) !== '$$') { dst[key] = src[key]; } } diff --git a/src/angular-bootstrap.js b/src/angular-bootstrap.js index 86b958148c40..eaf1cd2fae88 100644 --- a/src/angular-bootstrap.js +++ b/src/angular-bootstrap.js @@ -191,7 +191,7 @@ if (IGNORE[prop] || prop.match(/^moz[A-Z]/)) { //skip special variables which keep on changing continue; - } else if (!globalVars.hasOwnProperty(varKey)) { + } else if (!hasOwn.call(globalVars, varKey)) { //console.log('new global variable found: ', prop); try { globalVars[varKey] = window[prop]; diff --git a/src/auto/injector.js b/src/auto/injector.js index d39e2aa9b7e6..75325c834e59 100644 --- a/src/auto/injector.js +++ b/src/auto/injector.js @@ -529,7 +529,7 @@ function createInjector(modulesToLoad) { if (typeof serviceName !== 'string') { throw Error('Service name expected'); } - if (cache.hasOwnProperty(serviceName)) { + if (hasOwn.call(cache, serviceName)) { if (cache[serviceName] === INSTANTIATING) { throw Error('Circular dependency: ' + path.join(' <- ')); } @@ -554,7 +554,7 @@ function createInjector(modulesToLoad) { for(i = 0, length = $inject.length; i < length; i++) { key = $inject[i]; args.push( - locals && locals.hasOwnProperty(key) + locals && hasOwn.call(locals, key) ? locals[key] : getService(key) ); diff --git a/src/loader.js b/src/loader.js index ecb166085460..43ef770ec208 100644 --- a/src/loader.js +++ b/src/loader.js @@ -65,7 +65,7 @@ function setupModuleLoader(window) { * @returns {module} new module with the {@link angular.Module} api. */ return function module(name, requires, configFn) { - if (requires && modules.hasOwnProperty(name)) { + if (requires && hasOwn.call(modules, name)) { modules[name] = null; } return ensure(modules, name, function() { diff --git a/src/ng/compile.js b/src/ng/compile.js index 6606dc6c6586..ec11eaadde1b 100644 --- a/src/ng/compile.js +++ b/src/ng/compile.js @@ -177,7 +177,7 @@ function $CompileProvider($provide) { this.directive = function registerDirective(name, directiveFactory) { if (isString(name)) { assertArg(directiveFactory, 'directive'); - if (!hasDirectives.hasOwnProperty(name)) { + if (!hasOwn.call(hasDirectives, name)) { hasDirectives[name] = []; $provide.factory(name + Suffix, ['$injector', '$exceptionHandler', function($injector, $exceptionHandler) { @@ -917,7 +917,7 @@ function $CompileProvider($provide) { */ function addDirective(tDirectives, name, location, maxPriority) { var match = false; - if (hasDirectives.hasOwnProperty(name)) { + if (hasOwn.call(hasDirectives, name)) { for(var directive, directives = $injector.get(name + Suffix), i = 0, ii = directives.length; i Date: Tue, 12 Mar 2013 00:47:25 -0300 Subject: [PATCH 2/2] fix(angular.equals): stricter test for key presence Merely testing for object[key] will give incorrect results on keys defined in Object.prototype. --- src/Angular.js | 2 +- test/AngularSpec.js | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/src/Angular.js b/src/Angular.js index 80fe3293246e..b100328d7097 100644 --- a/src/Angular.js +++ b/src/Angular.js @@ -674,7 +674,7 @@ function equals(o1, o2) { keySet[key] = true; } for(key in o2) { - if (!keySet[key] && + if (!hasOwn.call(keySet, key) && key.charAt(0) !== '$' && o2[key] !== undefined && !isFunction(o2[key])) return false; diff --git a/test/AngularSpec.js b/test/AngularSpec.js index 45ca99922970..556f9af9d6f8 100644 --- a/test/AngularSpec.js +++ b/test/AngularSpec.js @@ -211,6 +211,11 @@ describe('angular', function() { expect(equals(new Date(0), 0)).toBe(false); expect(equals(0, new Date(0))).toBe(false); }); + + it('should correctly test for keys that are present on Object.prototype', function() { + expect(equals({}, {hasOwnProperty: 1})).toBe(false); + expect(equals({}, {toString: null})).toBe(false); + }); }); describe('size', function() {