Can't define variable in JavaScript object literal [duplicate] - javascript

This question already has answers here:
Self-references in object literals / initializers
(30 answers)
Closed 8 years ago.
Why does this code work...
var message = {
texts: {
text1: 'Hello',
text2: 'World'
},
greet: function() {
console.log(this.texts.text1 + ' ' + this.texts.text2 + '!');
}
}
message.greet();
...but this doesn't?
var message = {
texts: {
text1: 'Hello',
text2: 'World'
},
both: this.texts.text1 + ' ' + this.texts.text2 + '!',
greet: function() {
console.log(this.both);
}
}
message.greet();
It gives me "both is not defined" error. What am I missing here? Something's wrong withthis.both? I'm total newbie when it comes to object literal

Because in second case this is still not exist when you define both. if you will turn both to method, like in this example : http://jsfiddle.net/YyWMQ/ , it will work.
both: function(){ return this.texts.text1 + ' ' + this.texts.text2 + '!'}
Imho , good question , +1

var message = {
texts: {
text1: 'Hello',
text2: 'World'
},
// here this refers to the scope where message is defined
both: this.texts.text1 + ' ' + this.texts.text2 + '!',
greet: function() {
console.log(this.both);
}
}
message.greet();
To understand it you can try as given below
this.texts = {
text1: 'Alternate Hello',
text2: 'World'
};
var message = {
texts: {
text1: 'Hello',
text2: 'World'
},
// here this refers to the scope where message is defined
both: this.texts.text1 + ' ' + this.texts.text2 + '!',
greet: function() {
console.log(this.both);
}
}
message.greet();

Your misunderstanding is at the following line:
both: this.texts.text1 + ' ' + this.texts.text2 + '!',
You could use as function and return a value like:
both: function(){ return this.texts.text1 + ' ' + this.texts.text2 + '!'; } ,
And finally
greet: function() {
console.log(this.both());
}

