קורס Front-End Web Development שיעור תרגול מחלקות


זה נושא דיון מלווה לערך המקורי ב- https://www.tocode.co.il/bundles/html5-web-development/lessons/classes-lab

הנה הפתרונות שלי לסיכום של שיעור על אובייקטים:
אני מדביק פה לכל תרגיל רק את הקטע שחסר כדי שהתכנית תעבוד ואת לא כל דף הHTML
אשמח לענות לשאלות אם שינם לגבי הפתרונות
הערה: שילבתי תחבירים שונים בכל תרגיל כמו שנראה בקורס.

תרגיל1
. ```
function Person(name){
this.age=1;
this.name=name;
}

Person.prototype.hello= function(){
return log(‘My name is ‘+this.name +’ and I am ‘+this.age+’ years old’);
};

Person.prototype.growUp= function(){
return this.age+=1;
};

. ```
תרגיל 2:

. ```
function Summer(){
this.total=0;

}

var SummerProtoType = {
add:function(num){
this.total+=num;
},
getCurrentSum:function(){
return this.total;
}
};

Summer.prototype= SummerProtoType;

. תרגיל 3: .
. class Race{
constructor(){
this.carList=[];
}

addCars(c1,c2,c3){
    this.carList.push(c1,c2,c3);

}
winner(){
    var maxCar = this.carList[0];
    for(var i=1;i<this.carList.length;i++){
            if(this.carList[i].isFasterThan(maxCar))
                maxCar=this.carList[i];
    }
    return maxCar;
}

}
. ```

תרגיל 1

function Person(name){
    this.age=1;
    this.name=name;
}

Person.prototype.hello= function(){
    return log('My name is '+this.name +' and I am '+this.age+' years old');
};

Person.prototype.growUp= function(){
    return this.age+=1;
};

תרגיל 2:

function Summer(){
    this.total=0;

}

var SummerProtoType = {
    add:function(num){
        this.total+=num;
    },
    getCurrentSum:function(){
        return this.total;
    }
};

Summer.prototype= SummerProtoType;


נראה מעולה! ושמח שמצאת את סימן הגרש ההפוך הרבה יותר קל לקרוא את הקוד ככה :slight_smile:

סוף סוף גליתי איך להשתמש בגרש ההפוך :rofl::joy: ותודה על קבלת העיטור והסרת המגבלות ממשתמש חדש :stuck_out_tongue_winking_eye:
והנה הפתרון שלי שוב לתרגיל 3 במחלקות:

class Race{
    constructor(){
        this.carList=[];
    }

    addCars(c1,c2,c3){
        this.carList.push(c1,c2,c3);

    }
    winner(){
        var maxCar = this.carList[0];
        for(var i=1;i<this.carList.length;i++){
                if(this.carList[i].isFasterThan(maxCar))
                    maxCar=this.carList[i];
        }
        return maxCar;
    }

}

יפה - שתי הצעות לשיפור:

  1. נסה לתקן את הפונקציה addCars כך שיהיה אפשר להעביר לה כל מספר של פרמטרים (לא רק 3)

  2. נסה לעדכן את הפונקציה addCars ו winner כך שתוכל לוותר על הלולאה בפונקציה winner ולהחזיר מיד את התוצאה בלי לחשב.

  3. (בונוס) לגבי חישוב המקסימום, יש ספריית JavaScript שנקראת underscore.js ובה יש פונקציה בשם max .אפשר לקרוא עליה כאן:
    https://underscorejs.org/#max

נסה לשלב ספריה זו בתוכנית שכתבת עם הלולאה ב winner ולהשתמש בפונקציה max ממנה כדי לקצר את פונקציית חיפוש המנצח אצלך בתוכנית.

טוב אז ככה תודה על הפידבק וההצעות לתיקון
אז לגבי סעיפים 1 ו2 כתבתימחדש תקוד לפי הבקשות שלך מקווה שלזה התכוונת :blush:


class Race{
    constructor(){
        this.carList=[];
    }

    addCars(){
        this.carList=Array.from(arguments);
    }
    winner(){
        
        var win = function(car,nextcar){
            
            if(car.isFasterThan(nextcar))
                 return car;
            else
                return nextcar;
           
        };

        return this.carList.reduce(win);
    
    }

}

לגבי סעיף 3 האם התכוונת שפונקציית max מספריית underscore תחליף בתוכנית את הקריאה לisFasterThan מתוך הפונקציה win ?

הי,

קודם כל שים לב לבאג שנכנס כאן שלא היה בגירסא הקודמת: קודם היה אפשר לכתוב addCars מספר פעמים וכל המכוניות היו מתווספות (בכפולות של 3 כמובן). עכשיו אפשר להעביר כל מספר פרמטרים אבל רק הקריאה האחרונה תופסת.

