No tienes acceso a esta clase

¡Continúa aprendiendo! Únete y comienza a potenciar tu carrera

Herencia en JavaScript

16/20
Recursos

Aportes 48

Preguntas 23

Ordenar por:

¿Quieres ver más aportes, preguntas y respuestas de la comunidad?

Para hacer la herencia usando la sintaxis de prototipos podemos hacer lo siguiente:
 
Suponiendo que ya tenemos creada nuestra superclase (Student). Vamos a crear una clase (FreeStudent) que va a pasar los parámetros de inicialización al constructor de la superclase, para esto hacemos uso de la función call().

function FreeStudent(props) {
  Student.call(this, props);
}

Le pasamos como primer atributo el contexto de ejecución de nuestra nueva “clase” y como segundo parámetro los props, que son estas propiedades que recibiremos de inicialización.
 
Después de esto, clonamos el prototipo de nuestra superclase en el prototipo de nuestra subclase:

FreeStudent.prototype = Object.create(Student.prototype);

Por último, le agregamos cualquier función extra que deseemos agregar a la subclase:

FreeStudent.prototype.approveCourse = function (newCourse) {
  if (newCourse.isFree) {
    this.approvedCourses.push(newCourse);
  } else {
    console.warn(`Lo sentimos, ${this.name}, sólo puedes tomar cursos gratis`);
  }
}

Y eso es todo!
 
Fuente: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Inheritance_and_the_prototype_chain

Super
La palabra clave super es usada para acceder y llamar funciones del padre de un objeto.

Las expresiones super.prop y super[expr] son válidas en cualquier definición de método tanto para clases como para objetos literales (en-US).

Sintaxis
// llama al método constructor del objeto padre.
super([arguments]);

// llama cualquier otro método del objeto padre.
super.functionOnParent([arguments]);
Descripción
Cuando es usado en un constructor, la palabra clave super aparece sola lo cual invoca el constructor del objeto padre. En este caso debe usarse antes de que la palabra clave this sea usada. La palabra clave super también puede utilizarse para llamar otras funciones del objeto padre.
**
Ejemplo**
Usando super en clases
Este fragmento de código se toma del ejemplo de clases (demo en vivo). Aquí se llama a super() para evitar la duplicación de las partes del constructor que son comunes entre Rectangle y Square.

class Rectangle {
  constructor(height, width) {
    this.name = 'Rectangle';
    this.height = height;
    this.width = width;
  }
  sayName() {
    console.log('Hi, I am a ', this.name + '.');
  }
  get area() {
    return this.height * this.width;
  }
  set area(value) {
    this.height = this.width = Math.sqrt(value);
  }
}

class Square extends Rectangle {
  constructor(length) {
    this.height; // ReferenceError, super necesita ser llamado primero!

    // Aquí, llama al constructor de la clase padre con las longitudes
    // previstas para el ancho y la altura de Rectangle
    super(length, length);

    // Nota: En las clases derivadas, se debe llamar a super() antes de
    // poder usar 'this'. Salir de esto provocará un error de referencia.
    this.name = 'Square';
  }
}

Recuerdo haber visto en el curso de Fundamentos de JavaScript con el profesor Sacha como se creaba la herencia antes del ECMAScript 6 y era un dolor de cabeza. 🥴

Por si quieran ver, les dejo el link.

P.D.: No sé como dormían los desarrolladores de software antes del ECMAScript 6 (con razón nació JQuery en ese entonces).

Tengan en su reseña estudiantil este capitulo si tienen interés de seguir con React… Les aseguro que muchos somos los que volvemos sobre los fundamentos.

Tengo todo separado en distintos archivos:
student.js:

export default class Student {
  constructor({
    id,
    name,
    email,
    username,
    points = 0,
    twitter = undefined,
    instagram = undefined,
    facebook = undefined,
    approvedCourses = [],
    learningPaths = [],
  }) {
    this._id = id;
    this._name = name;
    this._email = email;
    this._username = username;
    this._points = points;
    this._approvedCourses = approvedCourses;
    this._learningPaths = learningPaths;
    this._socialMedia = {
      twitter,
      instagram,
      facebook,
    };
  }

  get id () {
    return this._id;
  }

  set id (newID) {
    this._id = newID;
  }

  get name () {
    return this._name;
  }

  set name (newName) {
    this._name = newName;
  }

  get email () {
    return this._email;
  }

  set email (newEmail) {
    this._email = newEmail;
  }

  get points () {
    return this._points;
  }

  set points (newPoints) {
    this._points = newPoints;
  }

  get username () {
    return this._username;
  }

  set username (newUsername) {
    this._username = newUsername;
  }

  get approvedCourses () {
    return this._approvedCourses;
  }

  set approvedCourses (newApprovedCourses) {
    this._approvedCourses = newApprovedCourses;
  }

  get learningPaths () {
    return this._learningPaths;
  }

  set learningPaths (newLearningPaths) {
    this._learningPaths = newLearningPaths;
  }

  /*get _socialMedia () {
    return this._socialMedia;
  }

  set _socialMedia (newSocialMedia) {
    this._socialMedia = newSocialMedia;
  }*/
};

freeStudent.js:

import Student from './student.js'

export default class FreeStudent extends Student {
  constructor(props) {
    super(props) //*Llama al constructor de la clase madre
  }

  approveCourse(newCourse) {
    if (newCourse.isFree){
      this.approvedCourses.push(newCourse)
    } else {
      console.warn(`Lo sentimos ${this.name}, sólo puedes tomar cursos gratis`)
    }
  }
}

basicStudent.js:

import Student from './student.js'

export default class BasicStudent extends Student {
  constructor(props) {
    super(props) //*Llama al constructor de la clase madre
  }

  approveCourse(newCourse) {
    if (newCourse.lang !== "English"){
      this.approvedCourses.push(newCourse)
    } else {
      console.warn(`Lo sentimos ${this.name}, no puedes tomar cursos en inglés`)
    }
  }
}

expertStudent.js

import Student from './student.js'

