例2:
Person.prototype = {
toString : function (){ //person.toString(),返回hehe,访问的是Person.prototype中的toString,不是原型链终端,这种和原型链终端名字一样的方法但实现不同功能的东西叫做方法的重写
return "hehe";
}
}
function Person (){
}
var person = new Person();
例3:
Number.prototype.toString();
Boolean.prototype.toString();
Array.prototype.toString();
String.prototype.toString(); //这些方法都是将toString方法进行了重写,每次访问时都是自己的toString。
例4:
var obj = {}; //创造空对象
document.write(obj); //其实每次document.write打印的都是目标的toString()方法,上一条语句创建了一个空的对象,但是也有原型,所以可以打印结果为[object Object]
例5:
var obj = Object.create(null); //用Object.create创建出的对象没有原型,所以也没有toString()方法,所以结果为报错
document.write(obj);
例6:
var obj = Object.create(null);
obj.toString = function (){ //人为添加上一个toString方法就可以正常访问了
return "hahhahah";
}
document.write(obj);
(3)
在控制台打印0.14 * 100时返回结果非14,这是由于javascript精度不准的原因,所以在javascript中尽量避免小数操作
进行小数操作的话可以利用Math.ceil()函数(向上取整),或者Math.floor()函数(向下取整),例如Math.ceil(124.141);返回结果为125,Math.ceil(124.141);返回结果为124
还有Math.random();这是随机产生一个(0,1)之间的开区间数
for(var i = 0;i < 10 ; i++){
var a = Math.random().toFixed(2) * 100; //这时输出一个0-100之间的随机数,但有时会不准会显示28.000000000000004,因为会产生精度的小偏差。
console.log(a);
}
因为上面的代码得到的数会有精度的偏差,所以一般用下面的代码实现取随机数。
for(var i = 0;i < 10 ; i++){
var a =Math.floor( Math.random()* 100); //取整就一定不会有精度的偏差了。
console.log(a);
}
(4)
javascript可正常计算的范围,前16位,后16位,
61.call/apply
1.之前Person()代表一个函数或者方法的执行,但其实Person.call()才是它执行的根本面貌。
2.call与apply的区别
call需要把实参按照形参的个数传进去
apply需要传一个arguments
3.call与apply干嘛的,有什么区别
就一个功能:改变this指向的
区别:传参列表不同
Person.call(obj),当向Person.call()中的一个参数传对象的话,它就会在Person执行时候让里面的this指向发生改变,指向你传进去的那个对象,如下例,这是借用别的函数,在此例中并不影响person。
例1:
function Person(name,age){
this.name = name; //这就变成了obj.name = name; obj.age = age;
this.age = age;
}
var person = new Person("LFY",100);
var obj = {
}
Person.call(obj,"LFY",100);
例2:Person函数和Student函数都需要name,age,sex属性,所以可以像下例中一样,具体解释见注释,还有当使用call时,只适用于自己的需求完全覆盖别人的需求时,没办法自己选择,无法实现需要哪个属性使用哪个属性。但是不想使用某个属性可以传参时传进去undefined,
function Person (name,age,sex){
this.name = name;
this.age = age;
this.sex = sex;
}
function Student (name, age, sex, tel, grade){
Person.call (this, name, age, tel); //参数中的this,是构造函数三步中第一步中的this,然后利用Person中的方法实现了自己功能的封装,其实这个也可以理解为将Person中的的三条语句直接拿到了自己(this)的函数中。总结就是用Person里的三个属性加上自己的两个属性把自己给实现了。
this.tel = tel;
this.grade = grade;
}
var student = new Student("LFY",21,'male', 110,2);
例3:call最终完整实例
在原型,原型链,call/apply下中1小时45分时有例题
62.继承发展史
1.传统形式
过多的继承了没用的属性
2.借用构造函数(勉强算继承,只是用别人的东西完成了自己的事,实际上不算是继承)
不能继承借用构造函数的原型
每次构造函数都要多走一个函数(只是视觉上操作上省了,但是实际上什么都没省,效率也没提高)
一般在工业开发中,只要是有这种我要的东西覆盖了你,就建议使用第二种
3.共享原型,在继承的角度上,最好用这种
例1: Son.prototype = Father.prototype;实现共享原型
Father.prototype.lastname = "Liu";
function Father (){
}
function Son (){
}
Son.prototype = Father.prototype; //son.lastname = "Liu" father.lastname = "Liu"
var son = new Son();
var father = new Father();
抽象出一种功能封装成函数,函数就代表功能,函数代表功能的复用,哪里能复用,哪里能定义化,通过参数来实现。
例2:咱不是想让对象去继承某个东西,而是想要构造函数继承某个东西,这样,通过这个构造函数生产出的所有对象就全继承那个东西了,这句话是针对function(Targer,Origin)说的
Father.prototype.lastname = "Liu";
function Father (){
}
function Son (){
}
function inherit(Target,Origin){
Target.prototype = Origin.prototype;
}
inherit(Son,Father);
var son = new Son(); //son.lastname结果为Liu
例3:一定要先继承后使用,本题中先使用后继承结果就为undefined
Father.prototype.lastname = "Liu";
function Father (){
}
function Son (){
}
function inherit(Target,Origin){
Target.prototype = Origin.prototype;
}
var son = new Son(); //son.lastname结果为undefined,因为已经生成对象了,已经确定原型了,所以后面的继承也不能起到什么作用的了,因为对象已经生成了,原型已经确定了。
inherit(Son,Father);
但是这种方法不足之处,若是son想给自己增加一个属性,以便后续的使用,如下:
var father = new Father();
Son.prototype.sex = "male"; //若是这么改的话,那么Father.prototype 也会改变,即father.sex返回结果也为male,因为Son.prototype与Father.prototype指向的是一个空间
所以利用这种方法,Son想实现自己的个性化的属性根本不可以,因为自己一改把人家的东西也改了,Son现在想实现的就是Son用的是Father的原型,但是Son往自己身上加东西根本不影响你Father的东西,也就是我既有自定义的原型,又拥有的你原型。
所以在此之上又生成了第四种方式,思想还是共享原型,但是有点小区别。
4.圣杯模式
例1:利用中间F函数如下,用这条语句Son.prototype.sex = 'male';向son的原型中添加属性,然而father不会变,即son.sex返回结果male,而father.sex返回结果为undefined
Father.prototype.lastname = "Liu";
function Father (){
}
function Son (){
}
function inherit(Target,Origin){ //重点部分
function F(){}
F.prototype = Origin.prototype;
Target.prototype = new F();
}
inherit(Son,Father);
var son = new Son();
var father = new Father();
例2:圣杯模式(最完美的一个方法)
Father.prototype.lastname = "Liu";
function Father (){
}
function Son (){
}
function inherit(Target,Origin){
function F(){}
F.prototype = Origin.prototype; //这条语句和下面那条语句顺序一定不能颠倒,颠倒过来就不好使了。因为涉及到原型指向的问题,new用的是原来的原型,后来再给人改了,可是人家已经用完了,晚了,所以一定在new之前进行更改。
Target.prototype = new F(); //首先这三条语句利用中间F函数,避免了Son.prototype改,Father.prototype也改
Target.prototype.constructor = Target; //让Son.prototype.constructor(原型的构造函数指向自己的构造函数)Son(),因为如果不写这句的话,Son.prototype.constructor返回结果为Father
Target.prototype.uber = Origin.prototype; //把Target到底继承自谁记下来,如果有一天想要知道Target真正继承自谁,可以通过这个方法把它调用出来,super与uber一样也可以实现,但是super是保留字不允许瞎用。
}
inherit(Son,Father);
var son = new Son();
var father = new Father();