Reputation: 526
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
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
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