export default class ExpertStudent extends Student {
  constructor(props) {
    super(props) //*Llama al constructor de la clase madre
  }

  approveCourse(newCourse) {
    this.approvedCourses.push(newCourse)
  }
}

main.js:

import FreeStudent from './freeStudent.js'
import BasicStudent from './basicStudent.js'
import ExpertStudent from './expertStudent.js'

//* Estudiantes ---------------------
const miguel = new ExpertStudent({
  id: 1,
  name: 'Miguel',
  email: '[email protected]',
  username: 'mike',
  points: 40000,
  approvedCourses: [cursoProgramacionBasica],
  learningPaths: [escuelaDesarrolloWeb]
});
console.log(miguel);

const juan = new FreeStudent({
  id: 2,
  name: 'Juan',
  email: '[email protected]',
  username: 'juanDC',
  points:  100000,
})
console.log(juan)
juan.approveCourse(cursoProgramacionBasica)
juan.approveCourse(cursoIntroMarketingDigital)
console.log(juan.approvedCourses)

const daniel = new BasicStudent({
  id: 3,
  name: 'Daniel',
})
console.log(daniel)
daniel.approveCourse(cursoProgramacionBasica)
daniel.approveCourse(cursoIntroMarketingDigital)
console.log(daniel.approvedCourses)

Solución de herencia con la sintaxis de prototipos:

Solo me queda duda de como pasarle un parametro directamente a la instancia de una función prototipo hija. Por ejemplo ahí en mi instancia de Perro, ¿Cómo le paso el parametro de “nombre” ademas de la “raza”?. De igual manera se puede hacer accediendo a los métodos del padre.

Uncaught TypeError: juanito.approvedCousess is not a function

tengan cuidado con el nombre del atributo y del metodo approvedCouses, tuve que cambiar el nombre del método para que pueda funcionar bien al momento de usar el comando

juan.approvedCousess(cursoProgBasica);

Amo a mi querido profesor Diego. Me ha enseñado tanto ❤️

Les dejo un reto, hacer que los usuarios no puedan approbar dos veces el mismo curso!

Inheritance: Classes can also inherit from other classes. The class being inherited from is called the parent, and the class inheriting from the parent is called the child. Let’s see an example, let’s say Administrator, can inherit the properties and methods of a User class:
.

.
In the above example, User is the parent and Administrator is the child. There’s a few important things to note. Firstly, when we create the child class we need to state that it extends the parent class. Then we need to pass whatever properties we want to inherit from the parent to the child’s constructor, as well as any new properties that we will define in the child class.
Next, we call the super method. Notice that we pass it the values that we pass the child class when creating the sara object. These values are defined in the parent’s constructor so we need to run it in order for the values to be instantiated. Now we can define our child class’s properties and methods.

Sintaxis con funciones y prototipos

.
Leí varios comentarios y busqué fuera, es curioso que existan múltiples formas, me pregunto a qué se debe, en mi resultado también aplique que el constructor recibiera un objeto, y no parámetros individuales.

function Student({
    name,
    age,
    cursosAprobados = []
}) {
    this._name = name;
    this.age = age;
    this.cursosAprobados = cursosAprobados;
}

Student.prototype.aprobarCurso = function(nuevoCurso) {
    this.cursosAprobados.push(nuevoCurso);
}

Student.prototype = {
    get name() {
        return this._name;
    },
    set name(newName) {
        this._name = newName
    }
};

function FreeStudent(props){
    Student.call(this, props);
    this.tipo = props.tipo;
}

FreeStudent.prototype = Object.create(Student.prototype);

FreeStudent.prototype.aprobarCurso = function(nuevoCurso) {
    if(nuevoCurso.IsFree) {
        this.cursosAprobados.push(nuevoCurso);
    } else {
        console.warn(`Lo sentimos ${this.name} no puede aprobar el ${nuevoCurso.name}, porque no es gratis`);
    }
}

const pancho = new FreeStudent({
    name: "pancho",
    age: 18,
    tipo: "gratis"
});

const cursoDataViz = {
    name: "Curso de Data Visualization",
    IsFree: false
}

console.log(pancho);
// output
// { _name: 'pancho', age: 18, cursosAprobados: [], tipo: 'gratis' }

pancho.aprobarCurso(cursoDataViz);
// output
// Lo sentimos pancho no puede aprobar el Curso de Data Visualization, porque no es gratis

Si te salio el error

Uncaught TypeError: juanito.approvedCousess is not a function

Es porque tenia el mismo nombre de un atributo de mi** clase student **y no me lo tomaba como un método sino me lo tomaba como atributo

como puedes ver el atributo de mi clase student se llama igual que mi metodo de mi clase FreeStudent

