getting error "property does not exist" [closed] - javascript

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 5 years ago.
Improve this question
I modified my question to be more specific. now i don't care about the desired behavior and i just need to correct syntax error
I was studying this tutorial I face with an error in this code.
severity: 'Error'
message: 'Property 'offset' does not exist on type 'PagerserviceProvider'.'
actually i have the same error for this three variables.
that.pageSize,that.offset,that.size
public async getPager(tableName:string,pageSize: number = 10) {
let pageSize = pageSize;
let offset = 0;
let limit = pageSize;
let size = await this.getTotal(tableName);
let that = this;
return {
initialPage:function(){
return new Promise((resolve,reject)=>{
var d = [];
that.executeSql(tableName,limit,offset).then((data)=>{
console.log(JSON.stringify(data));
for(var i = 0 ; i < data.rows.length ; i++)
{
d.push(data.rows.item(i));
}
resolve(d);
},(e)=>{
reject(e);
});
});
},
nextPage:function(){
if(that.offset <= that.size - that.pageSize )
{
that.offset += that.pageSize;
}
return new Promise((resolve,reject)=>{
var d = [];
that.executeSql(tableName,limit,offset).then((data)=>{
for(var i = 0 ; i < data.rows.length ; i++)
{
d.push(data.rows.item(i));
}
resolve(d);
},(e)=>{
reject(e);
});
});
}
};}

When you use the keyword function to declare a function, the function's this does not refer to the upper this. so using this in the function body, refers to the function itself.
The problem you are facing is related to the fact that your function is declared inside a class which already have a this defined, so you need a way to reference the upper this while being inside the nested function.
class Test {
hello () { console.log('hello') }
method () {
this.hello() // It will work because `this` refers to the class
function sayHello () {
return this.hello()
// it won't work because `this` refers to the function sayHello
}
return sayHello()
}
}
To bypass this limitation, you can save your upper this in a variable while your code is in the upper scope. This variable is usually called that or self.
class Test {
hello () { console.log('hello') }
method () {
var that = this // that is now refering to the class
this.hello() // It will work because `this` refers to the class
function sayHello () {
return that.hello()
// that is still refering to the class so it will succeed
}
return sayHello()
}
}
EDIT:
another trick to avoid using that is to use ES6 arrow function. Inside an arrow function, this alway refers to the upper scope.
class Test {
hello () { console.log('hello') }
method () {
this.hello() // It will work because `this` refers to the class
// `this` refers to the upper scope by default so it works
const sayHello = () => this.hello()
return sayHello()
}
}
EDIT 2:
Your code should be:
public async getPager(tableName: string, pageSize: number = 10) {
let pageSize = pageSize;
let offset = 0;
let limit = pageSize;
let size = await this.getTotal(tableName);
let that = this;
return {
initialPage: function () {
return new Promise((resolve,reject)=>{
var d = [];
that.executeSql(tableName, limit, offset).then(data => {
console.log(JSON.stringify(data));
for(var i = 0 ; i < data.rows.length ; i++) {
d.push(data.rows.item(i));
}
resolve(d);
}, e => {
reject(e);
});
});
},
nextPage: function () {
if(offset <= size - pageSize ) {
offset += pageSize;
// no need to use `that` because you used `let`
}
return new Promise((resolve, reject) => {
var d = [];
that.executeSql(tableName, limit, offset).then(data => {
for(var i = 0 ; i < data.rows.length ; i++) {
d.push(data.rows.item(i));
}
resolve(d);
}, e => {
reject(e);
});
});
}
};
}

'that' is just the name of a variable used to store the original value of 'this' at the start of your code, as the value of 'this' changes. The variable name could just as easily be 'dog' or 'apple'.
You might choose to use 'this' later on in your code instead if you intend to access the current value of 'this' at that point in time. Otherwise you will probably reference your original variable that stored it's value, e.g. 'that', 'dog' or 'apple'.

getPager is a method: If you call it with an already lost context, that will get the current this value, which is not pointing the correct context.
const someInstance = new SomeClass()
someInstance.getPager() // You call getPager directly from the someInstance context
someHTMLButton.onClick = someInstance.getPager // Here the getPager method lost its context
A solution is to bind getPager to someInstance. This way it will always have its context this pointing to someInstance.
someHTMLButton.onClick = someInstance.getPager.bind(someInstance)

