1、javascript的类是什么?
js没有class关键字,虽然es6增加了class关键字,类的写法接近主流的高级语言的写法了,但是毕竟可能相当长时间不会大部分浏览器都支持的,因此,先忘了js的class吧。
一般语言的类是这样写的:
public class Student
{
public string name;
public int age;
public int grade;
public Student(string name,int age,int grade)
{
this.name=name;
this.age=age;
this.grade=grade;
}
}
调用是这样的:
Student student1=new Student("小明",10,3);
Debug.WriteLine(student1.name);//小明
student1.course();//学习课程
js没有class,所以要用function代替类:
function Student(name,age,grade)
{
//public属性
this.name=name;
this.age=age;
this.grade=grade;
//public方法
this.course=function()
{
console.log("学生课程");
};
}
这样调用:
var student1=new Student("小明",10,3);
var student2=new Student("小红",9,2);
console.log("student1.name="+student1.name);//小明
console.log("student2.name="+student2.name);//小红
student1.course();//学生课程
student2.course();
实例可以直接通过.xx来访问属性和方法。至此可以说js已经完成一个类的功能了,实例化每个类,变成一个独立的存在,然后拥有自己的属性和方法。
js奇葩的地方在于他还有一个原型。
2、什么是js的原型?
我个人理解,原型就是一个静态的代码段,放在内存中的某处。原型不会因为实例的增多而增多,他始终只有一个。就是静态属性和静态方法吧,简单理解。
3、js的原型怎么访问?
通过方法名(他也被叫做构造函数)访问:
Student.prototype
实例访问有两个方法:
student1.__proto__ (此方法已废弃)
或者:
Object.getPrototypeOf(student1);
他们是等价的:
console.log(Object.getPrototypeOf(student1)===Student.prototype);//true
4、js原型到底是什么东东?
之前说了,原型可以理解为静态方法和静态属性,那么比如上面这个例子,他的原型包含了什么呢?
因为上面Student这个构造函数,他只包含了一个构造函数,里面是实例属性和实例方法,并没有原型属性和原型方法,因此他的原型里面只包含了一个构造函数。
类似这样:
{constructor:function Student(name,age,grade){xxx}}
如果这个类还有其他原型方法的话,也会出现在这个大括号里,这个原型对象是一个object,用key-value的形式存放这些数据。
5、js原型有什么用?
构造方法为什么要原型化,我觉得没什么用,但是原型方法就很有用了,如果很多实例,他们都需要调用同一个方法,那么静态方法比实例方法就好多了,因为他只需要一个。而如果是用实例方法,那这些方法都是重复的,浪费了。
6、怎么构造一个原型方法或属性?
在他的原型上面添加属性或者方法:
function Student(name,age,grade)
{
//public属性
this.name=name;
this.age=age;
this.grade=grade;
//public方法
// this.course=function()
// {
// console.log("学生课程");
// };
}
Student.prototype.course=function()
{
console.log("学生课程");
};
还可以重写整个原型,这种方法的好处是有多少属性方法一口气写了,不用像上面那样每次加一个都要声明Student.prototype.xx=xxx:
function Student(name,age,grade)
{
//public属性
this.name=name;
this.age=age;
this.grade=grade;
//public方法
// this.course=function()
// {
// console.log("学生课程");
// };
}
Student.prototype=
{
//注意这里构造函数要指向Student
constructor:Student,
course:function()
{
console.log("学生课程");
}
}
访问:
var student1=new Student("小明",10,3);
//可以把他当一个实例方法一样访问
student1.course();
Object.getPrototypeOf(student1).course();
Student.prototype.course();
7、js的类怎么实现继承?
方法一:简单粗暴直接proto对proto赋值;效果:失败
function Student()
{
this.studentValue="我是学生";
}
Student.prototype.getStudentValue=function()
{
// console.log(this.studentValue);
console.log("我是学生,直接调用");
};
function HighSchoolStudent()
{
this.highSchoolStudentValue="我是高中生";
}
HighSchoolStudent.prototype=Student.prototype;
HighSchoolStudent.prototype.getHighSchoolStudentValue=function()
{
//console.log(this.highSchoolStudentValue);
console.log("我是高中生,直接调用");
};
调用方法:
var student1=new Student();
console.log(student1.studentValue);//我是学生
student1.getStudentValue();//我是学生,直接调用
console.log(student1.highSchoolStudentValue);//undefined
student1.getHighSchoolStudentValue();//我是高中生,直接调用
可以看到,子类和父类共享一个prototype,当子类的prototype改变,父类的prototype也跟着改变,当子类添加了一个原型方法,父类也跟着有这个原型方法,这当然是错误的。
正确的通过原型继承的时候,当完成这个原型继承的时候(还未修改constructor指向之前),子类和父类的原型确实是一样的,但是,子类在后面对原型进行修改的时候,是绝对不会影响到父类的原型的。所以这种直接proto-proto赋值的方法是行不通的。
方法二:用父类的一个实例来给子类的proto赋值;效果:有问题
function Student()
{
this.studentValue="我是学生";
}
Student.prototype.getStudentValue=function()
{
console.log(this.studentValue);
// console.log("我是学生,直接调用");
};
function HighSchoolStudent()
{
this.highSchoolStudentValue="我是高中生";
}
HighSchoolStudent.prototype=new Student();
// HighSchoolStudent.prototype=Object.create(Student.prototype);
// HighSchoolStudent.prototype=createobject(Student.prototype);
HighSchoolStudent.prototype.constructor=HighSchoolStudent;
HighSchoolStudent.prototype.getHighSchoolStudentValue=function()
{
console.log(this.highSchoolStudentValue);
};
调用结果:
var hightSchoolStudent=new HighSchoolStudent();
console.log(hightSchoolStudent.studentValue);//我是学生
hightSchoolStudent.getStudentValue();//我是学生
console.log(hightSchoolStudent.highSchoolStudentValue);//我是高中生
hightSchoolStudent.getHighSchoolStudentValue();//我是高中生
可以看到,用过这种方式,父类的实例属性全部都带过来了,这个是不行的,这个还要原型有什么意义?
方法三:对父类使用Object.create(proto)给子类的proto赋值;效果:成功
function Student()
{
this.studentValue="我是学生";
}
Student.prototype.getStudentValue=function()
{
// console.log(this.studentValue);
console.log("我是学生,直接调用");
};
function HighSchoolStudent()
{
this.highSchoolStudentValue="我是高中生";
}
// HighSchoolStudent.prototype=new Student();
HighSchoolStudent.prototype=Object.create(Student.prototype);
// HighSchoolStudent.prototype=createobject(Student.prototype);
HighSchoolStudent.prototype.constructor=HighSchoolStudent;
HighSchoolStudent.prototype.getHighSchoolStudentValue=function()
{
console.log(this.highSchoolStudentValue);
};
调用结果:
var hightSchoolStudent=new HighSchoolStudent();
console.log(hightSchoolStudent.studentValue);//undefined
hightSchoolStudent.getStudentValue();//我是学生,直接调用
console.log(hightSchoolStudent.highSchoolStudentValue);//我是高中生
hightSchoolStudent.getHighSchoolStudentValue();//我是高中生
这是es5新增的方法,可以看到父类的实例属性已经访问不到了,但是原型方法还是可以访问到,成功。
方法四:对父类使用createobject(proto)给子类的proto赋值;效果:成功
function Student()
{
this.studentValue="我是学生";
}
Student.prototype.getStudentValue=function()
{
// console.log(this.studentValue);
console.log("我是学生,直接调用");
};
function HighSchoolStudent()
{
this.highSchoolStudentValue="我是高中生";
}
// HighSchoolStudent.prototype=new Student();
// HighSchoolStudent.prototype=Object.create(Student.prototype);
HighSchoolStudent.prototype=createobject(Student.prototype);
HighSchoolStudent.prototype.constructor=HighSchoolStudent;
HighSchoolStudent.prototype.getHighSchoolStudentValue=function()
{
console.log(this.highSchoolStudentValue);
};
function createobject(proto)
{
function F(){}
F.prototype=proto;
return new F();
}
调用结果:
var hightSchoolStudent=new HighSchoolStudent();
console.log(hightSchoolStudent.studentValue);//undefined
hightSchoolStudent.getStudentValue();//我是学生,直接调用
console.log(hightSchoolStudent.highSchoolStudentValue);//我是高中生
hightSchoolStudent.getHighSchoolStudentValue();//我是高中生
可以看到结果跟方法三是一样的。
方法五:对方法四进行封装。完美
把方法4封装一下,把构造函数的重新指向也封装到里面,免得漏掉了:
function Student()
{
this.studentValue="我是学生";
}
Student.prototype.getStudentValue=function()
{
// console.log(this.studentValue);
console.log("我是学生,直接调用");
};
function HighSchoolStudent()
{
this.highSchoolStudentValue="我是高中生";
}
// HighSchoolStudent.prototype=new Student();
// HighSchoolStudent.prototype=Object.create(Student.prototype);
// HighSchoolStudent.prototype=createobject(Student.prototype);
// HighSchoolStudent.prototype.constructor=HighSchoolStudent;
inherits(HighSchoolStudent,Student);
HighSchoolStudent.prototype.getHighSchoolStudentValue=function()
{
console.log(this.highSchoolStudentValue);
};
function inherits(Child,Parent)
{
function F(){}
F.prototype=Parent.prototype;
Child.prototype=new F();
Child.prototype.constructor=Child;
}
function createobject(proto)
{
function F(){}
F.prototype=proto;
return new F();
}
调用结果:
var hightSchoolStudent=new HighSchoolStudent();
console.log(hightSchoolStudent.studentValue);//undefined
hightSchoolStudent.getStudentValue();//我是学生,直接调用
console.log(hightSchoolStudent.highSchoolStudentValue);//我是高中生
hightSchoolStudent.getHighSchoolStudentValue();//我是高中生
可以看到,结果跟上面都是一样的。完美。
8、构造函数参数不同的子类
function Student(name,age,grade)
{
this.name=name;
this.age=age;
this.grade=grade;
}
Student.prototype.course=function()
{
console.log("学生课程");
};
function HighSchoolStudent(name,age,grade,division)
{
Student.call(this,name,age,grade);
this.division=division;
}
inherits(HighSchoolStudent,Student);
HighSchoolStudent.prototype.highCourse=function()
{
console.log("高中课程");
};
function inherits(Child,Parent)
{
function F(){}
F.prototype=Parent.prototype;
Child.prototype=new F();
Child.prototype.constructor=Child;
}
function createobject(proto)
{
function F(){}
F.prototype=proto;
return new F();
}
调用:
var student1=new Student("小明",10,3);
student1.course();
//student1.highCourse();//访问报错student1.highCourse is not a function
console.log(student1.division);//undefined
var highStudent1=new HighSchoolStudent("大鹏",15,12,"文科");
highStudent1.course();//学生课程
highStudent1.highCourse();//高中课程
console.log(highStudent1.division);//文科