לגבי winner לא ביטלת את הלולאה פשוט הסתרת אותה. הפונקציה reduce עדיין מריצה את אותה לולאה. המטרה של סעיף (2) היא לחשוב איך לבטל לגמרי את החישוב בפונקציה winner כך שכלל לא יהיו השוואות בפונקציה זו. תמשיך לחשוב על זה ותגיע.

רק הערה קטנה לגבי המימוש נהוג יותר להכניס את הגדרת הפונקציה לתוך הקריאה ל reduce באופן הבא:

winner() {
  return this.carList.reduce(function(acc, nextValue) {
      return acc.isFasterThan(nextValue) ? acc : nextValue;
    });
}

ובכתיב מודרני יותר אתה תראה גם אנשים משתמשים בפונקציית חץ במקום במילה function באופן הבא:

winner() {
  return this.carList.reduce((acc, nextValue) => (
    acc.isFasterThan(nextValue) ? acc : nextValue
  ));
}

ואפשר ללמוד יותר על כתיב זה בשיעור המתאים מקורס JavaScript ES6 באתר:
https://www.tocode.co.il/bundles/es6/lessons/arrow-functions

טוב 2 המשימות שנתת גרמו לי להתעמק עם פונקציות CALL APPLY וBIND
זה בהחלט שיעור חשוב עם עבודה במערכים בכלל ואובייקטים בפרט.
תודה על הפידבק והכיוונים שנתת אני מקווה שמה שכתבתי מחדש עונה לבקשות שלך
אז הנה תרגיל 3 שוב הפעם במלואו לפי הבקשות החדשות:

<!DOCTYPE html>
<html>
<head></head>

<body>
        <p id="p_log"></p>



<script>function log(msg) {
  p_log.innerHTML += msg + '<br />';
}


function Car(color, speed) {
  // the instance is called this
  this.color = color;
  this.speed = (speed || 0);
}

Car.prototype.drive = function(speed) {
  this.speed = speed;
};

Car.prototype.isFasterThan = function(other) {
  return this.speed > other.speed;
};

//CODE HERE///

class Race{
    constructor(){
        this.carList=[];
        
    }

    addCars(...newCarList){
        var newList=this.carList.concat(newCarList);
        return this.carList=newList;
    }
    winner(){        
        var carList = this.carList;//carList hold Cars Object Array
        var carSpeedValues = carList.map(car => car.speed);//mapping values from carList var of car Objects
        var maxSpeed = Math.max(...carSpeedValues); //returm the max Number of arr  arguments
        const maxcar = carList.find( car => car.speed === maxSpeed );
        return maxcar;
    }

}


//CODE HERE//

var c1 = new Car('red');
var c2 = new Car('blue', 500);
var c3 = new Car('black');
var c4 = new Car('white-pearl',100);

var race = new Race();
race.addCars(c1, c2, c3);
race.addCars(c4);
c1.drive(20);
c3.drive(10);

var winningCar = race.winner.apply(race,race.carList);

log('And the winner is: ' + winningCar.color);
</script>    
</body>
</html>


להתעמק ב bind ו apply זה תמיד רעיון טוב :slight_smile:
וגם הבאג שהיה תוקן

אבל אם ניסית להעלים את הלולאה תצטרך לחשוב בצורה יותר יצירתית כי גם map, גם max וגם find מבצעים כל אחד לולאה.

הדרך היא לא לשנות את אופן החישוב אלא את מועד החישוב ולנסות להעביר חלק מהלוגיקה החוצה מ winner

:sunglasses: אוקיי אז כנראה שבאמת לא הבנתי כיצד להתעלם מהלולאה כי בסופו של דבר כשאני חושב על זה תמיד חייבת להיות לולאה שתעבור על מערך carList כי אין מנוס מלמצוא ככה את המכונית בעלת המהירות המקסימלית
עכשיו אני באמת סקרן להבין את המימוש שאתה מדבר עליו :upside_down_face:

לא תמיד. המכוניות לא מתחילות בפונקציה winner. אם אתה חוזר לגירסא הראשונה שלך בה addCars מקבלת רק 3 פרמטרים קל להסתכל בהוספה מי המכונית הכי מהירה עד כה ולשמור אותה בצד. כך winner יכולה להחזיר את הערך הזה במקום לחשב בעצמה.

ונגיד שאני מגדיר בהגדרת הפונקציה addCars מי היא המכונית עם המהירות המקסימלית, שם עדיין אצטרך לעבור על האובייקטים במערך carList ונגיד לשמור אותו בתור שדה במחלקה ,לא?

סוג של. מבחינת חישוב אתה לא בורח מבדיקת כל המכוניות אתה פשוט עושה את זה קצת קודם

