Skip to content

Instantly share code, notes, and snippets.

@radupotop
Created April 22, 2014 12:55
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save radupotop/11178002 to your computer and use it in GitHub Desktop.
Save radupotop/11178002 to your computer and use it in GitHub Desktop.
Interview
/*
1. Whats the difference between a local and a global variable. Implement a bug that could be
caused by accidentally forgetting to var a local variable
*/
/**
A global variable is found in the global scope, eg. the window object, and can
be accessed from any other scope.
A local variable is contained within the scope of a function and can only be
accessed from that scope or from child scopes.
*/
var i = 42;
function fn() {
for (i=0; i<10; i++) {
// ...
}
}
> i
42
> fn()
> i
10
/*
2. What does it mean to say that functions in javascript are first class objects.
*/
/**
In JS functions are objects (of type Function) and can be manipulated like any
other object:
- can be passed as arguments
- can have properties
- can have methods (apply, bind)
- can be stored in a variable
- can be returned
*/
> Function instanceof Object
true
/*
3. You want to quickly search for an object within a large nested data structure, is there any
advantage to using $.each() over traditional javascript for loops.
*/
/**
An advantage would be the ability to iterate over both Arrays and Objects using
an uniform interface.
From a performance point of view there is not much difference.
jQuery.each caches the length in case of `for` loops over Arrays, but that is not
much of an improvement since modern JSVMs can optimize that loop.
*/
/*
4. You see a piece of existing code. A javascript object, with curly braces, and an Array
declaration, both have commas after the last entry. Is this valid javascript, what are the effects
this will have on the code.
*/
var hash = { a:1, b:2, c:3, };
var list = [1,2,3,];
/**
It is valid javascript.
However, the hash declaration will give an error in older versions of IE
such as 6 and 7, because of the trailing comma (it is expecting another element).
In other browsers the hash will create an object with 3 properties as expected.
In the case of the list, some browsers like Chrome and Firefox will create a list
with length = 3 while IE will create a list with length = 4.
While a list like [1,2,3,,,] will have a length of 5 in both Chrome and Firefox.
*/
/*
5. Explain how javascript prototypical inheritance differs from classical inheritance. Implement
a subclass using javascript using the following API and test script
ParentClass::firstMethod(args...)
ParentClass::secondMethod(args...)
ChildClass::secondMethod(args...) // calls
ParentClass::secondMethod(args...)
parentClass = new ParentClass();
childClass = new ChildClass();
parentClass.firstMethod(1,2); // expect console.log('firstMethod 1');
parentClass.secondMethod(1,2); // expect console.log('secondMethod 2');
childClass.secondMethod(3,4); // expect console.log('secondMethod 4');
console.log('thirdMethod 3');
*/
/**
Instead of inheriting from a base class, JS object instances inherit from a
prototype object.
The prototype is referenced by every new instance of the object.
An object can have its own properties/methods and properties/methods
inherited from the prototype.
JS uses prototype chains: object instance C can have as prototype
object instance B which has as prototype object instance A.
A property lookup traverses the prototype chain upwards.
*/
/**
* Declare methods on the parent class' prototype
*/
function ParentClass() {}
ParentClass.prototype = {
firstMethod: function(a,b) {
console.log('firstMethod', a);
},
secondMethod: function(a,b) {
console.log('secondMethod', b);
}
};
/**
* The child class will inherit from the parent class.
*/
function ChildClass() {}
ChildClass.prototype = new ParentClass();
/**
* Create instances of each
*/
parentClass = new ParentClass();
childClass = new ChildClass();
> childClass instanceof ParentClass
true
/**
* Test
*/
parentClass.firstMethod(1,2); // console.log('firstMethod 1');
parentClass.secondMethod(1,2); // console.log('secondMethod 2');
childClass.secondMethod(3,4); // console.log('secondMethod 4');
/*
6. You have an interface with a series of buttons that load content into a single div. There is a
bug report that sometimes when a user has clicked a series of buttons, the content from the
wrong button has loaded into the div. Why has this happened and how would you fix it.
Implement your fix in the below code snippet:
<button onclick="onClick('A.html')">A</button>
<button onclick="onClick('B.html')">B</button>
<div></div>
<script>
var onClick = function(url) {
$.get(url, function(html) {
$('div').html(html);
}
}
</script>
*/
/**
This is a race condition between the two asynchronous requests.
One response can take longer to complete than the other.
We can fix this by chaining the XHR requests.
In jQuery that would be:
*/
var request;
var onClick = function(url) {
if(request) {
request = request.always(function() {
return $.get(url, function(html) {
$('div').html(html);
};
})
} else {
request = $.get(url, function(html) {
$('div').html(html);
};
}
};
/**
An approach which I like more would be using a chain of promises in AngularJS:
*/
/**
* Declare an initial promise that always resolves so that we have an
* unifom interface.
*/
var Defer = $q.defer();
Defer.resolve();
var Promise = Defer.promise;
/**
* Chain HTTP requests
*/
function onClick(url) {
Promise = Promise.then(function() {
return $http.get(url).then(function(resp) {
$('div').html(resp.data);
});
});
return Promise;
}
/**
* I wrote a bit about promises in AngularJS here:
* http://wooptoo.com/blog/promises-in-angularjs/
*/
/*
7a. You have a function that is computationally expensive, but always returns the same
answer for a given input. You can't modify the original expensiveFunction code. Implement a
wrapper function to replace the original expensiveFunction variable, that caches the output
after the first execution.
*/
var expensiveFunction = function( arg ) {
return { answer: { deep: Math.pow(arg,2) }}; // expensive
};
/**
* Alias the original function to _expFn
* and override the original with our cacheFn
*/
var _expFn = expensiveFunction;
var expensiveFunction = cacheFn;
function md5sum(){}; // blackbox
var cache = {};
/**
* Always check for a cached result before running the expensive function
*/
function cacheFn(arg) {
var argChecksum = md5sum(arg);
if(!cache[argChecksum]) {
cache[argChecksum] = _expFn(arg);
}
return cache[argChecksum];
}
/*
7b. Your application code calls the above function then modifies the value returned. What will
be returned if you call the cached version of expensiveFunction() again? How could you avoid
this? What difference would this make if expensiveFunction() function simply returned a String
or a Number?
cached = expensiveFunction();
cached.answer = 42;
test = expensiveFunction();
test.answer == ???
*/
/**
If the function returns a primitive such as a Number or a String then we can
safely alter that value without mangling the cache. Primitives are assigned
by value.
If the returned value is an Object then altering any of its properties will
mangle the cache. Objects are assigned by reference.
We can avoid this by deep copying the result using the `extend` function from
point 8.
*/
/*
8. Whats the difference between a deep clone and a shallow clone with a javascript
object. Implement jQuery.extend(true, obj1, obj2) for deep cloning.
*/
/**
A shallow clone will only copy references to objects.
A deep clone will have its own copies of every object from the original source,
except Functions, since they are immutable.
*/
/**
* Does a deep clone by default.
* Recurse into objects until hitting primitives and copying those by value.
*
* extend(dest, src1, src2...)
*/
function extend(dest) {
$.each(arguments, function(i, arg){
if (arg !== dest) {
$.each(arg, function(key, value){
if($.isPlainObject(value)) {
dest[key] = dest[key] || {};
extend(dest[key], value);
} else {
dest[key] = value;
}
});
}
});
return dest;
}
/**
* Test
*/
a={};
b={'name': 'Anne'};
c={
'action': 'has',
'fruit': ['apples', 'oranges'],
'other': {
'test1': 1,
'test2': 123,
'test3': {
'key': 'value',
'array': [5,6,7]
}
}
};
extend(a,b,c);
/*
9. Describe the javascript thread model and how it interacts with setTimeout(function(){},0)
*/
/**
JS runs in a single thread. The main code runs inside an event loop.
Asynchronous events are appended to an event queue.
On each loop tick a certain number of operations will be run (consumed from the queue).
Some operations can be expensive (can block the main thread).
With setTimeout(fn, 0) a function can be triggered to run in the next tick of the event loop,
and computationally expensive operations can be split into chunks.
*/
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment