Skip to content

Instantly share code, notes, and snippets.

@wchan2
Last active August 11, 2024 20:13
Show Gist options
  • Save wchan2/893ebb400a06edcf5c96 to your computer and use it in GitHub Desktop.
Save wchan2/893ebb400a06edcf5c96 to your computer and use it in GitHub Desktop.
JavaScript Prototypal Inheritance Exercise
npm-debug.log
node_modules

Prototypal Inheritance

A JavaScript prototypal inheritance exercise.

Requirements

  1. node.js installed
  2. node package manager (npm) installed -- should be installed with the latest version of node

Installing the Requirements

Run the below command in the terminal after having npm installed to install dependencies specified in package.json.

npm install

Exercise Instructions

There are a series of bad practices that could use prototypal inheritance oo.js. Can you refactor them and keep the tests passing?

Some tests by default will pass; try not to break them when changing them to satisfy prototypal inheritance! The specs that should pass deal more with behavior and lives in oo.js. The specs for prototypal inheritance lives in proto.js which should all be failing.

The goal is to have all the tests passing.

  1. Write the code to satisfy protoypal inheritance in oo.js.
  2. Run the tests to make sure the code still does what it does and remains functioning after the refactor.
  3. Iterate steps 1 and 2 until all steps are passing.

Running the Tests

In the terminal execute the below commands.

Watch for any file changes and run the tests.

grunt watch

Run the tests

grunt test

Run the JSHint

JSHint checks for inconsistencies in code that are typically not great practice. This could potentially help with the refactor exercise.

