diff --git a/JS OOP/05. Class Methods and Properties/.jshintrc b/JS OOP/05. Class Methods and Properties/.jshintrc new file mode 100644 index 0000000..5b79c70 --- /dev/null +++ b/JS OOP/05. Class Methods and Properties/.jshintrc @@ -0,0 +1,7 @@ +{ + "curly":true, + "undef":true, + "unused":true, + "esversion":6, + "strict":true +} diff --git a/JS OOP/05. Class Methods and Properties/package.json b/JS OOP/05. Class Methods and Properties/package.json new file mode 100644 index 0000000..2fb4a75 --- /dev/null +++ b/JS OOP/05. Class Methods and Properties/package.json @@ -0,0 +1,23 @@ +{ + "name": "task", + "version": "1.0.0", + "description": "", + "main": "task-1.js", + "directories": { + "test": "tests" + }, + "scripts": { + "test": "mocha --compilers js:babel-core -R spec tests" + }, + "author": "", + "license": "ISC", + "dependencies": { + "chai": "^3.5.0", + "mocha": "^3.0.2" + }, + "devDependencies": { + "babel-core": "^6.14.0", + "babel-preset-es2015": "^6.14.0", + "babel-register": "^6.14.0" + } +} diff --git a/JS OOP/05. Class Methods and Properties/task/task-1.js b/JS OOP/05. Class Methods and Properties/task/task-1.js new file mode 100644 index 0000000..e3534af --- /dev/null +++ b/JS OOP/05. Class Methods and Properties/task/task-1.js @@ -0,0 +1,171 @@ +'use strict'; +class listNode { + constructor(value) { + this._value = value; + this._next = {}; + } +} + +class LinkedList { + constructor() { + this._head = null; + this._length = 0; + } + + get first() { + return this._head._value; + } + + get last() { + let current = this._head, + index = 0; + while (++index < this._length) { + current = current.next; + } + if (current.next === undefined) { + return current._value; + } else { + return null; + } + } + + get length() { + return this._length; + } + + * + [Symbol.iterator]() { + let current = this._head, + index = 0, + output = []; + while (++index <= this._length) { + output.push(current._value); + current = current.next; + } + yield* output; + } + + append(...values) { + values.map((value) => { + let node = new listNode(value), + current; + + if (this._head === null) { + this._head = node; + } else { + current = this._head; + while (current.next) { + current = current.next; + } + current.next = node; + } + this._length++; + }); + return this; + } + + at(...index) { + let current = this._head, + currentIndex = 0, + previous; + if (index[0] === 0) { + previous = this._head; + } + while (currentIndex++ <= index[0]) { + previous = current; + current = current.next; + } + if (index.length > 1) { + previous._value = index[1]; + } + + return previous._value; + } + + insert(index, ...values) { + let current = this._head, + currentIndex = 0, + detachedHead; + if (index === 0) { + this.prepend(...values); + } else { + while (++currentIndex < index) { + current = current.next; + } + + detachedHead = current.next; + current.next = null; + this.append(...values); + current = this._head; + + while (current.next) { + current = current.next; + } + if (current.next === undefined) { + + current.next = detachedHead; + } + } + + return this; + } + + prepend(...values) { + let previousHead = this._head, + previousLength = this._length; + this._head = null; + this._length = 0; + this.append(...values); + let current = this._head, + index = 0; + while (++index < this._length) { + current = current.next; + } + if (current.next === undefined) { + current.next = previousHead; + } else { + current = null; + } + this._length += previousLength; + return this; + } + + removeAt(index) { + if (index > -1 && index < this._length) { + let current = this._head, + currentIndex = 0, + previous; + if (index === 0) { + this._head = current.next; + this._length--; + return current._value; + } else { + while (currentIndex < index) { + previous = current; + current = current.next; + currentIndex++; + } + + previous.next = current.next; + this._length--; + return current._value; + } + } else { + return null; + } + } + + toArray() { + let array = []; + for (let item of this) { + array.push(item); + } + return array; + } + + toString() { + return this.toArray().join(' -> '); + } +} + +module.exports = LinkedList; diff --git a/JS OOP/05. Class Methods and Properties/tests/tests.js b/JS OOP/05. Class Methods and Properties/tests/tests.js new file mode 100644 index 0000000..a738b69 --- /dev/null +++ b/JS OOP/05. Class Methods and Properties/tests/tests.js @@ -0,0 +1,160 @@ +'use strict'; + +const chai = require('chai'), + expect = chai.expect, + LinkedList = require('../task/task-1'); + +describe('Linked list: ', () => { + it('should have append and toString correctly', () => { + + const list = new LinkedList(), + values = [1, 2, false, 3, 4]; + + list.append(...values); + + expect(list.first).to.equal(values[0]); + expect(list.last).to.equal(values[values.length - 1]); + expect(list.length).to.equal(values.length); + expect(list.toString()).to.equal(values.join(' -> ')); + }); + + it('append should implement chaining and toString should work correctly', () => { + const values = [1, 2, 3, 4, 5, 6], + list = new LinkedList() + .append(1, 2) + .append(3, 4) + .append(5) + .append(6); + + + expect(list.first).to.equal(values[0]); + expect(list.last).to.equal(values[values.length - 1]); + expect(list.length).to.equal(values.length); + expect(list.toString()).to.equal(values.join(' -> ')); + }); + + it('should implement prepend correctly, enable chaining and toString should work correctly', () => { + + const values = [0, 1, 2, 3, 4, 5], + list = new LinkedList() + .append(3, 4) + .prepend(1, 2) + .prepend(0) + .append(5); + + + expect(list.first).to.equal(values[0]); + expect(list.last).to.equal(values[values.length - 1]); + expect(list.length).to.equal(values.length); + expect(list.toString()).to.equal(values.join(' -> ')); + }); + + it('should insert correctly', () => { + const values = [1, 2, 6, 7, 8], + list = new LinkedList().append(...values).insert(2, 3, 4).insert(4, 5); + + expect(list.first).to.equal(1); + expect(list.length).to.equal(8); + expect(list.toString()).to.equal([1, 2, 3, 4, 5, 6, 7, 8].join(' -> ')); + }); + + it('should insert correctly', () => { + const list = new LinkedList().append(1, 2).insert(0, 3, 4); + + list.insert(list.length - 1, 'kremikovci'); + + expect(list.first).to.equal(3); + expect(list.last).to.equal(2); + expect(list.length).to.equal(5); + expect(list.toString()).to.equal([3, 4, 1, 'kremikovci', 2].join(' -> ')); + + }); + + it('should have correct for-of', () => { + + const values = [5, 6, 38], + list = new LinkedList().append(...values); + + for (const val of list) { + expect(values.indexOf(val)).to.not.equal(-1); + } + }); + + it('should have correct for-of', () => { + + const values = [5, 6, 3, 'gosho', true, null, 'ivan', { message: 'Hello' }], + list = new LinkedList() + .append(...values.slice(4)) + .prepend(...values.slice(0, 4)); + + for (const val of list) { + expect(val).to.equal(values.shift()); + } + }); + + it('should have correct removeAt', () => { + const theObj = { value: 'val', message: 'hello' }; + const values = ['test', true, null, 1, 2, 'testtest', theObj, 'gg'], + list = new LinkedList().append(...values), + removed1 = list.removeAt(1), + removed2 = list.removeAt(1), + removed3 = list.removeAt(0), + removed4 = list.removeAt(list.length - 1); + + expect(list.first).to.equal(1); + expect(list.last).to.equal(theObj); + expect(list.length).to.equal(values.length - 4); + expect([removed1, removed2, removed3, removed4].join()).to.equal([true, null, 'test', 'gg'].join()); + }); + + it('should have correct indexing with at(index)', () => { + const values = 'babel src --presets es2015 --out-dir ./build -s -w'.split(' '), + list = new LinkedList().append(...values), + listLength = list.length; + + for (let i = 0, length = values.length; i < length; i += 1) { + expect(list.at(i)).to.equal(values[i]); + } + + expect(list.first).to.equal(values[0]); + expect(list.last).to.equal(values[values.length - 1]); + expect(list.length).to.equal(listLength); + }); + + it('at(0) should return the same as .first', () => { + const list = new LinkedList().append(1, 2, 3, 5); + + expect(list.at(0)).to.equal(list.first); + }); + + it('at(list.length - 1) should return the same as .last', () => { + const list = new LinkedList().append(1, 2, 3, 5); + + expect(list.at(list.length - 1)).to.equal(list.last); + }); + + it('should have correct indexing with at(index, value)', () => { + const values = 'babel src --presets es2015 --out-dir ./build -s -w'.split(' '), + list = new LinkedList().append(...values), + listLength = list.length; + + for (let i = 0, length = values.length; i < length; i += 1) { + list.at(i, i); + expect(list.at(i)).to.equal(i); + } + + expect(list.first).to.equal(0); + expect(list.last).to.equal(values.length - 1); + expect(list.length).to.equal(listLength); + }); + + it('should have correct toArray', () => { + + const values = ['test', true, null, 1, 2, 'testtest', { value: 'val', message: 'hello' }], + array = new LinkedList().append(...values).toArray(); + + expect(array instanceof Array).to.be.true; + expect(array.length).to.equal(values.length); + expect(JSON.stringify(array)).to.equal(JSON.stringify(values)); + }); +});