582 lines
18 KiB
JavaScript
582 lines
18 KiB
JavaScript
// Copyright 2013 The Closure Library Authors. All Rights Reserved.
|
||
//
|
||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||
// you may not use this file except in compliance with the License.
|
||
// You may obtain a copy of the License at
|
||
//
|
||
// http://www.apache.org/licenses/LICENSE-2.0
|
||
//
|
||
// Unless required by applicable law or agreed to in writing, software
|
||
// distributed under the License is distributed on an "AS-IS" BASIS,
|
||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||
// See the License for the specific language governing permissions and
|
||
// limitations under the License.
|
||
|
||
goog.provide('goog.jsonTest');
|
||
goog.setTestOnly('goog.jsonTest');
|
||
|
||
goog.require('goog.functions');
|
||
goog.require('goog.json');
|
||
goog.require('goog.testing.jsunit');
|
||
goog.require('goog.userAgent');
|
||
|
||
function allChars(start, end) {
|
||
var sb = [];
|
||
for (var i = start; i < end; i++) {
|
||
sb.push(String.fromCharCode(i));
|
||
}
|
||
return sb.join('');
|
||
}
|
||
|
||
// serialization
|
||
|
||
function testStringSerialize() {
|
||
assertSerialize('""', '');
|
||
|
||
assertSerialize('"true"', 'true');
|
||
assertSerialize('"false"', 'false');
|
||
assertSerialize('"null"', 'null');
|
||
assertSerialize('"0"', '0');
|
||
|
||
// Unicode and control characters
|
||
assertSerialize('"\\n"', '\n');
|
||
assertSerialize('"\\u001f"', '\x1f');
|
||
assertSerialize('"\\u20ac"', '\u20AC');
|
||
assertSerialize('"\\ud83d\\ud83d"', '\ud83d\ud83d');
|
||
|
||
var str = allChars(0, 10000);
|
||
assertEquals(str, eval(goog.json.serialize(str)));
|
||
}
|
||
|
||
function testNullSerialize() {
|
||
assertSerialize('null', null);
|
||
assertSerialize('null', undefined);
|
||
assertSerialize('null', NaN);
|
||
|
||
assertSerialize('0', 0);
|
||
assertSerialize('""', '');
|
||
assertSerialize('false', false);
|
||
}
|
||
|
||
function testNullPropertySerialize() {
|
||
assertSerialize('{"a":null}', {'a': null});
|
||
assertSerialize('{"a":null}', {'a': undefined});
|
||
}
|
||
|
||
function testNumberSerialize() {
|
||
assertSerialize('0', 0);
|
||
assertSerialize('12345', 12345);
|
||
assertSerialize('-12345', -12345);
|
||
|
||
assertSerialize('0.1', 0.1);
|
||
// the leading zero may not be omitted
|
||
assertSerialize('0.1', .1);
|
||
|
||
// no leading +
|
||
assertSerialize('1', +1);
|
||
|
||
// either format is OK
|
||
var s = goog.json.serialize(1e50);
|
||
assertTrue('1e50',
|
||
s == '1e50' || s == '1E50' ||
|
||
s == '1e+50' || s == '1E+50');
|
||
|
||
// either format is OK
|
||
s = goog.json.serialize(1e-50);
|
||
assertTrue('1e50', s == '1e-50' || s == '1E-50');
|
||
|
||
// These numbers cannot be represented in JSON
|
||
assertSerialize('null', NaN);
|
||
assertSerialize('null', Infinity);
|
||
assertSerialize('null', -Infinity);
|
||
}
|
||
|
||
function testBooleanSerialize() {
|
||
assertSerialize('true', true);
|
||
assertSerialize('"true"', 'true');
|
||
|
||
assertSerialize('false', false);
|
||
assertSerialize('"false"', 'false');
|
||
}
|
||
|
||
function testArraySerialize() {
|
||
assertSerialize('[]', []);
|
||
assertSerialize('[1]', [1]);
|
||
assertSerialize('[1,2]', [1, 2]);
|
||
assertSerialize('[1,2,3]', [1, 2, 3]);
|
||
assertSerialize('[[]]', [[]]);
|
||
assertSerialize('[null,null]', [function() {}, function() {}]);
|
||
|
||
assertNotEquals('{length:0}', goog.json.serialize({length: 0}), '[]');
|
||
}
|
||
|
||
function testFunctionSerialize() {
|
||
assertSerialize('null', function() {});
|
||
}
|
||
|
||
function testObjectSerialize_emptyObject() {
|
||
assertSerialize('{}', {});
|
||
}
|
||
|
||
function testObjectSerialize_oneItem() {
|
||
assertSerialize('{"a":"b"}', {a: 'b'});
|
||
}
|
||
|
||
function testObjectSerialize_twoItems() {
|
||
assertEquals('{"a":"b","c":"d"}',
|
||
goog.json.serialize({a: 'b', c: 'd'}),
|
||
'{"a":"b","c":"d"}');
|
||
}
|
||
|
||
function testObjectSerialize_whitespace() {
|
||
assertSerialize('{" ":" "}', {' ': ' '});
|
||
}
|
||
|
||
function testSerializeSkipFunction() {
|
||
var object = {
|
||
s: 'string value',
|
||
b: true,
|
||
i: 100,
|
||
f: function() { var x = 'x'; }
|
||
};
|
||
assertSerialize('null', object.f);
|
||
assertSerialize('{"s":"string value","b":true,"i":100}', object);
|
||
}
|
||
|
||
function testObjectSerialize_array() {
|
||
assertNotEquals('[0,1]', goog.json.serialize([0, 1]), '{"0":"0","1":"1"}');
|
||
}
|
||
|
||
function testObjectSerialize_recursion() {
|
||
if (goog.userAgent.WEBKIT) {
|
||
return; // this makes safari 4 crash.
|
||
}
|
||
|
||
var anObject = {};
|
||
anObject.thisObject = anObject;
|
||
assertThrows('expected recursion exception', function() {
|
||
goog.json.serialize(anObject);
|
||
});
|
||
}
|
||
|
||
function testObjectSerializeWithHasOwnProperty() {
|
||
var object = {'hasOwnProperty': null};
|
||
if (goog.userAgent.IE && !goog.userAgent.isVersionOrHigher('9')) {
|
||
assertEquals('{}', goog.json.serialize(object));
|
||
} else {
|
||
assertEquals('{"hasOwnProperty":null}', goog.json.serialize(object));
|
||
}
|
||
}
|
||
|
||
function testWrappedObjects() {
|
||
assertSerialize('"foo"', new String('foo'));
|
||
assertSerialize('42', new Number(42));
|
||
assertSerialize('null', new Number('a NaN'));
|
||
assertSerialize('true', new Boolean(true));
|
||
}
|
||
|
||
// parsing
|
||
|
||
function testStringParse() {
|
||
|
||
assertEquals('Empty string', goog.json.parse('""'), '');
|
||
assertEquals('whitespace string', goog.json.parse('" "'), ' ');
|
||
|
||
// unicode without the control characters 0x00 - 0x1f, 0x7f - 0x9f
|
||
var str = allChars(32, 1000);
|
||
var jsonString = goog.json.serialize(str);
|
||
var a = eval(jsonString);
|
||
assertEquals('unicode string', goog.json.parse(jsonString), a);
|
||
|
||
assertEquals('true as a string', goog.json.parse('"true"'), 'true');
|
||
assertEquals('false as a string', goog.json.parse('"false"'), 'false');
|
||
assertEquals('null as a string', goog.json.parse('"null"'), 'null');
|
||
assertEquals('number as a string', goog.json.parse('"0"'), '0');
|
||
}
|
||
|
||
function testStringUnsafeParse() {
|
||
|
||
assertEquals('Empty string', goog.json.unsafeParse('""'), '');
|
||
assertEquals('whitespace string', goog.json.unsafeParse('" "'), ' ');
|
||
|
||
// unicode
|
||
var str = allChars(32, 1000);
|
||
var jsonString = goog.json.serialize(str);
|
||
var a = eval(jsonString);
|
||
assertEquals('unicode string', goog.json.unsafeParse(jsonString), a);
|
||
|
||
assertEquals('true as a string', goog.json.unsafeParse('"true"'), 'true');
|
||
assertEquals('false as a string', goog.json.unsafeParse('"false"'), 'false');
|
||
assertEquals('null as a string', goog.json.unsafeParse('"null"'), 'null');
|
||
assertEquals('number as a string', goog.json.unsafeParse('"0"'), '0');
|
||
}
|
||
|
||
function testNullParse() {
|
||
assertEquals('null', goog.json.parse(null), null);
|
||
assertEquals('null', goog.json.parse('null'), null);
|
||
|
||
assertNotEquals('0', goog.json.parse('0'), null);
|
||
assertNotEquals('""', goog.json.parse('""'), null);
|
||
assertNotEquals('false', goog.json.parse('false'), null);
|
||
}
|
||
|
||
function testNullUnsafeParse() {
|
||
assertEquals('null', goog.json.unsafeParse(null), null);
|
||
assertEquals('null', goog.json.unsafeParse('null'), null);
|
||
|
||
assertNotEquals('0', goog.json.unsafeParse('0'), null);
|
||
assertNotEquals('""', goog.json.unsafeParse('""'), null);
|
||
assertNotEquals('false', goog.json.unsafeParse('false'), null);
|
||
}
|
||
|
||
function testNumberParse() {
|
||
assertEquals('0', goog.json.parse('0'), 0);
|
||
assertEquals('12345', goog.json.parse('12345'), 12345);
|
||
assertEquals('-12345', goog.json.parse('-12345'), -12345);
|
||
|
||
assertEquals('0.1', goog.json.parse('0.1'), 0.1);
|
||
|
||
// either format is OK
|
||
assertEquals(1e50, goog.json.parse('1e50'));
|
||
assertEquals(1e50, goog.json.parse('1E50'));
|
||
assertEquals(1e50, goog.json.parse('1e+50'));
|
||
assertEquals(1e50, goog.json.parse('1E+50'));
|
||
|
||
// either format is OK
|
||
assertEquals(1e-50, goog.json.parse('1e-50'));
|
||
assertEquals(1e-50, goog.json.parse('1E-50'));
|
||
}
|
||
|
||
function testNumberUnsafeParse() {
|
||
assertEquals('0', goog.json.unsafeParse('0'), 0);
|
||
assertEquals('12345', goog.json.unsafeParse('12345'), 12345);
|
||
assertEquals('-12345', goog.json.unsafeParse('-12345'), -12345);
|
||
|
||
assertEquals('0.1', goog.json.unsafeParse('0.1'), 0.1);
|
||
|
||
// either format is OK
|
||
assertEquals(1e50, goog.json.unsafeParse('1e50'));
|
||
assertEquals(1e50, goog.json.unsafeParse('1E50'));
|
||
assertEquals(1e50, goog.json.unsafeParse('1e+50'));
|
||
assertEquals(1e50, goog.json.unsafeParse('1E+50'));
|
||
|
||
// either format is OK
|
||
assertEquals(1e-50, goog.json.unsafeParse('1e-50'));
|
||
assertEquals(1e-50, goog.json.unsafeParse('1E-50'));
|
||
}
|
||
|
||
function testBooleanParse() {
|
||
assertEquals('true', goog.json.parse('true'), true);
|
||
assertEquals('false', goog.json.parse('false'), false);
|
||
|
||
assertNotEquals('0', goog.json.parse('0'), false);
|
||
assertNotEquals('"false"', goog.json.parse('"false"'), false);
|
||
assertNotEquals('null', goog.json.parse('null'), false);
|
||
|
||
assertNotEquals('1', goog.json.parse('1'), true);
|
||
assertNotEquals('"true"', goog.json.parse('"true"'), true);
|
||
assertNotEquals('{}', goog.json.parse('{}'), true);
|
||
assertNotEquals('[]', goog.json.parse('[]'), true);
|
||
}
|
||
|
||
function testBooleanUnsafeParse() {
|
||
assertEquals('true', goog.json.unsafeParse('true'), true);
|
||
assertEquals('false', goog.json.unsafeParse('false'), false);
|
||
|
||
assertNotEquals('0', goog.json.unsafeParse('0'), false);
|
||
assertNotEquals('"false"', goog.json.unsafeParse('"false"'), false);
|
||
assertNotEquals('null', goog.json.unsafeParse('null'), false);
|
||
|
||
assertNotEquals('1', goog.json.unsafeParse('1'), true);
|
||
assertNotEquals('"true"', goog.json.unsafeParse('"true"'), true);
|
||
assertNotEquals('{}', goog.json.unsafeParse('{}'), true);
|
||
assertNotEquals('[]', goog.json.unsafeParse('[]'), true);
|
||
}
|
||
|
||
function testArrayParse() {
|
||
assertArrayEquals([], goog.json.parse('[]'));
|
||
assertArrayEquals([1], goog.json.parse('[1]'));
|
||
assertArrayEquals([1, 2], goog.json.parse('[1,2]'));
|
||
assertArrayEquals([1, 2, 3], goog.json.parse('[1,2,3]'));
|
||
assertArrayEquals([[]], goog.json.parse('[[]]'));
|
||
|
||
// Note that array-holes are not valid json. However, goog.json.parse
|
||
// supports them so that clients can reap the security benefits of
|
||
// goog.json.parse even if they are using this non-standard format.
|
||
assertArrayEquals([1, /* hole */, 3], goog.json.parse('[1,,3]'));
|
||
|
||
// make sure we do not get an array for something that looks like an array
|
||
assertFalse('{length:0}', 'push' in goog.json.parse('{"length":0}'));
|
||
}
|
||
|
||
function testArrayUnsafeParse() {
|
||
function arrayEquals(a1, a2) {
|
||
if (a1.length != a2.length) {
|
||
return false;
|
||
}
|
||
for (var i = 0; i < a1.length; i++) {
|
||
if (a1[i] != a2[i]) {
|
||
return false;
|
||
}
|
||
}
|
||
return true;
|
||
}
|
||
|
||
assertTrue('[]', arrayEquals(goog.json.unsafeParse('[]'), []));
|
||
assertTrue('[1]', arrayEquals(goog.json.unsafeParse('[1]'), [1]));
|
||
assertTrue('[1,2]', arrayEquals(goog.json.unsafeParse('[1,2]'), [1, 2]));
|
||
assertTrue('[1,2,3]',
|
||
arrayEquals(goog.json.unsafeParse('[1,2,3]'), [1, 2, 3]));
|
||
assertTrue('[[]]', arrayEquals(goog.json.unsafeParse('[[]]')[0], []));
|
||
|
||
// make sure we do not get an array for something that looks like an array
|
||
assertFalse('{length:0}', 'push' in goog.json.unsafeParse('{"length":0}'));
|
||
}
|
||
|
||
function testObjectParse() {
|
||
function objectEquals(a1, a2) {
|
||
for (var key in a1) {
|
||
if (a1[key] != a2[key]) {
|
||
return false;
|
||
}
|
||
}
|
||
return true;
|
||
}
|
||
|
||
assertTrue('{}', objectEquals(goog.json.parse('{}'), {}));
|
||
assertTrue('{"a":"b"}',
|
||
objectEquals(goog.json.parse('{"a":"b"}'), {a: 'b'}));
|
||
assertTrue('{"a":"b","c":"d"}',
|
||
objectEquals(goog.json.parse('{"a":"b","c":"d"}'),
|
||
{a: 'b', c: 'd'}));
|
||
assertTrue('{" ":" "}',
|
||
objectEquals(goog.json.parse('{" ":" "}'), {' ': ' '}));
|
||
|
||
// make sure we do not get an Object when it is really an array
|
||
assertTrue('[0,1]', 'length' in goog.json.parse('[0,1]'));
|
||
}
|
||
|
||
function testObjectUnsafeParse() {
|
||
function objectEquals(a1, a2) {
|
||
for (var key in a1) {
|
||
if (a1[key] != a2[key]) {
|
||
return false;
|
||
}
|
||
}
|
||
return true;
|
||
}
|
||
|
||
assertTrue('{}', objectEquals(goog.json.unsafeParse('{}'), {}));
|
||
assertTrue('{"a":"b"}',
|
||
objectEquals(goog.json.unsafeParse('{"a":"b"}'), {a: 'b'}));
|
||
assertTrue('{"a":"b","c":"d"}',
|
||
objectEquals(goog.json.unsafeParse('{"a":"b","c":"d"}'),
|
||
{a: 'b', c: 'd'}));
|
||
assertTrue('{" ":" "}',
|
||
objectEquals(goog.json.unsafeParse('{" ":" "}'), {' ': ' '}));
|
||
|
||
// make sure we do not get an Object when it is really an array
|
||
assertTrue('[0,1]', 'length' in goog.json.unsafeParse('[0,1]'));
|
||
}
|
||
|
||
|
||
function testForValidJson() {
|
||
function error_(msg, s) {
|
||
assertThrows(msg + ', Should have raised an exception: ' + s,
|
||
goog.partial(goog.json.parse, s));
|
||
}
|
||
|
||
error_('Non closed string', '"dasdas');
|
||
error_('undefined is not valid json', 'undefined');
|
||
|
||
// These numbers cannot be represented in JSON
|
||
error_('NaN cannot be presented in JSON', 'NaN');
|
||
error_('Infinity cannot be presented in JSON', 'Infinity');
|
||
error_('-Infinity cannot be presented in JSON', '-Infinity');
|
||
}
|
||
|
||
function testIsNotValid() {
|
||
assertFalse(goog.json.isValid('t'));
|
||
assertFalse(goog.json.isValid('r'));
|
||
assertFalse(goog.json.isValid('u'));
|
||
assertFalse(goog.json.isValid('e'));
|
||
assertFalse(goog.json.isValid('f'));
|
||
assertFalse(goog.json.isValid('a'));
|
||
assertFalse(goog.json.isValid('l'));
|
||
assertFalse(goog.json.isValid('s'));
|
||
assertFalse(goog.json.isValid('n'));
|
||
assertFalse(goog.json.isValid('E'));
|
||
|
||
assertFalse(goog.json.isValid('+'));
|
||
assertFalse(goog.json.isValid('-'));
|
||
|
||
assertFalse(goog.json.isValid('t++'));
|
||
assertFalse(goog.json.isValid('++t'));
|
||
assertFalse(goog.json.isValid('t--'));
|
||
assertFalse(goog.json.isValid('--t'));
|
||
assertFalse(goog.json.isValid('-t'));
|
||
assertFalse(goog.json.isValid('+t'));
|
||
|
||
assertFalse(goog.json.isValid('"\\"')); // "\"
|
||
assertFalse(goog.json.isValid('"\\')); // "\
|
||
|
||
// multiline string using \ at the end is not valid
|
||
assertFalse(goog.json.isValid('"a\\\nb"'));
|
||
|
||
|
||
assertFalse(goog.json.isValid('"\n"'));
|
||
assertFalse(goog.json.isValid('"\r"'));
|
||
assertFalse(goog.json.isValid('"\r\n"'));
|
||
// Disallow the unicode newlines
|
||
assertFalse(goog.json.isValid('"\u2028"'));
|
||
assertFalse(goog.json.isValid('"\u2029"'));
|
||
|
||
assertFalse(goog.json.isValid(' '));
|
||
assertFalse(goog.json.isValid('\n'));
|
||
assertFalse(goog.json.isValid('\r'));
|
||
assertFalse(goog.json.isValid('\r\n'));
|
||
|
||
assertFalse(goog.json.isValid('t.r'));
|
||
|
||
assertFalse(goog.json.isValid('1e'));
|
||
assertFalse(goog.json.isValid('1e-'));
|
||
assertFalse(goog.json.isValid('1e+'));
|
||
|
||
assertFalse(goog.json.isValid('1e-'));
|
||
|
||
assertFalse(goog.json.isValid('"\\\u200D\\"'));
|
||
assertFalse(goog.json.isValid('"\\\0\\"'));
|
||
assertFalse(goog.json.isValid('"\\\0"'));
|
||
assertFalse(goog.json.isValid('"\\0"'));
|
||
assertFalse(goog.json.isValid('"\x0c"'));
|
||
|
||
assertFalse(goog.json.isValid('"\\\u200D\\", alert(\'foo\') //"\n'));
|
||
}
|
||
|
||
function testIsValid() {
|
||
assertTrue(goog.json.isValid('\n""\n'));
|
||
assertTrue(goog.json.isValid('[1\n,2\r,3\u2028\n,4\u2029]'));
|
||
assertTrue(goog.json.isValid('"\x7f"'));
|
||
assertTrue(goog.json.isValid('"\x09"'));
|
||
// Test tab characters in json.
|
||
assertTrue(goog.json.isValid('{"\t":"\t"}'));
|
||
}
|
||
|
||
function testDoNotSerializeProto() {
|
||
function F() {};
|
||
F.prototype = {
|
||
c: 3
|
||
};
|
||
|
||
var obj = new F;
|
||
obj.a = 1;
|
||
obj.b = 2;
|
||
|
||
assertEquals('Should not follow the prototype chain',
|
||
'{"a":1,"b":2}',
|
||
goog.json.serialize(obj));
|
||
}
|
||
|
||
function testEscape() {
|
||
var unescaped = '1a*/]';
|
||
assertEquals('Should not escape',
|
||
'"' + unescaped + '"',
|
||
goog.json.serialize(unescaped));
|
||
|
||
var escaped = '\n\x7f\u1049';
|
||
assertEquals('Should escape',
|
||
'',
|
||
findCommonChar(escaped, goog.json.serialize(escaped)));
|
||
assertEquals('Should eval to the same string after escaping',
|
||
escaped,
|
||
goog.json.parse(goog.json.serialize(escaped)));
|
||
}
|
||
|
||
function testReplacer() {
|
||
assertSerialize('[null,null,0]', [, , 0]);
|
||
|
||
assertSerialize('[0,0,{"x":0}]', [, , {x: 0}], function(k, v) {
|
||
if (v === undefined && goog.isArray(this)) {
|
||
return 0;
|
||
}
|
||
return v;
|
||
});
|
||
|
||
assertSerialize('[0,1,2,3]', [0, 0, 0, 0], function(k, v) {
|
||
var kNum = Number(k);
|
||
if (k && !isNaN(kNum)) {
|
||
return kNum;
|
||
}
|
||
return v;
|
||
});
|
||
|
||
var f = function(k, v) {
|
||
return typeof v == 'number' ? v + 1 : v;
|
||
};
|
||
assertSerialize('{"a":1,"b":{"c":2}}', {'a': 0, 'b': {'c': 1}}, f);
|
||
}
|
||
|
||
function testDateSerialize() {
|
||
assertSerialize('{}', new Date(0));
|
||
}
|
||
|
||
function testToJSONSerialize() {
|
||
assertSerialize('{}', {toJSON: goog.functions.constant('serialized')});
|
||
assertSerialize('{"toJSON":"normal"}', {toJSON: 'normal'});
|
||
}
|
||
|
||
|
||
/**
|
||
* Asserts that the given object serializes to the given value.
|
||
* If the current browser has an implementation of JSON.serialize,
|
||
* we make sure our version matches that one.
|
||
*/
|
||
function assertSerialize(expected, obj, opt_replacer) {
|
||
assertEquals(expected, goog.json.serialize(obj, opt_replacer));
|
||
|
||
// goog.json.serialize escapes non-ASCI characters while JSON.stringify
|
||
// doesn’t. This is expected so do not compare the results.
|
||
if (typeof obj == 'string' && obj.charCodeAt(0) > 0x7f) return;
|
||
|
||
// I'm pretty sure that the goog.json.serialize behavior is correct by the ES5
|
||
// spec, but JSON.stringify(undefined) is undefined on all browsers.
|
||
if (obj === undefined) return;
|
||
|
||
// Browsers don't serialize undefined properties, but goog.json.serialize does
|
||
if (goog.isObject(obj) && ('a' in obj) && obj['a'] === undefined) return;
|
||
|
||
// Replacers are broken on IE and older versions of firefox.
|
||
if (opt_replacer && !goog.userAgent.WEBKIT) return;
|
||
|
||
// goog.json.serialize does not stringify dates the same way.
|
||
if (obj instanceof Date) return;
|
||
|
||
// goog.json.serialize does not stringify functions the same way.
|
||
if (obj instanceof Function) return;
|
||
|
||
// goog.json.serialize doesn't use the toJSON method.
|
||
if (goog.isObject(obj) && goog.isFunction(obj.toJSON)) return;
|
||
|
||
if (typeof JSON != 'undefined') {
|
||
assertEquals(
|
||
'goog.json.serialize does not match JSON.stringify',
|
||
expected,
|
||
JSON.stringify(obj, opt_replacer));
|
||
}
|
||
}
|
||
|
||
|
||
/**
|
||
* @param {string} a
|
||
* @param {string} b
|
||
* @return {string} any common character between two strings a and b.
|
||
*/
|
||
function findCommonChar(a, b) {
|
||
for (var i = 0; i < b.length; i++) {
|
||
if (a.indexOf(b.charAt(i)) >= 0) {
|
||
return b.charAt(i);
|
||
}
|
||
}
|
||
return '';
|
||
}
|