Path: csiph.com!.POSTED.204-73-239-109.cust.centrio.cz!not-for-mail From: Cezary Tomczyk Newsgroups: comp.lang.javascript Subject: Re: Object.defineProperties Date: Sun, 7 May 2017 10:06:43 +0200 Organization: csiph.com Internet News Service Message-ID: References: <1943190.NgBsaNRSFp@PointedEars.de> <1592229.TLkxdtWsSY@PointedEars.de> Mime-Version: 1.0 Content-Type: text/plain; charset=utf-8; format=flowed Content-Transfer-Encoding: 7bit Injection-Date: Sun, 7 May 2017 08:06:45 +0000 (UTC) Injection-Info: csiph.com; posting-host="204-73-239-109.cust.centrio.cz:109.239.73.204"; logging-data="49940"; mail-complaints-to="admin@kev009.com" User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.12; rv:45.0) Gecko/20100101 Thunderbird/45.8.0 In-Reply-To: Xref: csiph.com comp.lang.javascript:33248 On 07/05/2017 00:29, Stefan Weiss wrote: > Cezary Tomczyk wrote: >> function isTypeOf(obj, typeToCheck) { >> var type; >> >> if (arguments.length < 2) { >> throw new Error('[isTypeOf] requires two arguments'); >> } >> >> type = typeToCheck.toLowerCase(); >> >> if (type === 'null' && obj === null) { >> return 'null'; >> } >> >> if (type === 'array' && Array.isArray(obj)) { >> return 'array'; >> } >> >> return typeof obj === type; >> } > > It's shorter, but I still don't see the advantage of this: > > isTypeOf(value, "null") > isTypeOf(value, "string") > isTypeOf(value, "array") > > over this: > > value === null > typeof value == "string" > Array.isArray(value) > > There may be a use for a function that can examine values using a > dynamically provided type - for example in a debugger, something like "list > all object properties, sorted by type, and separating nulls and arrays". > > But I'm wondering if you actually need it. In another post, you wrote: > > | One of the reason is because I use it in other function that extends > | deeply one object with another. I can't use Object.assign as the > | changes on extended object must not mutate original object. > > Could you elaborate on that? Object.assign() only changes the first of its > arguments (the target); the rest stays intact. There are other caveats with > Object.assign(), but the source object should not be changed (unless its > getters are doing something strange). Here is the example case: var o = { a: [1] }, c = {}; Object.assign(c, o); console.log(o.a[0]); 1 console.log(c.a[0]); 1 c.a[0] = 2; console.log(o.a[0]); 2 but should be 1. So, Object.assign does shallow copy, not deep copy. My goal , by having "extend" function in that case, is to do deep copy. If I do extend({}, o); then new object will have his own data and changes made on new object must not reflect on the source object. So far I've done: function extend(target, source) { var output = target; function processProperty(key) { if (isTypeOf(source[key], 'object')) { output[key] = {}; extend(output[key], source[key]); } else if (isTypeOf(source[key], 'array')) { output[key] = source[key].slice(0); } else { output[key] = source[key]; } } Object.keys(source).forEach(processProperty); return output; } Unit test passes when I run them in the browser. it('should extend new object with specified object (deep copy)', function () { var o = { id: 1, arr: [ { example: 'example' } ], nodes: [ document.createElement('span') ], str: 'str' }, obj = object.extend({}, o); obj.id = 2; obj.arr[0].example = 'example2'; obj.nodes[0] = document.createElement('div'); obj.str = 'str2'; expect(o.id).toBe(1); expect(o.arr[0].example).toBe('example'); expect(o.nodes[0].nodeName.toLowerCase()).toBe('span'); expect(o.str).toBe('str'); }); However, when I run it in PhantomJS 2.1.1 (Mac OS X) then it throws exception: "TypeError: Requested keys of a value that is not an object. in object.js (line 9)" While I understand that "source" is passed as a non-object then I can't find out what's causing it. At least debugging PhantomJS is a bit hard. -- Cezary Tomczyk http://www.ctomczyk.pl/