SameerShaik
SameerShaik

Reputation: 526

why the values passed in a callback are returning undefined?

Here im trying to write a custom each method as in jquery, for that in each function im checking whether the object is array-like or not and if it is array like im running a loop and calling a callback function by sending aruguments in each function. in each function im getting correct values but in call back they are returning as undefined.

var obj = document.getElementsByTagName('input');

var isArrayLike = function(obj){
	if(typeof obj.length === "number"){
		if(obj.length===0){
			return true;			
		}
		else if(obj.length>=0){
			return (obj.length)-1 in obj;	
		}
	}
	return false;
}

function cb(ob,ik){
//here value of ob is returning as 2 and id as undefined
    console.log(ob)
	console.log(ik)
	if(document.getElementById(ik).checked){
		 console.log(ik)
	}	
}

function each (obj,cb) {
	if(isArrayLike(obj)){
		for(var i=0;i<obj.length;i++){
			var id = obj[i].getAttribute('id');
			cb.call(obj,id)
		}
	}
}

each(obj,cb)

Upvotes: 2

Views: 1046

Answers (2)

e11438
e11438

Reputation: 894

According to MDN you are calling Function.prototype.call() in a wrong way.When calling the call() function first parameter is the value of this in the calling function. Parameters for the calling function starts from the second parameter in call() function.

Here is an example from MDN,

var animals = [
  { species: 'Lion', name: 'King' },
  { species: 'Whale', name: 'Fail' }
];

for (var i = 0; i < animals.length; i++) {
  (function(i) {
    this.print = function() {
      console.log('#' + i + ' ' + this.species
                  + ': ' + this.name);
    }
    this.print();
  }).call(animals[i], i);
}

You got undefined because you didn't pass a second parameter to you function with cb.call(obj,id)

So passing your parameters as 2nd and 3rd parameters to call() function will solve your problem.

function each (obj,cb) {
if(isArrayLike(obj)){
    for(var i=0;i<obj.length;i++){
        var id = obj[i].getAttribute('id');
        cb.call(obj,obj,id)
    }
}
}

Upvotes: 0

Arun P Johny
Arun P Johny

Reputation: 388316

The problem is, to call() you are passing obj and id, the first argument to call will be passed as the value of this in the callback and second argument will be passed as the value of first parameter and so on. So in your case obj is passed as the value of this and the id is passed as the value of ob, so ik has become undefined since there is no value passed to it.

One solution is to use this to refer to the current element in the callback, another is to pass the obj[i] as the this value and as the first parameter.

cb.call(obj[i], obj[i], id)

Since you are passing the dom object itself to the callback, there is no need to pass the id

var obj = document.getElementsByTagName('input');

var isArrayLike = function(obj) {
  if (typeof obj.length === "number") {
    if (obj.length === 0) {
      return true;
    } else if (obj.length >= 0) {
      return (obj.length) - 1 in obj;
    }
  }
  return false;
}

function cb(ob) {
  //here value of ob is returning as 2 and id as undefined
  console.log(ob, this)
  if (ob.checked) {
    snippet.log(ob.id)
  }
}

function each(obj, cb) {
  if (isArrayLike(obj)) {
    for (var i = 0; i < obj.length; i++) {
      cb.call(obj[i], obj[i])
    }
  }
}

function testit() {
  each(obj, cb)
}
<!-- Provides the `snippet` object, see http://meta.stackexchange.com/a/242144/134069 -->
<script src="http://tjcrowder.github.io/simple-snippets-console/snippet.js"></script>
<input type="checkbox" id="1" />
<input type="checkbox" id="2" />

<button onclick="testit()">Test</button>

Upvotes: 2

Related Questions