When calling greet, `this' will be the parent obj, message. This is not the case when you're actually constructing the message object. You could write something similar like:
var Message = function () {
this.texts = {
text1: 'Hello',
text2: 'Word'
}
this.both = this.texts.text1 + ' ' + this.texts.text2 + '!';
}
Message.prototype.greet = function () {
console.log(this.both);
}
message = new Message();
message.greet();

Related

Amazon Alexa - Undefined speech response

I am trying to invoke the "AskQuestion" in the "SetLanguageIntent" to construct a speech to the user, using Alexa fact skill blueprint.
'SetMyLanguageIntent': function() {
this.attributes['language'] = this.event.request.intent.slots.languages.value;
var language = this.attributes['language'];
this.response
.speak('Okay, I will ask you some questions about ' +
language + '. Here is your first question.' +
this.AskQuestion).listen(this.AskQuestion);
this.emit(':responseReady');
},
'AskQuestion': function() {
var language = this.attributes['language'];
var currentQuestion = flashcardsDictionary[this.attributes['currentFlashcardIndex']].question;
return 'In ' + language + ', ' + currentQuestion;
},
This is the server's response:
{
"version": "1.0",
"response": {
"outputSpeech": {
"ssml": "<speak> Okay, I will ask you some questions about undefined. Here is your first question.undefined </speak>",
"type": "SSML"
},
"reprompt": {
"outputSpeech": {
"ssml": "<speak> undefined </speak>",
"type": "SSML"
}
},
Alexa utters the word "undefined" in the response, Here is the dialogue: "Okay, I will ask you some questions about undefined. Here is your first question. undefined"
Why is the response "undefined"? and how to go about fixing this issue?
Here is the the whole Code:
'use strict';
var Alexa = require('alexa-sdk');
var flashcardsDictionary = [{
question: 'how do you find the length of a string?',
rubyAnswer: 'length',
pythonAnswer: 'Len',
javascriptAnswer: 'length'
},
{
question: 'how do you print to the console or terminal?',
rubyAnswer: 'puts',
pythonAnswer: 'print',
javascriptAnswer: 'console.log'
},
{
question: 'are boolean terms capitalized or not capitalized?',
rubyAnswer: 'not capitalized',
pythonAnswer: 'capitalized',
javascriptAnswer: 'not capitalized'
}
];
var DECK_LENGTH = flashcardsDictionary.length;
var handlers = {
// Open Codecademy Flashcards
'LaunchRequest': function() {
this.attributes['language'] = '';
this.attributes['numberCorrect'] = 0;
this.attributes['currentFlashcardIndex'] = 0;
this.response
.listen('Welcome to Flashcards. In this session, do you want to test' +
' your knowledge in Ruby, Python, or Javascript?').speak(
'Which language would you like to practice?');
this.emit(':responseReady');
},
'SetMyLanguageIntent': function() {
this.attributes['language'] = this.event.request.intent.slots.languages.value;
var language = this.attributes['language'];
this.response
.speak('Okay, I will ask you some questions about ' +
language + '. Here is your first question.' +
this.AskQuestion).listen(this.AskQuestion);
this.emit(':responseReady');
},
// User gives an answer
'AnswerIntent': function() {
var userAnswer = this.event.request.intent.slots.answer.value;
var language = this.attributes['language'];
var languageAnswer = language + userAnswer;
var correctAnswer = flashcardsDictionary[this.attributes['currentFlashcardIndex']][languageAnswer];
if (userAnswer === correctAnswer) {
this.attributes['numberCorrect']++;
var numberCorrect = this.attributes['numberCorrect'];
this.response
.speak('Nice job! The correct answer is ' + correctAnswer + '. You ' +
'have gotten ' + numberCorrect + ' out of ' + DECK_LENGTH + ' ' +
language + ' questions correct.' + this.AskQuestion)
.listen(this.AskQuestion);
} else {
var numberCorrect = this.attributes['numberCorrect'];
this.response
.speak('Sorry, the correct answer is ' + correctAnswer + '. You ' +
'have gotten ' + numberCorrect + ' out of ' + DECK_LENGTH + ' ' +
language + ' questions correct. Here is your next question.' +
this.AskQuestion).listen(this.AskQuestion);
}
this.attributes['currentFlashcardIndex']++;
this.emit(':responseReady');
},
// Test my {language} knowledge
'AskQuestion': function() {
var language = this.attributes['language'];
var currentQuestion = flashcardsDictionary[this.attributes['currentFlashcardIndex']].question;
return 'In ' + language + ', ' + currentQuestion;
},
// Stop
'AMAZON.StopIntent': function() {
this.response.speak('Ok, let\'s play again soon.');
this.emit(':responseReady');
},
// Cancel
'AMAZON.CancelIntent': function() {
this.response.speak('Ok, let\'s play again soon.');
this.emit(':responseReady');
}
};
exports.handler = function(event, context, callback) {
var alexa = Alexa.handler(event, context);
alexa.registerHandlers(handlers);
alexa.execute();
};
Use this.AskQuestion() instead of this.AskQuestion as AskQuestion is a function and not an object.

Add a custom matcher in Jasmine 1.3 - shows undefined

I'm using protractor with jasmine 1.3, tried adding a custom matcher to my spec using the example here
beforeEach(function () {
utils.log("beforeEach");
this.addMatchers({
toBeGoofy: function (expected) {
if (expected === undefined) {
expected = '';
}
var pass = this.actual.hyuk === "gawrsh" + expected;
if (pass) {
this.message = "Expected " + this.actual + " not to be quite so goofy";
} else {
this.message = "Expected " + this.actual + " to be goofy, but it was not very goofy";
}
return pass;
},
});
});
note that I didn't change anything from their example.
after that, i try using it inside an "it" like that:
expect({ "hyuk": "j" }).toBeGoofy();
and i get an error:
TypeError: undefined is not a function
on the line that the matcher was used on..
any help?
The problem was the matcher definition apparently.
instead of:
if (pass) {
this.message = "Expected " + this.actual + " not to be quite so goofy";
} else {
this.message = "Expected " + this.actual + " to be goofy, but it was not very goofy";
}
this message should be an array of 2 messages, first for pass, second for not.matcher so it would be something like this:
this.message = function() {
return [
"Expected " + this.actual.hyuk + " to be gawrsh",
"Expected " + this.actual.hyuk + " not to be gawrsh"
];
};

How to set an element property from within a callback function

I have this "service" element where I would like to set the property "bookmarks" with the function getTree, which takes a callback function.
My problem is that I don't see how I could reach the property from within the callback function where "this" is undefined!!
<dom-module id="...">
<style>
:host {
display: none;
}
</style>
<script>
Polymer({
is: "bookmark-service",
properties: {
bookmarks: {
type: Array,
value: function() { return [{title:"init"}]; }
}
},
created: function() {
chrome.bookmarks.getTree(
function(bookmarkTreeNodes) {
this.bookmarks = bookmarkTreeNodes;
console.log(this.localName + '#' + this.id + ' in getTree.');
} );
console.log(this.localName + '#' + this.id + ' was created');
console.log("Bookmark: " + this.bookmarks[0].title + '.');
},
...
You could save a reference for this before calling getTree:
var that = this;
chrome.bookmarks.getTree(function(bookmarkTreeNodes) {
that.bookmarks = bookmarkTreeNodes;
console.log(that.localName + '#' + that.id + ' in getTree.');
});
You can use bind to set this in your callback function.
chrome.bookmarks.getTree(
function(bookmarkTreeNodes) {
this.bookmarks = bookmarkTreeNodes;
console.log(this.localName + '#' + this.id + ' in getTree.');
}.bind(this) );
That was a part of my problem and I prefer not to use "bind" which I fear may have side effects with this and looks more complicated.
But another problem, was the asynchronous nature of getTree. For this, I had to add an observer.
Also, the properties doesn't even exist in "created" phase, I had to use "ready"
So here is the almost final result:
properties: {
bookmarks: {
type: Array,
value: function() { return [{title:"init"}]; },
observer: 'bookready'
}
},
bookready: function(){
console.log("Bookmark ready: " + this.bookmarks[0].title + '.');
},
ready: function() {
var self = this;
chrome.bookmarks.getTree(
function(bookmarkTreeNodes) {
self.bookmarks = bookmarkTreeNodes[0].children;
}
);
console.log(this.localName + '#' + this.id + ' was readied');
console.log("Bookmark: " + this.bookmarks[0].title + '.');
},

Iterating through array and not all items are showing

See the example here - http://jsfiddle.net/jayblanchard/b2y1tagk/
With the following code I would think that I would get all three elements appended to result, but I don't. I get:
primary - bar
secondary - glorp
var elements = [{
type: 'secondary',
name: 'foo'
}, {
type: 'primary',
name: "bar"
}, {
type: 'secondary',
name: "glorp"
}];
var elementItem;
$(elements).each(function () {
if (this.type == 'primary') {
elementItem = this.type + ' - ' + this.name + '<br />';
} else {
elementItem += this.type + ' - ' + this.name + '<br />';
}
});
$('#results').append(elementItem);
So I'm thinking that I should add the += operator to the first portion of the if condition, but when I do I get this:
undefinedsecondary - foo
primary - bar
secondary - glorp
It doesn't matter what order these are in when they are generated, they just all have to be there when complete. I feel sure that I am missing something obvious, can someone tell me what that is?
elementItem = this.type + ' - ' + this.name + '<br />';
needs to be:
elementItem = this.type + ' - ' + this.name + '<br />' + elementItem;
Otherwise, you overwrite it if primary is not the first item.
Initialize it with var elementItem = ""; so it doesn't typecast elementItem to the string "undefined"
http://jsfiddle.net/b2y1tagk/3/
You are resetting your elementItem variable with = when you reach the primary type. Try appending every item in your list. Initialize the elementItem by var elementItem=''.
var elements = [{
type: 'secondary',
name: 'foo'
}, {
type: 'primary',
name: "bar"
}, {
type: 'secondary',
name: "glorp"
}];
var elementItem = '';
$(elements).each(function () {
if (this.type == 'primary') {
elementItem += this.type + ' - ' + this.name + '<br />';
} else {
elementItem += this.type + ' - ' + this.name + '<br />';
}
});
$('#results').append(elementItem);

How to Use Inheritance in JavaScript with Constructor Methods Returning Object Literals with Private Properties?

var Animal = function(config) {
config = config || {};
var name = config.name,
numLegs = config.numLegs,
weight = config.weight,
speed = config.speed,
sound = config.sound
return {
getName: function () {
return name;
},
getNumLegs: function () {
return numLegs;
},
getWeight: function () {
return weight;
},
getSpeed: function () {
return speed;
},
getSound: function () {
return sound;
},
run: function(distance, unit) {
unit = unit || 'miles';
return 'The ' + name + ' ran ' + distance + ' ' + unit;
},
speak: function() {
return 'The ' + name + ' says "' + sound + '"';
}
}
};
function DragonFly(config) {
var me = {},
numWings = config.numWings;
me.prototype = new Animal(config);
me.getNumWings = function() {
return numWings;
};
me.fly = function(distance, unit) {
unit = unit || 'miles';
return 'The ' + me.name + ' flew ' + distance + ' ' + unit;
}
return me;
}
var dragonFly = new DragonFly({
numWings: 2,
name: 'DragonFly',
numLegs: 6
});
Okay, coming from a PHP background, I don't understand inheritance in JavaScript one bit and I'd like some help.
Basically, here's what I'd like to be able to do with an instance of the dragonFly object:
dragonFly.getName(); // 'DragonFly'
dragonFly.fly(1, 'mile'); // 'The dragonfly flew 1 mile';
dragonFly.run(1, 'yard'); // 'The dragonfly ran 1 yard';
I'd also like to know how to override methods and call the parent of those overridden methods. What is wrong with my approach? All the examples above return undefined or throw an error. The main reason I went with the object-literal style is so I could make properties private.
the "fastest" way :
var Animal = function(config) {
config = config || {};
var name = config.name,
numLegs = config.numLegs,
weight = config.weight,
speed = config.speed,
sound = config.sound
return {
getName: function () {
return name;
},
getNumLegs: function () {
return numLegs;
},
getWeight: function () {
return weight;
},
getSpeed: function () {
return speed;
},
getSound: function () {
return sound;
},
run: function(distance, unit) {
unit = unit || 'miles';
return 'The ' + name + ' ran ' + distance + ' ' + unit;
},
speak: function() {
return 'The ' + name + ' says "' + sound + '"';
}
}
};
function DragonFly(config) {
var me = new Animal(config);
var numWings = config.numWings;
me.getNumWings = function() {
return numWings;
};
me.fly = function(distance, unit) {
unit = unit || 'miles';
return 'The ' + me.name + ' flew ' + distance + ' ' + unit;
}
return me;
}
var dragonFly = new DragonFly({
numWings: 2,
name: 'DragonFly',
numLegs: 6
});
You are mixing 2 kind of "inheritance" in your script , the "classical" inheritance and the prototypal inheritance , you cant do that unless you want to be in serious trouble. both work , both have their pros and cons. Stick to the "classical" inheritance , or object augmentation since you began with it.
An object literal doesnt have a prototype , functions have prototypes. That's why in my opinion js isnt "really" object oriented , but it can mimic object oriented langages
A good exercice now would be to try using functions and prototypes , though i'm not sure you could create private fields with that.
Edit : the me.name should be me.getName() since name is "private". i think.

Categories