From 2b79ebe418a0b95cc181f9e401675dfb040c6675 Mon Sep 17 00:00:00 2001 From: kazuya kawaguchi Date: Sun, 15 Nov 2015 08:59:43 +0900 Subject: [PATCH] fix: ocurred error in 'set' and 'delete' utility functions --- src/compiler/compile-props.js | 2 +- src/directives/internal/class.js | 2 +- src/directives/public/el.js | 2 +- src/directives/public/for.js | 8 ++++---- src/instance/state.js | 6 +++--- src/observer/index.js | 2 +- src/util/lang.js | 16 ++++++++++++++-- src/util/options.js | 4 ++-- test/unit/specs/api/data_spec.js | 4 ++-- test/unit/specs/instance/state_spec.js | 5 +++-- test/unit/specs/observer/observer_spec.js | 16 ++++++++++++++-- test/unit/specs/parsers/path_spec.js | 3 ++- test/unit/specs/util/lang_spec.js | 8 ++++++++ 13 files changed, 56 insertions(+), 22 deletions(-) diff --git a/src/compiler/compile-props.js b/src/compiler/compile-props.js index d355636482e..83038097720 100644 --- a/src/compiler/compile-props.js +++ b/src/compiler/compile-props.js @@ -185,7 +185,7 @@ function makePropsLinkFn (props) { function getDefault (vm, options) { // no default, return undefined - if (!options.hasOwnProperty('default')) { + if (!_.hasOwn(options, 'default')) { // absent boolean value defaults to false return options.type === Boolean ? false diff --git a/src/directives/internal/class.js b/src/directives/internal/class.js index 09213196e75..d08b3185402 100644 --- a/src/directives/internal/class.js +++ b/src/directives/internal/class.js @@ -67,5 +67,5 @@ function stringToObject (value) { function contains (value, key) { return _.isArray(value) ? value.indexOf(key) > -1 - : value.hasOwnProperty(key) + : _.hasOwn(value, key) } diff --git a/src/directives/public/el.js b/src/directives/public/el.js index 0e92e47fde5..c6c29ce3b76 100644 --- a/src/directives/public/el.js +++ b/src/directives/public/el.js @@ -11,7 +11,7 @@ module.exports = { } var id = this.id = _.camelize(this.arg) var refs = (this._scope || this.vm).$els - if (refs.hasOwnProperty(id)) { + if (_.hasOwn(refs, id)) { refs[id] = this.el } else { _.defineReactive(refs, id, this.el) diff --git a/src/directives/public/for.js b/src/directives/public/for.js index 7e08fd9bb41..ecb320ecb2d 100644 --- a/src/directives/public/for.js +++ b/src/directives/public/for.js @@ -87,8 +87,8 @@ module.exports = { var item = data[0] var convertedFromObject = this.fromObject = isObject(item) && - item.hasOwnProperty('$key') && - item.hasOwnProperty('$value') + _.hasOwn(item, '$key') && + _.hasOwn(item, '$value') var trackByKey = this.params.trackBy var oldFrags = this.frags @@ -366,7 +366,7 @@ module.exports = { } } else { id = this.id - if (value.hasOwnProperty(id)) { + if (_.hasOwn(value, id)) { if (value[id] === null) { value[id] = frag } else { @@ -423,7 +423,7 @@ module.exports = { var index = scope.$index // fix #948: avoid accidentally fall through to // a parent repeater which happens to have $key. - var key = scope.hasOwnProperty('$key') && scope.$key + var key = _.hasOwn(scope, '$key') && scope.$key var primitive = !isObject(value) if (trackByKey || key || primitive) { var id = trackByKey diff --git a/src/instance/state.js b/src/instance/state.js index 469402be09a..06c8e32b0e0 100644 --- a/src/instance/state.js +++ b/src/instance/state.js @@ -54,14 +54,14 @@ exports._initData = function () { this._data = optionsData for (var prop in propsData) { if (process.env.NODE_ENV !== 'production' && - optionsData.hasOwnProperty(prop)) { + _.hasOwn(optionsData, prop)) { _.warn( 'Data field "' + prop + '" is already defined ' + 'as a prop. Use prop default value instead.' ) } if (this._props[prop].raw !== null || - !optionsData.hasOwnProperty(prop)) { + !_.hasOwn(optionsData, prop)) { _.set(optionsData, prop, propsData[prop]) } } @@ -105,7 +105,7 @@ exports._setData = function (newData) { i = keys.length while (i--) { key = keys[i] - if (!this.hasOwnProperty(key)) { + if (!_.hasOwn(this, key)) { // new property this._proxy(key) } diff --git a/src/observer/index.js b/src/observer/index.js index 27e1253a3a3..5b3e0164436 100644 --- a/src/observer/index.js +++ b/src/observer/index.js @@ -48,7 +48,7 @@ Observer.create = function (value, vm) { } var ob if ( - Object.prototype.hasOwnProperty.call(value, '__ob__') && + _.hasOwn(value, '__ob__') && value.__ob__ instanceof Observer ) { ob = value.__ob__ diff --git a/src/util/lang.js b/src/util/lang.js index cdca4fd3be3..48eb229909d 100644 --- a/src/util/lang.js +++ b/src/util/lang.js @@ -10,7 +10,7 @@ */ exports.set = function set (obj, key, val) { - if (obj.hasOwnProperty(key)) { + if (exports.hasOwn(obj, key)) { obj[key] = val return } @@ -43,7 +43,7 @@ exports.set = function set (obj, key, val) { */ exports.delete = function (obj, key) { - if (!obj.hasOwnProperty(key)) { + if (!exports.hasOwn(obj, key)) { return } delete obj[key] @@ -62,6 +62,18 @@ exports.delete = function (obj, key) { } } +var hasOwn = Object.prototype.hasOwnProperty +/** + * Check whether the object has the property. + * + * @param {Object} obj + * @param {String} key + * @return {Boolean} + */ +exports.hasOwn = function (obj, key) { + return hasOwn.call(obj, key) +} + /** * Check if an expression is a literal value. * diff --git a/src/util/options.js b/src/util/options.js index 0c41ec54dc0..63114865273 100644 --- a/src/util/options.js +++ b/src/util/options.js @@ -25,7 +25,7 @@ function mergeData (to, from) { for (key in from) { toVal = to[key] fromVal = from[key] - if (!to.hasOwnProperty(key)) { + if (!_.hasOwn(to, key)) { _.set(to, key, fromVal) } else if (_.isObject(toVal) && _.isObject(fromVal)) { mergeData(toVal, fromVal) @@ -326,7 +326,7 @@ exports.mergeOptions = function merge (parent, child, vm) { mergeField(key) } for (key in child) { - if (!(parent.hasOwnProperty(key))) { + if (!(_.hasOwn(parent, key))) { mergeField(key) } } diff --git a/test/unit/specs/api/data_spec.js b/test/unit/specs/api/data_spec.js index d6d067a8e5e..ec410be0525 100644 --- a/test/unit/specs/api/data_spec.js +++ b/test/unit/specs/api/data_spec.js @@ -72,8 +72,8 @@ describe('Data API', function () { it('$delete', function () { vm._digest = jasmine.createSpy() vm.$delete('a') - expect(vm.hasOwnProperty('a')).toBe(false) - expect(vm._data.hasOwnProperty('a')).toBe(false) + expect(_.hasOwn(vm, 'a')).toBe(false) + expect(_.hasOwn(vm._data, 'a')).toBe(false) expect(vm._digest).toHaveBeenCalled() // reserved key should not be deleted vm.$delete('_data') diff --git a/test/unit/specs/instance/state_spec.js b/test/unit/specs/instance/state_spec.js index 00db3853e3a..32f9cfc5827 100644 --- a/test/unit/specs/instance/state_spec.js +++ b/test/unit/specs/instance/state_spec.js @@ -1,4 +1,5 @@ var Vue = require('../../../../src/vue') +var _ = require('../../../../src/util') describe('Instance state initialization', function () { @@ -38,7 +39,7 @@ describe('Instance state initialization', function () { el: document.createElement('div'), props: ['c'] }) - expect(vm.hasOwnProperty('c')).toBe(true) + expect(_.hasOwn(vm, 'c')).toBe(true) }) it('should use default prop value if prop not provided', function () { @@ -98,7 +99,7 @@ describe('Instance state initialization', function () { // proxy new key expect(vm.b).toBe(2) // unproxy old key that's no longer present - expect(vm.hasOwnProperty('a')).toBe(false) + expect(_.hasOwn(vm, 'a')).toBe(false) }) }) diff --git a/test/unit/specs/observer/observer_spec.js b/test/unit/specs/observer/observer_spec.js index 2b71c15dae3..d1ef144aefc 100644 --- a/test/unit/specs/observer/observer_spec.js +++ b/test/unit/specs/observer/observer_spec.js @@ -282,7 +282,7 @@ describe('Observer', function () { expect(obj.b).toBe(2) expect(dep.notify.calls.count()).toBe(1) _.delete(obj, 'a') - expect(obj.hasOwnProperty('a')).toBe(false) + expect(_.hasOwn(obj, 'a')).toBe(false) expect(dep.notify.calls.count()).toBe(2) // set existing key, should be a plain set and not // trigger own ob's notify @@ -299,7 +299,19 @@ describe('Observer', function () { // should work on non-observed objects var obj2 = { a: 1 } _.delete(obj2, 'a') - expect(obj2.hasOwnProperty('a')).toBe(false) + expect(_.hasOwn(obj2, 'a')).toBe(false) + // should work on Object.create(null) + var obj3 = Object.create(null) + obj3.a = 1 + var ob3 = Observer.create(obj3) + var dep3 = ob3.dep + spyOn(dep3, 'notify') + _.set(obj3, 'b', 2) + expect(obj3.b).toBe(2) + expect(dep3.notify.calls.count()).toBe(1) + _.delete(obj3, 'a') + expect(_.hasOwn(obj3, 'a')).toBe(false) + expect(dep3.notify.calls.count()).toBe(2) }) it('observing array mutation', function () { diff --git a/test/unit/specs/parsers/path_spec.js b/test/unit/specs/parsers/path_spec.js index b530ddf5bf8..37909a8a5dd 100644 --- a/test/unit/specs/parsers/path_spec.js +++ b/test/unit/specs/parsers/path_spec.js @@ -1,4 +1,5 @@ var Path = require('../../../../src/parsers/path') +var _ = require('../../../../src/util') function assertPath (str, expected) { var path = Path.parse(str) @@ -134,7 +135,7 @@ describe('Path Parser', function () { var target = Object.create(parent) var res = Path.set(target, 'a.b.c', 123) expect(res).toBe(true) - expect(target.hasOwnProperty('a')).toBe(false) + expect(_.hasOwn(target, 'a')).toBe(false) expect(parent.a.b.c).toBe(123) }) diff --git a/test/unit/specs/util/lang_spec.js b/test/unit/specs/util/lang_spec.js index 2f45a352ac0..aabf3aef825 100644 --- a/test/unit/specs/util/lang_spec.js +++ b/test/unit/specs/util/lang_spec.js @@ -2,6 +2,14 @@ var _ = require('../../../../src/util') describe('Util - Language Enhancement', function () { + it('hasOwn', function () { + var obj1 = { a: 1 } + expect(_.hasOwn(obj1, 'a')).toBe(true) + var obj2 = Object.create(null) + obj2.a = 2 + expect(_.hasOwn(obj2, 'a')).toBe(true) + }) + it('isLiteral', function () { expect(_.isLiteral('123')).toBe(true) expect(_.isLiteral('12.3')).toBe(true)