A煤n no tienes acceso a esta clase

Crea una cuenta y contin煤a viendo este curso

Herencia en JavaScript

14/17
Recursos

Aportes 26

Preguntas 15

Ordenar por:

驴Quieres ver m谩s aportes, preguntas y respuestas de la comunidad? Crea una cuenta o inicia sesi贸n.

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 鈥渃lase鈥 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';
  }
}

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)

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).

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 鉂わ笍

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 鈥渘ombre鈥 ademas de la 鈥渞aza鈥?. De igual manera se puede hacer accediendo a los m茅todos del padre.

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

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.

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

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

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`);
        }
    };
}
//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"
});

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());

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 鈥榩rops鈥 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 馃槂

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鈥檚 see an example, let鈥檚 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鈥檚 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鈥檚 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鈥檚 constructor so we need to run it in order for the values to be instantiated. Now we can define our child class鈥檚 properties and methods.

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 ],
})

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

驴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

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

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