וזה רעיון יפה שכתיב מונחה עצמים מקדם- שאפשר להזיז את החישוב למועד יותר נוח. אם אתה חושב על תוכנית שמשתמש בונה משהו צעד אחר צעד ואז בסוף לוחץ כפתור ״סיימתי״ כדאי לזכור שאפשר להקדים חלק מהחישוב ולעשות אותו תוך כדי שמשתמש עדיין בונה את המירוץ (או מה שהוא לא בונה)

וגם להיפך: יש הרבה מצבים שכל צעד בבניה חייב לקרות ממש מהר אבל דווקא בסוף יש לך כמה שניות לנשום ומשתמש יודע שהוא עכשיו מחכה למשל לרשימת הטיסות שהוא חיפש ואז אפשר להלביש על השלב הזה יותר חישובים

והכי כיף בתכנות מונחה עצמים זה שיחסית קל להעביר את הלוגיקה הזו בין פונקציות ולשמור את התוצאה במשתנה מחלקה ולקרוא אותו מפונקציה אחרת

אוקי אני מקווה שהפעם ירדתי לסוף דעתך :roll_eyes:
שוב הקוד במלואו

<!DOCTYPE html>
<html>
<head></head>

<body>
        <p id="p_log"></p>



<script>function log(msg) {
  p_log.innerHTML += msg + '<br />';
}


function Car(color, speed) {
  // the instance is called this
  this.color = color;
  this.speed = (speed || 0);
}

Car.prototype.drive = function(speed) {
  this.speed = speed;
};

Car.prototype.isFasterThan = function(other) {
  return this.speed > other.speed;
};

//CODE HERE///

class Race{
    constructor(){
        this.carList=[];
        
    }

    addCars(...newCarList){
        var newList=this.carList.concat(newCarList);
        this.maxCar = newList.reduce((prev,cur)=>cur.speed > prev.speed ? cur :prev );
        this.carList=newList;
    }
    winner(){        
        return this.maxCar;

    }

}


//CODE HERE//

var c1 = new Car('red');
var c2 = new Car('blue', 500);
var c3 = new Car('black');
var c4 = new Car('white-pearl',100);
var c5 = new Car('nitroniguma',900);
var race = new Race();
race.addCars(c1, c2, c3);
race.addCars(c4,c5);
c1.drive(20);
c3.drive(10);

var winningCar = race.winner();

log('And the winner is: ' + winningCar.color);
</script>    
</body>
</html>

ולגבי ההערה האחרונה שלך היכולת הזאת להיות דינמיים וליצור שדה באובייקט מתוך פונקציה שלו - (שדה שלא הופיעה תחילה במחלקה) משמש רק את javaScript?
זה תופס בשפות אחרות נניח java?

מעולה.

ב Java אחרות היית צריך להצהיר על השדה הזה בבנאי ואולי לתת לו ערך ראשוני. אבל JavaScript היא כמובן לא השפה הדינמית היחידה בעולם ואת אותה יכולת יש גם בפייתון ושפות רבות נוספות.

זה הפתרון שלי לתרגיל 3.

class Race{
constructor(){
this.ListOfCars = [];
this.thewinner = new Car(‘BlankCar’,0);

    }
    addCars(){
        //this.ListOfCars =  this.ListOfCars.concat(arguments);
        Array.prototype.push.apply(this.ListOfCars,arguments);
    }
    winner(){
        
        this.ListOfCars.forEach(function(car,index,arr){
            if (car.speed > this.thewinner.speed) {
                this.thewinner = car;
            }
        },this)
    return this.thewinner;
    }
}

למה זה לא עובד לי ? הבעיה היא בפונקציה שאמורה להוסיף את המכוניות למערך - לא מבין למה זה לא מוסיף


function log(msg) {
  p_log.innerHTML += msg + '<br />';
}


function Car(color, speed) {
  // the instance is called this
  this.color = color;
  this.speed = (speed || 0);
}

Car.prototype.drive = function(speed) {
  this.speed = speed;
};

Car.prototype.isFasterThan = function(other) {
  return this.speed > other.speed;
};

//add code here
function Race() {
  this.cards=[];
}
Race.prototype.addCars=function(){
  var args = [].slice.call(arguments);
  this.cards.concat(args);
}
Race.prototype.winner=function(){
  var myFun = function(winner,car) {(winner.isFasterThan(car)? winner:car);};
   
  return this.cards.reduce(myFun);
    
}

var race = new Race();
race.addCars(c1, c2, c3);

c1.drive(20);
c3.drive(10);

var winningCar = race.winner();
log('And the winner is: ' + winningCar.color);

כדאי לקרוא שוב את המשפט הראשון מההסבר על concat:

לייק 1