grunt jshint
var sys = require('sys'),
exec = require('child_process').exec;
module.exports = function(grunt) {
grunt.initConfig({
pkg: grunt.file.readJSON('package.json'),
jshint: {
files: ['oo.js', 'oo_spec.js', 'proto_spec.js'],
options: {
globals: {
console: true,
module: true,
document: true
}
}
},
watch: {
files: ['<%= jshint.files %>'],
tasks: ['jshint']
}
});
grunt.loadNpmTasks('grunt-contrib-jshint');
grunt.loadNpmTasks('grunt-contrib-watch');
grunt.registerTask('lint', ['jshint']);
grunt.registerTask('default', ['jshint']);
grunt.registerTask('test', 'Runs the jasmine tests inside the specs folder', function() {
var done = this.async();
exec('jasmine-node oo_spec.js proto_spec.js', function(error, stdout, stderror) {
sys.print(stdout, stderror);
if (error) {
done(false);
} else {
done();
}
});
});
grunt.event.on('watch', function() {
exec('grunt test', function(error, stdout, stderror) {
sys.print(stdout, stderror);
});
});
};
;(function(globals) {
'use strict';
// The Car and the Truck class have similar behavior and properties.
// Rewrite them in a way such that they share those properties.
var Vehicle = function(driver) {
this.driver = driver;
this.speed = 0;
this.drive = function(mph) {
this.speed = mph;
return this.driver + ' driving at ' + mph + ' miles per hour';
};
};
var Car = function(driver) {
this.driver = driver;
this.speed = 0;
this.drive = function(mph) {
this.speed = mph;
return this.driver + ' driving at ' + mph + ' miles per hour';
};
};
var Truck = function(driver) {
this.driver = driver;
this.speed = 0;
this.cargo = [];
this.drive = function(mph) {
this.speed = mph;
return this.driver + ' driving at ' + mph + ' miles per hour';
};
this.loadCargo = function(cargo) {
this.cargo.push(cargo);
return this;
};
this.unloadCargo = function() {
return this.cargo.pop();
};
};
globals.Vehicle = Vehicle;
globals.Truck = Truck;
globals.Car = Car;
})(exports);
var exercise = require('./oo');
// BEHAVIORAL SPECS
describe('Vehicle', function() {
'use strict';
describe('the constructor', function() {
var Vehicle;
beforeEach(function() {
Vehicle = exercise.Vehicle;
});
it('is a function', function() {
expect(Vehicle).toEqual(jasmine.any(Function));
});
describe('when called', function() {
var vehicle;
beforeEach(function() {
vehicle = new Vehicle('bob');
});
it('sets the driver', function() {
expect(vehicle.driver).toEqual('bob');
});
it('sets the initial speed', function() {
expect(vehicle.speed).toEqual(0);
});
});
});
describe('#drive', function() {
var vehicle;
beforeEach(function() {
vehicle = new exercise.Vehicle('bob');
});
it('exists', function() {
expect(vehicle.drive).toEqual(jasmine.any(Function));
});
it('drives', function() {
expect(vehicle.drive(20)).toEqual('bob driving at 20 miles per hour');
});
it('sets the speed', function() {
vehicle.drive(45);
expect(vehicle.speed).toEqual(45);
});
});
});
describe('Car', function() {
'use strict';
describe('the constructor', function() {
var Car;
beforeEach(function() {
Car = exercise.Car;
});
it('is a function', function() {
expect(Car).toEqual(jasmine.any(Function));
});
describe('when called', function() {
var car;
beforeEach(function() {
car = new Car('bob');
});
it('sets the driver', function() {
expect(car.driver).toEqual('bob');
});
it('sets the initial speed', function() {
expect(car.speed).toEqual(0);
});
});
});
describe('#drive', function() {
var car;
beforeEach(function() {
car = new exercise.Car('bob');
});
it('exists', function() {
expect(car.drive).toEqual(jasmine.any(Function));
});
it('drives', function() {
expect(car.drive(20)).toEqual('bob driving at 20 miles per hour');
});
it('sets the speed', function() {
car.drive(45);
expect(car.speed).toEqual(45);
});
});
});
describe('Truck', function() {
'use strict';
describe('the constructor', function() {
var Truck;
beforeEach(function() {
Truck = exercise.Truck;
});
it('is a function', function() {
expect(Truck).toEqual(jasmine.any(Function));
});
describe('when called', function() {
var truck;
beforeEach(function() {
truck = new Truck('bob');
});
it('sets the driver', function() {
expect(truck.driver).toEqual('bob');
});
it('sets the initial speed', function() {
expect(truck.speed).toEqual(0);
});
it('sets the initial cargo load', function() {
expect(truck.cargo).toEqual([]);
});
});
});
describe('#drive', function() {
var truck;
beforeEach(function() {
truck = new exercise.Truck('bob');
});
it('exists', function() {
expect(truck.drive).toEqual(jasmine.any(Function));
});
it('drives', function() {
expect(truck.drive(20)).toEqual('bob driving at 20 miles per hour');
});
it('sets the speed', function() {
truck.drive(45);
expect(truck.speed).toEqual(45);
});
});
describe('#loadCargo', function() {
var truck;
beforeEach(function() {
truck = new exercise.Truck('bob');
truck.loadCargo('test cargo');
});
it('adds the cargo on the truck', function() {
expect(truck.cargo).toEqual(['test cargo']);
});
it('returns itself', function() {
expect(truck.loadCargo('test')).toBe(truck);
});
});
describe('#unloadCargo', function() {
var truck,
unloadedCargo;
beforeEach(function() {
truck = new exercise.Truck('bob');
truck.cargo = ['cargo 1', 'cargo 2'];
unloadedCargo = truck.unloadCargo();
});
it('returns the latest cargo', function() {
expect(unloadedCargo).toEqual('cargo 2');
});
it('reduces the cargo load by 1', function() {
expect(truck.cargo.length).toEqual(1);
});
});
});
{
"name": "oo.js",
"version": "0.0.1",
"description": "An object oriented exercise.",
"main": "oo.js",
"devDependencies": {
"grunt": "0.4.2",
"grunt-contrib-jasmine": "0.5.2",
"grunt-contrib-watch": "0.5.3",
"grunt-contrib-jshint": "0.8.0",
"grunt-template-jasmine-requirejs": "0.1.9",
"grunt-jasmine-node": "^0.2.1"
},
"scripts": {
"preinstall": "npm install -g grunt-cli; npm -g install jasmine-node"
},
"repository": "",
"author": "William Chan",
"license": "MIT"
}
var exercise = require('./oo');
describe('Vehicle prototype', function() {
'use strict';
it('has a drive method', function() {
expect(exercise.Vehicle.prototype.drive).toEqual(jasmine.any(Function));
});
});
describe('Car', function() {
'use strict';
describe('prototype constructor', function() {
it('is Car', function() {
expect(exercise.Car.prototype.constructor).toEqual(exercise.Car);
});
});
describe('#drive', function() {
var car;
beforeEach(function() {
car = new exercise.Car('test');
});
it('is the same function as Vehicle.prototype.drive', function() {
expect(car.drive).toBe(exercise.Vehicle.prototype.drive);
});
});
});
describe('Truck', function() {
'use strict';
describe('prototype constructor', function() {
it('is Truck', function() {
expect(exercise.Truck.prototype.constructor).toEqual(exercise.Truck);
});
});
describe('#drive', function() {
var truck;
beforeEach(function() {
truck = new exercise.Truck('test');
});
it('is the same function as Vehicle.prototype.drive', function() {
expect(truck.drive).toBe(exercise.Vehicle.prototype.drive);
});
});
describe('#loadCargo', function() {
var truck;
beforeEach(function() {
truck = new exercise.Truck('test');
});
it('is on the prototype', function() {
expect(exercise.Truck.prototype.loadCargo).toEqual(jasmine.any(Function));
expect(truck.loadCargo).toBe(exercise.Truck.prototype.loadCargo);
});
});
describe('#unloadCargo', function() {
var truck;
beforeEach(function() {
truck = new exercise.Truck('test');
});
it('is on the prototype', function() {
expect(exercise.Truck.prototype.unloadCargo).toEqual(jasmine.any(Function));
expect(truck.unloadCargo).toBe(exercise.Truck.prototype.unloadCargo);
});
});
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment