Context page
What is "this"? Learn about context and build your very own .
operator!
Overview
- Rules for setting context
- proto & prototype: A visual representation
- Exercise!
Video
Slides
Exercise: DOT operator
The problem
Write the DOT (.
) operator as if it was implemented in JS as a function.
For example, the following uses the DOT
operator to read properties from person
:
var Person = function(name) {
this.name = name;
}
Person.prototype.isPerson = true;
var person = new Person('Smith');
DOT(person, 'name'); //person.name
DOT(person, 'isPerson'); //person.isPerson
To solve this problem, DOT should read from the proto chain. While it can be implemented as simple as the following:
const DOT = function(obj, property){
return obj[property];
}
You should instead only use the []
property accessor when you know the object has
that direct property.
To get started, click the button at the bottom of the following:
<div id="qunit"></div>
<link rel="stylesheet" href="//code.jquery.com/qunit/qunit-1.12.0.css">
<script src="//code.jquery.com/qunit/qunit-1.12.0.js"></script>
<script type="module">
/* start DOT code here */
function DOT(object, property) {
}
/* end DOT code */
// Test code. There’s no need to edit the following:
QUnit.test("DOT works", function(){
var Person = function(name){
this.name = name;
}
Person.prototype.species = 'Homo Sapien';
Person.prototype.speak =function(toWhom) {
return 'Hello ' + toWhom + '. My name is ' + this.name + '.';
}
var person = new Person('Alexis');
var species = DOT(person, 'species');
var toString = DOT(person, 'toString');
QUnit.equal(species, 'Homo Sapien', 'property accessed');
QUnit.equal(toString, Object.prototype.toString,
'Object.prototype.toString accessed');
QUnit.equal(DOT(person, 'foobar'), undefined, 'property not found');
});
</script>
What you need to know
- The
DOT
function will take an object and a property name as a string. - hasOwnProperty returns if an object has a direct property:
var obj = {foo: "bar"}; console.log( obj.hasOwnProperty("foo") ) // Logs: true
- Object.getPrototypeOf(obj) returns the
__proto__
value of the passed obj. This is the recommended way of reading the__proto__
property.var date = new Date() console.log( Object.getPrototypeOf(date) === Date.prototype ) // Logs: true
- Recursive functions call themselves to answer a sub-problem:
function factorial(number){ if (number === 0) { return 1; } else { return number * factorial(number-1); } } console.log( factorial(4) ) // Logs: 24
The solution
<div id="qunit"></div>
<link rel="stylesheet" href="//code.jquery.com/qunit/qunit-1.12.0.css">
<script src="//code.jquery.com/qunit/qunit-1.12.0.js"></script>
<script type="module">
/* start DOT code here */
function DOT(object, property) {
if( Object.prototype.hasOwnProperty.call(object, property) ) {
return object[property];
}
var proto = Object.getPrototypeOf(object);
if( proto ) {
return DOT(proto, property);
}
}
/* end DOT code */
// Test code. There’s no need to edit the following:
QUnit.test("DOT works", function(){
var Person = function(name){
this.name = name;
}
Person.prototype.species = 'Homo Sapien';
Person.prototype.speak =function(toWhom) {
return 'Hello ' + toWhom + '. My name is ' + this.name + '.';
}
var person = new Person('Alexis');
var species = DOT(person, 'species');
QUnit.equal(species, 'Homo Sapien', 'property accessed');
QUnit.equal(DOT(person, 'foobar'), undefined, 'property not found');
});
</script>
Exercise: DOTCALL operator
The problem
Write the dot (.
) [[call]]
operator as if it was implemented in JS.
For example, instead of calling person.speak("Hi")
, we will call it as
DOTCALL(person,"speak",["Hi"])
as follows:
const Person = function(name) {
this.name = name;
}
Person.prototype.speak = function(message){
console.log(message + ' ' + this.name);
}
var person = new Person('Smith');
DOTCALL(person,"speak",["Hi"]) //person.speak("Hi")
DOTCALL( obj, prop, args )
will take:
- obj - the context of the function to call.
- prop - the property name to lookup.
- args - an array of arguments to pass to the function.
To get started, click the Run in your browser button at the bottom of the following code sample:
<div id="qunit"></div>
<link rel="stylesheet" href="//code.jquery.com/qunit/qunit-1.14.0.css">
<script src="//code.jquery.com/qunit/qunit-1.14.0.js"></script>
<script type="module">
// The DOT operator will be useful
function DOT(object, property) {
if( Object.prototype.hasOwnProperty.call(object, property) ) {
return object[property];
}
var proto = Object.getPrototypeOf(object);
if( proto ) {
return DOT(proto, property);
}
}
function DOTCALL(obj, prop, args){
}
</script>
<script>
QUnit.test('DOTCALL works', function() {
var Person = function(name){
this.name = name;
};
Person.prototype.species = 'Homo Sapien';
Person.prototype.speak = function(toWhom) {
return 'Hello ' + toWhom + '. My name is ' + this.name + '.';
};
var person = new Person('Alexis');
var speak = DOTCALL(person, 'speak', ['Justin']);
var greet = 'Hello Justin. My name is Alexis.';
equal(speak, greet, 'method called with argument');
});
</script>
What you need to know
- Use apply to
call a function (also constructor functions) with a
this
value and an array of arguments. - If the call operator (
()
) is used on a value that is not a function, an error is thrown. For this example, throw:
wherethrow new Error("${prop} is not a function");
prop
is the name of the property that is being called.
The solution
<div id="qunit"></div>
<link rel="stylesheet" href="//code.jquery.com/qunit/qunit-1.14.0.css">
<script src="//code.jquery.com/qunit/qunit-1.14.0.js"></script>
<script type="module">
// The DOT operator will be useful
function DOT(object, property) {
if( Object.prototype.hasOwnProperty.call(object, property) ) {
return object[property];
}
var proto = Object.getPrototypeOf(object);
if( proto ) {
return DOT(proto, property);
}
}
function DOTCALL(obj, prop, args){
var fn = DOT(obj, prop);
if(typeof fn === "function") {
return fn.apply(obj, args);
} else {
throw new Error(prop+" is not a function");
}
}
</script>
<script>
QUnit.test('DOTCALL works', function() {
var Person = function(name){
this.name = name;
};
Person.prototype.species = 'Homo Sapien';
Person.prototype.speak = function(toWhom) {
return 'Hello ' + toWhom + '. My name is ' + this.name + '.';
};
var person = new Person('Alexis');
var speak = DOTCALL(person, 'speak', ['Justin']);
var greet = 'Hello Justin. My name is Alexis.';
equal(speak, greet, 'method called with argument');
});
</script>