Related

Which type of variable is created in the code below

In the code below is an iterator:
const cart = ['Product 0','Product 1','Product 2','Product 3','Product 4','Product 5','Product 6','Product 7','Product 8','Product 9','Product 10']
function createIterator(cart) {
let i = 0;//(*)
return {
nextProduct: function() {
//i:0; (**)
let end = (i >= cart.length);
let value = !end ? cart[i++] : undefined;
return {
end: end,
value: value
};
}
};
}
const it = createIterator(cart);
First I know a copy of the present state of the function's variables and the parameters are parsed.(Right?)...
And when you run
const it = createIterator(cart);
Is a property below created?
//i:0 (**);
Making it.next(); equivalent to
{
i:0;//state or value of i from createIterator() definition;
next : function(cart){
let end = (this.i >= cart.length);
let value = !end ? cart[this.i++] : undefined;
return {
end: end,
value: value
};
}
Or does state of the value of i in line (*) from the first code, Is what's what is modified?
Please if this point is not clear... let me know to explain better.
Calling the iterator will create an instance of i scoped to the createIterator function. The object returned from it will only have access to that specific instance of i, but i is not a property of the object returned. It only can access it due to the function scope.
You can see a little better how this works if we break your code down a little more simply:
function createIterator(cart, display) {
let i = 0;
return {
next: function() {
i++;
console.log(display + ' next: ', i);
}
};
}
const cart1 = [];
const cart2 = [];
const it1 = createIterator(cart1, 'cart1');
it1.next();
it1.next();
const it2 = createIterator(cart2, 'cart2');
it2.next();
it2.next();
Each instance of the iterator has a different copy of i and only the object returned from the iterator function can access it.

Why is a function returning undefined and how to debug it?

I'm experimenting with closures and classes in data variables and in the example below I'm getting undefined even though I placed a console.log() right before the function returns the result and it isn't undefined. It seems to work if it isn't attached to an event handler. Can someone tell me why is this happening and if there is a way to spot where exactly does the error happen? When debugging it goes from the console log straight to the error and I don't see how that makes sense.
To trigger the error run the snippet and click on the names.
The same functions in $('#Individuals').data('functions') can be chained and work fine when called in IndividualsList(), but not from the event listener, then the result becomes undefined.
$(document).ready(function() {
var thisWindow = $('#Individuals');
var randomNames = ['Sonia Small', 'Kurt Archer', 'Reese Mullins', 'Vikram Rayner', 'Jethro Kaye', 'Suhail Randolph', 'Kaydon Crouch', 'Jamaal Elliott', 'Herman Atkins', 'Sia Best', 'Kory Gentry', 'Fallon Sawyer', 'Zayyan Hughes', 'Ayomide Byers', 'Emilia Key', 'Jaxson Guerrero', 'Gracey Frazier', 'Millie Mora', 'Akshay Parker', 'Margareta Emiliana'];
var generatedIndividuals = [];
function generateIndividual(name) {
return {
IndividualName: name
};
}
function IndividualsList(element) {
var list = [];
this.add = function(thisIndividual) {
$('#Individuals').data('functions').init(element, list).add(thisIndividual);
}
this.refresh = function() {
$('#Individuals').data('functions').init(element, list).refresh();
}
this.sort = function(order) {
$('#Individuals').data('functions').init(element, list).sort(order);
}
}
thisWindow.data('functions', (function() {
var element = $();
var list = [];
return {
add: function(thisIndividual) {
list.push(thisIndividual);
return thisWindow.data('functions');
},
init: function(thisElement, thisList) {
element = thisElement;
list = thisList;
return thisWindow.data('functions');
},
refresh: function() {
var thisList = element.html('');
for (let i = 0; i < list.length; i++) {
thisList.append(
'<div>' + list[i].IndividualName + '</div>'
);
}
return thisWindow.data('functions');
},
sort: function(order) {
list.sort(function(a, b) {
if (a.IndividualName < b.IndividualName) return -1 * order;
if (a.IndividualName > b.IndividualName) return 1 * order;
return 0;
});
console.log(thisWindow.data('functions'));
return thisWindow.data('functions');
}
}
})());
for (let i = 0; i < 20; i++) {
let nameNum = Math.floor(Math.random() * randomNames.length);
let thisClient = generateIndividual(randomNames[nameNum]);
generatedIndividuals.push(thisClient);
}
(function() {
var targetElement = thisWindow.find('div.individuals-list');
var targetData = {}
targetElement.data('individualsList', new IndividualsList(targetElement));
targetData = targetElement.data('individualsList');
for (let i = 0; i < generatedIndividuals.length; i++) {
targetData.add(generatedIndividuals[i]);
}
targetData.refresh();
})();
thisWindow.on('click', '.individuals-list', function() {
var thisElem = $(this);
var order = parseInt(thisElem.data('order'));
thisWindow.find('div.individuals-list').data('individualsList').sort(order).refresh();
thisElem.data('order', order * (-1));
});
});
.individuals-list {
border: 1px solid;
cursor: pointer;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="Individuals">
<div class="individuals-list" data-order="1"></div>
</div>
https://jsfiddle.net/Kethus/ymgwrLhj/
You are referring to the wrong sort() function, hence call it incorrectly so it returns undefined. Then you call refresh() on undefined that was returned from sort. Here's why:
In your IFFE, you use .data() to set the data = new IndvidualsList on thisWindow.find('div.individuals-list')
This code:
thisWindow.find('div.individuals-list').data('individualsList')
Returns that instantiated IndividualsList Object:
IndividualsList = $1
add: function(thisIndividual)
refresh: function()
sort: function(fieldName, order)
IndividualsList Prototype
Note the sort() function's definition. Sort in this object requires two parameters, fieldName and order; yet you call sort() and only pass order;
This indicates your expectation for the sort() function is incorrect or the wrong sort function is being made available at that line of code (in the click handler).
How to debug
Set a breakpoint at line 132 of the provided JavaScript in the
Fiddle.
Click a name in the list.
While at the breakpoint (execution paused), move to the console and run this in the console:
thisWindow.find('div.individuals-list').data('individualsList')
Note the sort() function definition in the list of functions
Next, in the console run this statement:
thisWindow.find('div.individuals-list').data('individualsList').sort(order)
Note the return is undefined <-- This is the issue
The returned value doesn't transfer from the closure to the instance that called it, the class has to be changed like so:
function IndividualsList(element) {
var list = [];
this.add = function(thisIndividual) {
return $('#Individuals').data('functions').init(element, list).add(thisIndividual);
}
this.refresh = function() {
return $('#Individuals').data('functions').init(element, list).refresh();
}
this.sort = function(order) {
return $('#Individuals').data('functions').init(element, list).sort(order);
}
}
The breakpoint could have been in one of IndividualsList()'s methods so it can be noticed that the closure returns the desired object while the method does not. Different names for either the functions or methods would help to reinforce that they are separate.

Nested function repeat

I'm trying to make a function REPEAT, instead of for. Here is my code :
function REPETER(nb) {
return {
INSTRUCTIONS: function(callback) {
for(i_repeter=1;i_repeter<=nb;i_repeter++) callback();
return this ;
}
};
}
var x = 1 ;
REPETER(5)
.INSTRUCTIONS (() => {
xxx = xxx + 2 ;
alert(i_repeter);
}
);
It works well.
But :
REPETER(2)
.INSTRUCTIONS(() => {
xxx = xxx + 1 ;
REPETER(5)
.INSTRUCTIONS(() => {
xxx = xxx + 2 ;
alert(i_repeter);
}
);
}
);
doesn't work, the first REPETER does nothing.
How can i fix this ?
Thanks !
You need to declare i_repeter within the INSTRUCTIONS function. Because you're not declaring it, you're creating an implicit global. Globals are a Bad Thing, implicit ones doubly so. Since you have a repeater calling a repeater, you end up with crosstalk; the first one thinks it's done before it is.
So:
function REPETER(nb) {
return {
INSTRUCTIONS: function(callback) {
var i_repeter; // <=== Change is here
for (i_repeter = 1; i_repeter <= nb; i_repeter++) callback();
return this;
}
};
}
Also don't try to use i_repeter in your function updating xxx (and be sure to declare xxx).

Javascript closure (this) [duplicate]

This question already has answers here:
Methods in ES6 objects: using arrow functions
(6 answers)
Closed 6 years ago.
I have already looked everywhere on stackoverflow, but couldn't find any answer for this.
Uncaught TypeError: this.rsGame is not a function (same about this.addEnemy)
let game = new Phaser.Game(600,600);
let speed = 500;
let scyla = {
preload: () => {
game.load.image('bg', 'assets/bg.png');
game.load.image('pl', 'assets/pl.png');
game.load.image('enemy', 'assets/enemy.png');
},
create: () => {
game.physics.startSystem(Phaser.Physics.ARCADE)
game.add.sprite(0,0, 'bg');
this.player = game.add.sprite(300, 500, 'pl');
this.player.anchor.set(0.5);
game.physics.arcade.enable(this.player);
this.cursors = game.input.keyboard.createCursorKeys();
this.enemies = game.add.group();
// this.timer = game.time.events.loop(200, this.addEnemy(), this);
},
update: () => {
this.player.body.velocity.x = 0;
this.player.body.velocity.y = 0;
if (this.cursors.left.isDown)
this.player.body.velocity.x = speed * -1;
if (this.cursors.right.isDown)
this.player.body.velocity.x = speed;
if (this.cursors.up.isDown)
this.player.body.velocity.y = speed * -1;
if (this.cursors.down.isDown)
this.player.body.velocity.y = speed;
if (this.player.inWorld === false)
this.rsGame();
},
rsGame: () => {
game.state.start('scyla');
},
addEnemy: () => {
let enemy = game.add.sprite(300, 100, 'enemy');
game.physics.arcade.enable(enemy);
enemy.body.gravity.y = 200;
this.enemies.add(enemy);
enemy.checkWorldBounds = true;
enemy.outOfBoundsKill = true;
}
}
game.state.add('scyla', scyla);
game.state.start('scyla');
I tried things like
let self = this
this return the windows object anyway. This has something to do with closure, but I don't understand exactly
don't know how to solve this :/
Arrow function set this to the lexical scope. You're trying to access the scyla object but the arrow function is setting it to window (or whatever this is equal to at the time that you declare scyla).
Either reference scyla directly:
scyla.rsGame();
or write your methods using standard function expressions:
update: function() {
...
if (this.player.inWorld === false)
this.rsGame();
}
or shorthand method declarations:
update() {
...
if (this.player.inWorld === false)
this.rsGame();
}
Arrow functions preserve the value of this from when they are declared.
Use a regular function expression. Don't use arrow functions for this.
preload: function preload () {
// etc
}
Arrow functions have lexically scoped this. You need to use regular functions in your case so that this gets binded as usual. Change:
update: () => {
To:
update: function ( ) {
and similarly for the other properties of scyla.

Pointers and array class in javascript [duplicate]

This question already has an answer here:
Double-Queue Code needs to be reduced
(1 answer)
Closed 9 years ago.
Is there any way for me to shorten this code by using pointers?
I need to make a class that has mostly the same function as a given array class unshift,shift,push and pop but with different names.
var makeDeque = function()
{
var a= [], r=new Array(a);
length = r.length=0;
pushHead=function(v)
{
r.unshift(v);
}
popHead=function()
{
return r.shift();
}
pushTail=function(v)
{
r.push(v);
}
popTail=function()
{
return r.pop();
}
isEmpty=function()
{
return r.length===0;
}
return this;
};
(function() {
var dq = makeDeque();
dq.pushTail(4);
dq.pushHead(3);
dq.pushHead(2);
dq.pushHead("one");
dq.pushTail("five");
print("length " + dq.length + "last item: " + dq.popTail());
while (!dq.isEmpty())
print(dq.popHead());
})();
Output should be
length 5last item: five
one
2
3
4
Thanks!
Maybe I'm oversimplifying, but why not just add the extra methods you need to the Array prototype and call it directly?
I need to make a class that has mostly the same function as a given array class unshift,shift,push and pop but with different names.
I suppose you could add these "new" methods to Array.prototype.
Like this perhaps?
var makeDeque = (function (ap) {
var Deque = {
length: 0,
pushHead: ap.unshift,
popHead: ap.shift,
pushTail: ap.push,
popTail: ap.pop,
isEmpty: function () {
return !this.length;
}
};
return function () {
return Object.create(Deque);
};
})(Array.prototype);
DEMO
If it's still too long, you can always directly augment Array.prototype like others already mentionned. We agree that it's all experimental here and the only goal is to save characters.
!function (ap) {
ap.pushHead = ap.unshift;
ap.popHead = ap.shift;
ap.pushTail = ap.push;
ap.popTail = ap.pop;
ap.isEmpty = function () {
return !this.length;
};
}(Array.prototype);
function makeDeque() {
return [];
}
This can be compressed to 174 chars:
function makeDeque(){return[]}!function(e){e.pushHead=e.unshift;e.popHead=e.shift;e.pushTail=e.push;e.popTail=e.pop;e.isEmpty=function(){return!this.length}}(Array.prototype)
DEMO
Not sure why you need this, but my suggestions per best practice are:
Don't override the Array.prototype. The reason for this is because other libraries might try to do the same, and if you include these libraries into yours, there will be conflicts.
This code is not needed. var a= [], r=new Array(a);. You only need ...a = [];.
Ensure you are creating a real class. In your code, makeDeque is not doing what you want. It is returning this which when a function is not called with the new keyword will be the same as the window object (or undefined if you are using what is called as "strict mode"). In other words, you have made a lot of globals (which are usually a no-no, as they can conflict with other code too).
When you build a class, it is good to add to the prototype of your custom class. This is because the methods will only be built into memory one time and will be shared by all such objects.
So I would first refactor into something like this:
var makeDeque = (function() { // We don't need this wrapper in this case, as we don't have static properties, but I've kept it here since we do want to encapsulate variables in my example below this one (and sometimes you do need static properties).
function makeDeque () {
if (!(this instanceof makeDeque)) { // This block allows you to call makeDeque without using the "new" keyword (we will do it for the person using makeDeque)
return new makeDeque();
}
this.r = [];
this.length = 0;
}
makeDeque.prototype.setLength = function () {
return this.length = this.r.length;
};
makeDeque.prototype.pushHead=function(v) {
this.r.unshift(v);
this.setLength();
};
makeDeque.prototype.popHead=function() {
return this.r.shift();
this.setLength();
};
makeDeque.prototype.pushTail=function(v){
this.r.push(v);
this.setLength();
};
makeDeque.prototype.popTail=function() {
return this.r.pop();
this.setLength();
};
makeDeque.prototype.isEmpty=function() {
return this.r.length === 0;
};
return makeDeque;
}());
Now you could shorten this as follows, but I wouldn't recommend doing this, since, as it was well said by Donald Knuth, "premature optimization is the root of all evil". If you try to shorten your code, it may make it inflexible.
var makeDeque = (function() {
function makeDeque () {
if (!(this instanceof makeDeque)) {
return new makeDeque();
}
this.r = [];
this.length = 0;
}
makeDeque.prototype.setLength = function () {
return this.length = this.r.length;
};
for (var i=0, methodArray = [
['pushHead', 'unshift'], ['popHead', 'shift'], ['pushTail', 'push'], ['popTail', 'pop']
]; i < methodArray.length; i++) {
makeDeque.prototype[methodArray[i][0]] = (function (i) { // We need to make a function and immediately pass in 'i' here because otherwise, the 'i' inside this function will end up being set to the value of 'i' after it ends this loop as opposed to the 'i' which varies with each loop. This is a common "gotcha" of JavaScript
return function () {
var ret = this.r[methodArray[i][1]].apply(this.r, arguments);
this.setLength();
return ret;
};
}(i));
}
makeDeque.prototype.isEmpty=function() {
return this.r.length === 0;
};
return makeDeque;
}());
If you need to get the length by a length property, as opposed to a method like setLength() which sets it manually after each update, either of the above code samples could be shortened by avoiding the setLength() method, but you'd need to use the Object.defineProperty which does not work (or does not work fully) in older browsers like IE < 9.

Categories

Resources