class Student {
    constructor({
         approvedCourses = [];
   }){

Y al heredar todos los atributos de la superclase que es Student pues me marca que no es una funcion en la consola y un funcion es igual a un metodo o funcion igual a el

class FreeStudent extends Student {
    constructor(props) {
        super(props);
    }

   ** approvedCourses**(newCourse) {
        if (newCourse.isFree) {
            this.approvedCourses.push(newCourse);
        } else {
            console.log(`Lo siento, ${this.name} solo puedes tomar cursos abiertos`);
        }
    };
}

tengo compañeros que son sordos y les gustaria aprender en Platzi pero no tiene subtitulos las clases yo digo que seria buena idea agregar esa opcion.

Herencia con prototipos

function extendFrom(prototypeChild, prototypeParent) {
    var fn = function () {
    }; // funcion anonima
    fn.prototype = prototypeParent.prototype;
    prototypeChild.prototype = new fn;
    prototypeChild.prototype.constructor = prototypeChild;
}

function Person(firstName, lastName, height) {
    this.firstName = firstName;
    this.lastName = lastName;
    this.height = height;
}

Person.prototype.greet = function () {
    console.log(`Hola, me llamo ${this.firstName} ${this.lastName}`);
}

Person.prototype.imTall = function () {
    return this.height > 1.80;
}

function Developer(firstName, lastName, height) {
    this.firstName = firstName;
    this.lastName = lastName;
    this.height = height;
}

// Funcion de herencia
extendFrom(Developer, Person);

Developer.prototype.greet = function () {
    console.log(`Hola, me llamo ${this.firstName} ${this.lastName} y soy un Desarrollador`);
}

// En esta arrow function el this es Window
Person.prototype.imTall = () => this.height > 1.80;
Person.prototype.imTall = function () {
    return this.height > 1.80;
}

let sergio = new Person('Sergio Antonio', 'Ochoa Martinez', 1.175);
sergio.greet();
console.log(sergio.imTall());


let rocio = new Person('Rocio', 'Paredes', 1.65);
rocio.greet();
console.log(rocio.imTall());

let angel = new Person('Angel', 'Martinez', 1.92);
angel.greet();
console.log(angel.imTall());

let devSergio = new Developer('Sergio', 'Ochoa', 1.75);
devSergio.greet();
console.log(devSergio.imTall());

Aqui un pequeño ejemplo

class Persona {
    constructor({
        nombre, 
        edad, 
        sexo,
    }) {
        this.nombre = nombre; 
        this.edad = edad
        this.sexo = sexo
    }
}

class Hombre extends Persona {
    constructor(props) {
        super(props);
    }

    agregarSexo(sexo) {
        if(sexo === "Masculino") {
            this.sexo = sexo
        } else {
            console.warn("Ese no es tu sexo")
        }
    } 
}
# (16) **Herencia en JavaScript** En JavaScript, la herencia se puede lograr utilizando la sintaxis de clases mediante el uso de la palabra clave `class` y el método `extends`. La herencia permite que una clase herede propiedades y métodos de otra clase, creando una relación de "es un/a" entre ellas. En este contexto, la clase hija (`FreeStudent`, `BasicStudent`, `ExpertStudent`) hereda de la clase padre (`Student`). 1. **Definición de la clase** `Student`**:** * La clase `Student` tiene un constructor que inicializa propiedades como `name`, `email`, `username`, `socialMedia`, `approvedCourses`, y `learningPaths`. * Se utiliza una sintaxis especial para el constructor, donde se desestructuran las propiedades del objeto pasado como argumento. 2. **Definición de las clases hijas (**`FreeStudent`**,** `BasicStudent`**,** `ExpertStudent`**):** * Cada clase hija extiende la clase `Student` mediante la palabra clave `extends`. Esto significa que heredan todas las propiedades y métodos de la clase `Student`. * Cada clase hija tiene su propio constructor que llama al constructor de la clase padre (`super(props)`). 3. **Método** `approveCourse` **en las clases hijas:** * Cada clase hija tiene su propio método `approveCourse` que modifica el comportamiento de la función original de la clase `Student`. * `FreeStudent` solo aprueba cursos gratuitos. * `BasicStudent` aprueba cursos que no estén en inglés. * `ExpertStudent` aprueba cualquier curso. 4. **Instancias (**`juan`**,** `miguelito`**):** * Se crean instancias de las clases hijas utilizando la sintaxis `new ClassName({ ...props })`, proporcionando los datos específicos para cada estudiante. Ahora, para ilustrar la herencia y el uso de las clases, consideremos un ejemplo de definir una clase `Course` y crear instancias para luego aprobarlos usando los métodos `approveCourse` de las instancias `juan` y `miguelito`. Asumiremos la existencia de las variables `escuelaWeb` y `escuelaData`: javascriptCopy code class Course { constructor(name, lang, isFree) { this.name = name; this.lang = lang; this.isFree = isFree; } } const escuelaWeb = new Course("EscuelaWeb", "español", false); const escuelaData = new Course("EscuelaData", "english", true); juan.approveCourse(escuelaWeb); // Juan puede aprobar cursos gratuitos, así que se aprueba "EscuelaWeb". miguelito.approveCourse(escuelaData); // Miguelito no puede tomar cursos en inglés, así que se muestra una advertencia. Este ejemplo muestra cómo se heredan las propiedades y métodos de la clase `Student`, y cómo las clases hijas pueden tener comportamientos específicos a través de la sobrescritura de métodos.

nah yo me saltare lo de prototype

Después de investigar un poco, así me quedó el reto:

function Padre(a, b) {
  this.a = a;
  this.b = b;
}
Padre.prototype.sumar = function () {return this.a + this.b;};

const obj1 = new Padre(1,2);
console.group("obj1");
console.log(obj1.sumar());
console.groupEnd();

function Hijo(y,z) {
  this.y = y;
  this.z = z;
}

//Se aplica la herencia
Hijo.prototype = new Padre(1, 2); 

const obj2 = new Hijo("a", "b");
console.group("Obj2");
console.log(obj2.z);
console.log(obj2.a);
console.log(obj2.sumar());
console.groupEnd();

Que la clase tenga incluidos los archivos con el código me ayudo a encontrar un error que yo cometí, hay cursos que no tienen archivos de clase, por esto si pudiera le daba a este curso 20 estrellas.

Para aplicar herencia antes de ES6, se requerían múltiples pasos:

//primero había que construir un objeto padre

function Animal(legs){
	this.legs = legs
}

//luego asignamos un método a este prototipo (clase)
Animal.prototype.walk = function () {
	console.log("El animal camina con " + this.legs + " patas")
}

//después creamo otro prototipo que será el que herede los métodos y atributos del prototipo padre

function Dog(legs) {
	Animal.call(this, legs)
}
//usar el call es como referirse en la cadena prototipal al prototipo padre, refiriendose tambien con el this al atributo legs que tienen ambos

//luego creamos al objeto Dog con el molde que en este caso es el prototipo Animal

Dog.prototype = Object.create(Animal.prototype)
Dog.prototype.constructor = Animal

//creamos un método propio para el objeto Dog
Dog.prototype.bark = function () {
	console.log('barking')
}

//instanciamos el objeto Dog

var pitbull = new Dog(4)

pitbull.walk() //walking in 4 legs
pitbull.bark() //barking

Dejare esto por aquí:
Si tienes separado tus clases en archivos diferentes y en el mismo archivo de Student.js creaste las herencias freestudent y demás, le tienes que agregar export a cada clase ejemplo:

export class FreeStudent extends Studen

Y para importarlo a tu main.js se realiza de la siguiente manera:

import {Student, FreeStudent, BasicStudent, ExpertStudent} from './student.js'

De lo contrario no reconoce las funciones de las clases con herencia.

Así me funcionó a mi, saludos a todos!

😃 mi cara cuando veo que no entendi modulos y nos los vamos usar mas por ahora jajajajajjaja

//metodo para reproducir video
function videoPlay(id){
    const urlSecreta = "https://urlsecretamasquelanasa" + id;
    console.lod("se esta reproduciendo desde la url" + urlSecreta);
}

//metodo para pausar el video
function videoStop(id){
    const urlSecreta = "https://urlsecretamasquelanasa" + id;
    console.lod("se pauso la url" + urlSecreta);
}

//clase de platsiclass
class PlatziClass{
    constructor({
        name,
        videoId,
    }){
        this.name = name;
        this.videoId = videoId;
    }

    reproducir(){
        videoPlay(this.videoId);
    }

    pausar(){
        videoStop(this.videoId);
    }
}


// clase curso
class Course{
    constructor({
        name,
        classes = [],
        isFree = false,
        lang = "spanish",
    }){
        this._name = name;
        this.classes = classes;
        this.isFree = isFree;
        this.lang = lang;
    }

    get name(){
        return this._name;
    }

    set name(NuevoNombrecito){
        if(NuevoNombrecito === "Curso malito de programacion"){
            console.error("Web... NO!");
        }else{
            this._name = NuevoNombrecito;
        }
    }
}

//instancia de curso
const cursoProgBasica = new Course(
    {
        name : "Curso gratis de programacion basica",
        isFree: true,
});

const cursoVGS = new Course(
    {
        name : "Curso Introduccion a VGS",
        lang: "english",
});

const cursoVGS2 = new Course(
    {
        name : "Curso practico VGS"
});

const cursoDefinitivoHTML = new Course(
    {
        name : "Curso definitivo de HTML y CSS"
});

const cursoPracticoHTML = new Course({
    name : "Curso practico de HTML y CSS",
});
// clase ruta de aprendisaje
class LearningPaths{
    constructor({
        name,
        courses = []
    }){
        this._name = name;
        this.courses = courses;
    }

    get name(){
        return this._name;
    }

    set name(NuevoNombrecito){
        this._name = NuevoNombrecito;
    }
}

// instancias de  rutas de aprendisaje
const escuelaWeb = new LearningPaths({
    name: "Escuela de desarrollo web",
    courses : [
        cursoProgBasica,
        cursoDefinitivoHTML
    ]
});

const escuelaData = new LearningPaths({
    name: "Escuela de DataScience",
    courses: [
        cursoPracticoHTML,
        cursoDefinitivoHTML,
    ]
});

const escuelaVgs = new LearningPaths({
    name: "Escuela de Vgs",
    courses: [
        cursoVGS,
        cursoVGS2
    ]
});




// clase estudiante
class Student{
    constructor({
        name, 
        username,
        email,
        twitter = undefined,
        instagram = undefined,
        facebook = undefined,
        approvedCourses = [],
        learningPaths = []
    }){
        this.name = name; 
        this.username = username;
        this.email = email;
        this.socailMedia={
            twitter,
            instagram,
            facebook
        };
        this.approedCourses = approvedCourses;
        this.learningPaths = learningPaths;
    }
}   

//clase studiante Free
class StudentFree extends Student{
    constructor(props){
        super(props);
    }

    approveCourses(newCourse){
        if(newCourse.isFree){
            this.approvedCourses.push(newCourse);
        }else{
            console.warn("Lo sentimos " + this.name + ", solo puedes tomar cursos gratuitos");
        }
    }
}

class StudentBasic extends Student{
    constructor(props){
        super(props);
    }

    approveCourses(newCourse){
        if(newCourse.lang !== "english"){
            this.approvedCourses.push(newCourse);
        }else{
            console.warn("Lo sentimos " + this.name + ", no puedes tomar cursos en ingles");
        }
    }
}

class StudentExpert extends Student{
    constructor(props){
        super(props);
    }

    approveCourses(newCourse){
       this.approvedCourses.push(newCourse);
    }
}

// instancias de la clase estudiante
const victor = new StudentFree({
    name : "Victor Hugo Cruz",
    username : "hugutiobody",
    email : "[email protected]",
    learningPaths : [
        escuelaWeb,
        escuelaData
    ]
});

const vanesa = new StudentBasic({
    name : "Vanesa Pozo",
    username : "vanesita024",
    email : "[email protected]",
    learningPaths : [
        escuelaVgs,
        escuelaData
    ]
});

const emanuel = new Student({
    name : "Emanuel Cruz Pozo",
    username : "emita",
    email : "[email protected]",
    twitter : "emitas_pro"
});

Todo lo que hicimos en esta clase, debe estar escrito al final del codigo para que se declaren primero los objetos de clases, porque sino se crea el objeto clase ifFree: False; puesto que aún no era declarada, cuando fue solitiada.

la herencia me permite hacer objetos de objetos entonces se vuelve mucho mas sencillo escalar y escalar y escalar código por ejemplo acá tenia el constructor student y del constructor student con los ‘props’ heredo lo que sea que tenían los objetos anteriores a los nuevos objetos free, basic y expert entonces por ejemplo puedo agregar propiedades por defecto o agregar propiedades especificas a la clase entonces con esta opción puedo agrupar las cosas como mejor me parezca o necesite, ahorrando código innecesario y volviendo mi código mas fácil de escribir y de leer a largo plazo.-- ese seria mi resumen del curso.

Excelente clase 😃

Así me está funcionando todo. Espero en caso tal, comentarios de ustedes.

// prototypes/constructors/molds
class LearningPath {
  constructor({
    path_name,
    courses = [],
  }) {
    this.path_name = path_name;
    courses;
  };
};
class Course {
  constructor({
    name,
    classes = [],
    isFree = false,
    lang = 'spanish',
  }) {
    this._name = name;
    this.classes = classes;
    this.isFree = isFree;
    this.lang = lang;
  }

  get name() {
    return this._name;
  }
  set name(newName) {
    if (newName === '') {
      console.warn('Nombre no válido.');
    } else {
      this._name = newName;
    }
  }
};
class Student {
  constructor({
    name,
    email,
    username,
    twitter = undefined,
    instagram = undefined,
    facebook = undefined,
    approvedCourses = [],
    learningPaths = [],
  }) {
    this.name = name;
    this.email = email;
    this.approvedCourses = approvedCourses;
    this.learningPaths = learningPaths;
    this.socialMedia = {
      username,
      twitter,
      instagram,
      facebook,
    };
  };
};
class ClassForCourse {
  constructor({
    name,
    id,
    numberOfClass,
    comments = [
      numComments = 0,
      messages = [],
    ],
    questions = [],
    classResources = [
      links = [],
      text = undefined,
    ],
    nextClass,
    previousClass,
  }) {
    this.name = name;
    this.id = id;
    this.numberOfClass = numberOfClass;
    this.comments = comments;
    this.questions = questions;
    this.classResources = classResources;
    this.nextClass = nextClass;
    this.previousClass = previousClass;

  }
}
class PlatziClass {
  cosntructor({
    name,
    videoId,
  }) {
    this.name = name;
    this.videoId = videoId;
  }

  reproduce() {
    videoPlay(this.videoId);
  }
  pause() {
    videoStop(this.videoId);
  }
}
class FreeStudent extends Student {
  constructor(props) {
    super(props);
  };

  approveCourse(newCourse) {
    if(newCourse.isFree) {
      this.approvedCourses.push(newCourse);
    } else {
      console.warn('Lo sentimos ' + this.name + ', solo puedes tomar cursos abiertos o gratis.')
    }
  };
}
class BasicStudent extends Student {
  constructor(props) {
    super(props);
  };

  approveCourse(newCourse) {
    if(newCourse.lang !== 'english') {
      this.approvedCourses.push(newCourse);
    } else {
      console.warn('Lo sentimos ' + this.name + ', solo puedes tomar cursos en español.')
    }
  };
}
class ExpertStudent extends Student {
  constructor(props) {
    super(props);
  }

  approveCourse(newCourse) {
    this.approvedCourses.push(newCourse);
  };
}



function videoPlay(id) {
  const secretUrl = 'https://www.google.com/';
  console.log('Se reproduce desde la url' + secretUrl);
}
function videoStop(id) {
  const secretUrl = 'https://www.medium.com/';
  console.log('Se detuvo la url' + secretUrl);
}

// Course-lessons
const firstLinecodeLesson = new ClassForCourse({
  name: 'Mi primera línea de código',
  id: 'BPCC1',
  numberOfClass: 1,
  comments: [
    numComments = 16,
    messages = [],
  ],
  questions: [],
  classResources: [
    links = [],
    text = 'lorem ipsum in dolor sit amet',
  ],
  nextClass: '¿qué es HTML/CSS/JS?',
  previousClass: '',
})

// courses
const basicProgrammingCourse = new Course({
  name: 'Curso de Programación básica',
  classes: [
    firstLinecodeLesson,
    '¿qué es HTML/CSS/JS?',
  ],
  isFree: true,
})
const webIntroCourse = new Course({
  name: 'Introducción a la Web',
  classes: [
    'MBienvenido al Desarrollo Web',
    '¿Cómo empezó todo?',
  ]
})
const pooCourse = new Course({
  name: 'Curso de POO',
  classes: [
  '¿Por qué aprender Programación Orientada a Objetos?',
  '¿Qué resuelve la Programación Orientada a Objetos?',
  ],
  lang: 'english',
})

// grades
const webDevelopmentGrades = [
  basicProgrammingCourse,
  webIntroCourse,
  pooCourse,
];
const ExclusiveCoursesGrades = [
  'Cómo Conseguir Trabajo en Programación',
  'Curso de Finanzas para Startups',
  'Curso de Inglés Técnico para Profesionales'
];
const pythonDevGrades = [
  basicProgrammingCourse,
  webIntroCourse,
  pooCourse,
  'Curso de Fundamentos de Web Scraping con Python y Xpath',
  'Curso de Introducción al Pensamiento Computacional con Python',
];

// Colleges
const pythonDevelopmentCollege = new LearningPath({
  path_name: 'Escuela de Desarrollo en Python',
  courses: pythonDevGrades,
})
const webDevelopmentCollege = new LearningPath({
  path_name: 'Escuela de Desarrollo Web',
  courses: webDevelopmentGrades,
});
const exclusiveCoursesCollege = new LearningPath({
  path_name: 'Cursos Exclusivos', 
  courses: ExclusiveCoursesGrades,
});

// students
const andres = new FreeStudent({
  name :'Andrés',
  username: 'altair__6',
  email: '[email protected]',
  instagram: 'altair__6',
  learningPaths: [ pythonDevelopmentCollege ],
})
const felipe = new BasicStudent({
  name :'Felipe',
  username: 'Jaya__9',
  email: '[email protected]',
  instagram: 'Jaya__9',
  twitter: 'Jaya__9',
  learningPaths: [ webDevelopmentCollege, exclusiveCoursesCollege ],
})

me sale un error de Cannot read properties of undefined (reading 'push') alguien conoce alguna razon o una solucion
Esto no necesité verlo otra vez como los getters y setters 🥲 * Herencia 🫡 * SuperClase 🫡 * Extends 🫡 * Constructor(props) 🫡 * Super(props) 🫡

Lo que dice en el minuto 9:08 no es cierto, hay algunos cursos a los que solamente los profesores pueden acceder, platzi los utiliza para capacitación interna

jajaja nuevamente estoy viendo el curso y ahora entiendo menos....
Aqui no entendi nada, debo ver El curso como mil veces mas
Este es un ejemplo de código para poder dar herencia a los objetos sin necesidad de utilizar clases: ```js / Riley.cursosAprobados.push('Curso de Responsive Design'); function Student (name, age, emocion, cursosAprobados, address ) { this._name = name; this._age = age; this.emocion = emocion this.cursosAprobados = cursosAprobados; this.address = address this.aprobarCurso = function(nuevoCurso) { this.cursosAprobados.push(nuevoCurso); } } // Extension sin clases Student.prototype.aprobarCurso = function(nuevoCurso) { this.cursosAprobados.push(nuevoCurso) } // Constructor de FreeStudent function FreeStudent(name, age, emocion, cursosAprobados, address) { Student.call(this, name, age, emocion, cursosAprobados, address); this.tipo = 'Free'; } // Herencia prototipica para FreeStudent; FreeStudent.prototype = Object.create(Student.prototype); FreeStudent.prototype.constructor = FreeStudent; // Constructor de BasicStudent function BasicStudent(name, age, emocion, cursosAprobados, address) { Student.call(this, name, age, emocion, cursosAprobados, address); this.tipo = 'Basic'; } // Herencia prototipica para BasicStudent BasicStudent.prototype = Object.create(Student.prototype); BasicStudent.prototype.constructor = BasicStudent; // Constructor de ExpertStudent function ExpertStudent(name, age, emocion, cursosAprobados, address) { Student.call(this, name, age, emocion, cursosAprobados, address); this.tipo = 'Expert'; } // Herencia prototipica para ExpertStudent ExpertStudent.prototype = Object.create(Student.prototype); ExpertStudent.prototype.constructor = ExpertStudent; // Ejemplo de uso const freeStudent = new FreeStudent('Alice', 20, 'Happy', ['Math'], '123 Main St.'); const basicStudent = new BasicStudent('Bob', 22, 'Excited', ['Science'], '456 Elm St.'); const expertStudent = new ExpertStudent('Charles', 24, 'Determined', ['Physics'], '789 Oak St.'); console.log(freeStudent); console.log(basicStudent); console.log(expertStudent); ```

Esta seria la versión con la sintaxis de prototipos. Debo confesar que no lo hice yo, le mande a chatgpt hacer este trabajo 😄

function Student({
  name,
  email,
  username,
  twitter = undefined,
  instagram = undefined,
  facebook = undefined,
  approvedCourses = [],
  learningPaths = [],
}) {
  this.name = name;
  this.email = email;
  this.username = username;
  this.socialMedia = {
    twitter,
    instagram,
    facebook,
  };
  this.approvedCourses = approvedCourses;
  this.learningPaths = learningPaths;
}

function FreeStudent(props) {
  Student.call(this, props);

  this.approveCourse = function(newCourse) {
    if (newCourse.isFree) {
      this.approvedCourses.push(newCourse);
    } else {
      console.warn("Lo sentimos, " + this.name + ", solo puedes tomar cursos abiertos");
    }
  };
}

function BasicStudent(props) {
  Student.call(this, props);

  this.approveCourse = function(newCourse) {
    if (newCourse.lang !== "english") {
      this.approvedCourses.push(newCourse);
    } else {
      console.warn("Lo sentimos, " + this.name + ", no puedes tomar cursos en inglés");
    }
  };
}

function ExpertStudent(props) {
  Student.call(this, props);

  this.approveCourse = function(newCourse) {
    this.approvedCourses.push(newCourse);
  };
}

// Objeto padre
var animal = {
  tipo: "Desconocido",
  hacerSonido: function() {
    console.log("Haciendo ruido");
  }
};

// Objeto hijo que hereda de animal
var gato = Object.create(animal);
gato.tipo = "Gato";
gato.ronronear = function() {
  console.log("Ronroneando...");
};

// Crear una instancia de gato
var miGato = Object.create(gato);

// Acceder a las propiedades y métodos
console.log(miGato.tipo); // "Gato"
miGato.hacerSonido(); // "Haciendo ruido"
miGato.ronronear(); // "Ronroneando..."

Resumen de la clase📗

<aside>
🎓 Al inicio teniamos un prototipo de estudiante

</aside>

class Student{
   constructor({
    name,
    email,
    username,
    twitter = undefined,
    instagram = undefined ,
    facebook = undefined,
    approvedCourses = [],
    learningPaths = [],
   }) {
    this.name = name;
    this.email = email;
    this.username = username;
    this.socialMedia = {
        twitter,
        instagram,
        facebook,
    };
    this.approvedCourses = approvedCourses;
    this.learningPaths = learningPaths;
   }
}

<aside>
🎓 Pero necesitamos que el usuario student se sub divisione si es un usuario free, basic o expert.

</aside>


Para aquello realizamos herencias.

class FreeStudent extends Student {
    constructor(props) {
      super(props);
    }
  
    approveCourse(newCourse) {
      if (newCourse.isFree) {
        this.approvedCourses.push(newCourse);
      } else {
        console.warn("Lo sentimos, " + this.name + ", solo puedes tomar cursos abiertos porque eres un usuario free");
      }
    }
  }

<aside>
🎓 🟢 ahora hay un nuevo prototipo objeto (hijo de estudent que comparte los mismos atributos y metodos que el objeto padre estudent) ✏️

</aside>


Super

<aside>
🍀 Que es super? en POO

</aside>


  • La palabra clave super es usada para acceder y llamar funciones del padre de un objeto.
  • Las expresiones super.prop y super[expr] son válidas en cualquier definición de método tanto para clases como para objetos literales (en-US).

<aside>
🍀 Sintaxis

</aside>

llama al método constructor del objeto padre.

super([arguments]);

llama cualquier otro método del objeto padre.

super.functionOnParent([arguments]);

<aside>
🍀 Descripción

</aside>

Cuando es usado en un constructor, la palabra clave super aparece sola lo cual invoca el constructor del objeto padre. En este caso debe usarse antes de que la palabra clave this sea usada. La palabra clave super también puede utilizarse para llamar otras funciones del objeto padre.

ejemplo:

class Square extends Rectangle {
  constructor(length) {
    this.height; // ReferenceError, super necesita ser llamado primero!

    // Aquí, llama al constructor de la clase padre con las longitudes
    // previstas para el ancho y la altura de Rectangle
    super(length, length);

    // Nota: En las clases derivadas, se debe llamar a super() antes de
    // poder usar 'this'. Salir de esto provocará un error de referencia.
    this.name = 'Square';
  }
}

super - JavaScript | MDN


<aside>
🏯 Volviendo al codigo:

</aside>

const juan = new FreeStudent({
    name: "JuanDC",
    username: "juandc10",
    email:"[email protected]",
    twitter: "fjjuandc",
    learningPaths:[
        escuelaVDJ,
        escuelaDATA,
        escuelaWeb,
    ]
});

<aside>
🏯 Ahora juan ya no es solamente un prototipo estudiante, ahora Juan pasa a ser un elemento hijo del prototipo objeto padre Estudiante. Por lo que ahora necesitamos aprovar o desaporvar cursos por cada variante de estudiante.

</aside>

approveCourse(newCourse) {
      if (newCourse.isFree) {
        this.approvedCourses.push(newCourse);
      } else {
        console.warn("Lo sentimos, " + this.name + ", solo puedes tomar cursos abiertos porque eres un usuario free");
      }
    }

<aside>
🏯 En este caso juan, es un estudiante GRATIS por lo cual no puede acceder a cursos de paga como un basic.

</aside>

Lo que hacemos es validar si el curso que quiere aprovar sea free o no, si logra a ser gratis podrá sumarse a los demás cursos que juan aprueve.


¿Pero cómo se tiene en cuenta que un curso sea o no gratis o en español o ingles?

class Course{
    constructor({
        name,
        classes = [],
        isFree = false,
        lang = "spanish",
        teacher,
    }){
        this._name = name;
        this.classes = classes;
        this.isFree = isFree;
        this.lang = lang;
        this.teacher = teacher;
    }

    get name(){
        return this._name;
    }
    chamgeName(nuevoNombrecito){
        this._name = nuevoNombrecito
    }

    set name(nuevoNombrecito){
        if(nuevoNombrecito !== this.name){
            console.error("no puedes cambiar el nombre de el curso")
        }
        else{
            this._name = nuevoNombrecito;
        }
    }
}

<aside>
🏯 Para aquello volvemos a el prototipo curso y por cada objeto creado definimos si es gratis o no, en ingles o español.

</aside>


ahora si:

!A la consola!

juan.approveCourse(cursoProgBasica)

>>undefined

juan.approvedCourses
>> [Course]0:
				 Course {_name: 'Curso gratis de programacion basica', classes: Array(1), isFree: true, lang: 'spanish', teacher: Array(1)}length: 1[[Prototype]]: Array(0)

<aside>
🏯 como el curso de programacion basica es gratis, JUAN SI PUEDE aprovar el curso.

</aside>

ahora intentemos otro curso:

juan.approveCourse(cursoPracticoHTML)
>> Lo sentimos, JuanDC, solo puedes tomar cursos abiertos porque eres un usuario free
  • FUNCIONA!

Quien cambia el tema como yo en las noches a claro teniendo el cuarto oscuro 😁

Quitar scroll horizontal

Seguro ya notaste que es un poco molesto ese scroll horizontal cuando tu código se extiende demasiado.

¿Te gustaría tenerlo todo a la vista? Solo debes agregar tus preferencias en el archivo settings.json de vsc.

Abrir archivo settings.json

  • Ctrl + , (coma)
  • Open settings: Esquina derecha superior 📝
    • Icono hoja con esquina doblada y con flecha :v
{
    "editor.wordWrap": "on", //👈👀
}

Te dejo mis apuntes por si quieres ver más configuraciones Configura VSC.

Siguiendo con modulos mi code queda de la siguiente manera…

  • main.mjs
import Clases from "./clases.mjs";
import Modules from "./modules.mjs";
import Courses from "./courses.mjs";

const progBasicaClass1 = new Clases({
    name: "Hola Mundo"
})

const jsPracticoClass1 = new Clases({
    name: "DOM"
})

const jsBasicoClass1 = new Clases({
    name: "¿Por qué JavaScript?"
})

const jsBasicoClass2 = new Clases({
    name: "¿Qué es JavaScript y para qué sirve?"
})

const jsBasicoClass3 = new Clases({
    name: "Elementos de un Lenguaje de Programación: Variables, Funciones y Sintaxis"
})

const jsBasicoClass4 = new Clases({
    name: "Qué es una variable en JavaScript"
})

const jsBasicoClass5 = new Clases({
    name: "Qué son las funciones en JavaScript"
})

const jsBasicoClass6 = new Clases({
    name: "¿Qué es una función declarativa y una expresiva?"
})

const jsBasicoClass7 = new Clases({
    name: "Playground: retorna el tipo"
})

const jsBasicoClass8 = new Clases({
    name: "Quiz de Introducción a JavaScript"
})

const jsBasicoClass9 = new Clases({
    name: "Scope"
})

const jsBasicoClass10 = new Clases({
    name: "Hoisting"
})

const progBasicaModule1 = new Modules({
    name : "Introducción a Programación",
    clases : [
        progBasicaClass1,
    ]
})

const jsPracticoModule1 = new Modules({
    name : "Introducción a JavaScript Práctico",
    clases : [
        jsPracticoClass1,
    ]
})

const jsBasicoModule1 = new Modules({
    name : "Introducción a JavaScript",
    clases : [
        jsBasicoClass1,
        jsBasicoClass2,
        jsBasicoClass3,
        jsBasicoClass4,
        jsBasicoClass5,
        jsBasicoClass6,
        jsBasicoClass7,
        jsBasicoClass8
    ]
})

const jsBasicoModule2 = new Modules({
    name : "Bases de JavaScript",
    clases : [
        jsBasicoClass9,
        jsBasicoClass10
    ]
})

const jsBasico = new Courses({
    name:"Curso Básico de JavaScript",
    teacher: "Diego de Granda",
    modules: [
        jsBasicoModule1,
        jsBasicoModule2
    ]
})

const jsPractico = new Courses({
    name:"Curso Práctico de JavaScript",
    teacher: "Diego de Granda",
    lang : "english",
    modules: [
        jsPracticoModule1
    ]
})

const programacionBasica = new Courses({
    name:"Curso de Programación Básica",
    teacher: "Diego de Granda",
    isFree : true,
    modules: [
        progBasicaModule1
    ]
})

class LearningPath {
    constructor({
        name,
        courses
    }){
        this.name = name;
        this.courses = courses;
    }
}

const JavaScriptAProfundidad = new LearningPath({
    name: "JavaScript a Profundidad",
    courses:[
        jsBasico,
        /* cursoPracticoJavaScript,
        tallerPracticoJavaScriptMatematicas,
        tallerPracticoJavaScriptVideojuegos,
        cursoClosuresScope,
        cursoEcmaScript,
        cursoPOO,
        cursoBasicoPOOJavaScript */
    ]
})

class Student {
    constructor({
        name,
        username,
        age,
        email,
        learningPath = [],
        approvedCourses=[],
        facebook = undefined,
        instagram = undefined
    }) {
        this.name = name,
        this.age = age,
        this.email = email,
        this.username = username,
        this.learningPath = learningPath,
        this.approvedCourses=approvedCourses,
        this.socialMedia = {
            facebook,
            instagram
        }
    }
}

const alfonso = new Student({
    name:"Alfonso",
    email:"[email protected]",
    age:24,
    username:"rica999",
    facebook: "Ricardo Chavez",
    learningPath:[
        JavaScriptAProfundidad
    ]
})

//---------------------Herencia--------------------

class FreeStudent extends Student {
    constructor(props) { //props hereda todos los atributos de la clase madre (Student)
        super(props);//super los define como si fueran con this.props = props;
    }

    approveCourse(newCourse) {
        if (newCourse.isFree) {
            this.approvedCourses.push(newCourse);
        } else {
            console.warn("Lo sentimos, " + this.name + ", solo puedes tomar cursos abiertos");
        }
    }
}

class BasicStudent extends Student {
    constructor(props) {
        super(props);
    }

    approveCourse(newCourse) {
        if (newCourse.lang !== "english") {
            this.approvedCourses.push(newCourse);
        } else {
            console.warn("Lo sentimos, " + this.name + ", no puedes tomar cursos en inglés");
        }
    }
}

class ExpertStudent extends Student {
    constructor(props) {
        super(props);
    }

    approveCourse(newCourse) {
        this.approvedCourses.push(newCourse);
    }
}

const juan = new FreeStudent({
    name: "JuanDC",
    username: "juandc",
    email: "[email protected]",
    instagram: "fjuandc",
    learningPaths: [
        JavaScriptAProfundidad
    ],
});

const miguelito = new BasicStudent({
    name: "Miguelito",
    username: "migelitofeliz",
    email: "[email protected]",
    instagram: "migelito_feliz",
    learningPaths: [
        JavaScriptAProfundidad
    ],
});

juan.approveCourse(programacionBasica); //agregado
juan.approveCourse(jsBasico); //no agregado por no ser free
miguelito.approveCourse(programacionBasica); //agregado
miguelito.approveCourse(jsPractico); //no agregado por ser en idioma inglés

console.log(juan);
console.log(miguelito);
  • courses.mjs
export default class Courses{
    constructor({
        name,
        teacher,
        modules,
        isFree = false,
        lang = "spanish"
    }) {
        this._name = name;
        this.teacher = teacher;
        this.modules = modules;
        this.isFree = isFree;
        this.lang = lang;
    }
    get Name(){
        return this._name;
    }
    set Name(nuevoNombre){
        nuevoNombre != "" ? this._name = nuevoNombre : console.error("Nombre vacio");
    }
}

-modules.js

export default class Modules {
    constructor({
        name,
        clases
    }) {
        this._name = name;
        this.clases = clases;
    }
    get Name(){
        return this._name;
    }
    set Name(nuevoNombre){
        nuevoNombre != "" ? this._name = nuevoNombre : console.error("Nombre vacio");
    }
}
  • clases.mjs
export default class Clases {
    constructor({
        name
    }) {
        this._name = name;
    }
    get Name(){
        return this._name;
    }
    set Name(nuevoNombre){
        nuevoNombre != "" ? this._name = nuevoNombre : console.error("Nombre vacio");
    }
}

deberías de hacer una carpeta por cada clase para explicar todo con un poco mas de orden

Me funciono de la siguiente forma:

function Student({
    name,
    username,
    points,
    socialMedia = {},
    approvedCourses = [],
    learningPaths = []
}){
    this.name = name;
    this.username = username;
    this.points = points;
    this.socialMedia = socialMedia;
    this.approvedCourses = approvedCourses ;
    this.learningPaths = learningPaths;
}

const FreeStudent = Student;
FreeStudent.prototype = {
constructor: Student,
approvateCourse(newCourse){
    if(newCourse.isFree){
        this.approvedCourses.push(newCourse);
    }else{
        console.warn(`Lo siento, ${this.name}, solo puedes tomar cursos gratuitos`);
    }
}
}

Yo no sé, pero mi compañero de abajo, sí 👇

¿Cómo separar cada clase en un archivo diferente y luego heredo de una clase que está en un archivo deferente?

Yo creo que el tipo de estudiante tendría que ser un atributo en vez de un objeto, porque el estado de los estudiantes puede ir cambiando a medida que pasa el tiempo.
ejemplo:
cuando se vence el plan anual o mensual ,
cuando un estudiante free se suscribe a uno de los planes

Que pasa si miguelito quiere pasar del plan basic al plan expert? No lo veo posible con ese modelo

No vi la ventaja de usar mjs, nunca lo habia visto antes y como todo en js, no existe un standard de por que o donde usar algo, bueno, ahi esta typescript que soluciona un poco eso

Un poco confuso, debi investigar en otras paginas para poder entender, se da mucho las vueltas, poca didactica esta explicacion