第九课:js的类与继承

有关js的构造函数,继承的方法大家可以去看js的高级程序设计

function A(){}

A.prototype = {  aa:1 }

var a = new A();

A.prototype = {  aa:2  }

console.log(  a.aa  )

大家会认为,会打印出2.因为构造函数A的原型改变了,当访问实例对象时,如果实例对象没有的属性,就去访问它的原型属性,所以应该是2.

但是结果却是1.为什么会这样呢?

大家要看下在改变A.prototype时,a实例已经new出来了。所以就不能按正常的方式来理解了(如果new出来的实例是在改变A原型之后,那么肯定就是2了。)

其实每当我们new出一个对象的时候,js都会默认设置这个对象一个内部属性[[Prototype]](现在的浏览器可以通过实例对象的proto属性访问),它指向的是new时的原型对象。

因此,a.proto指向的是{  aa:1 } ,当你在new它后面改变A.prototype = {  aa:2  },不会对a的proto属性有任何影响,因此打印出来的是1.之后,如果你再new A方法,那么,打印出来的aa就是2了。

还有一个比较重要的问题:

大家可以去打印一下a.constructor,打印出来的是Object,为什么不是A呢?

问题就出在这里:A.prototype = {  aa:1 }。当你新建一个A构造方法的时候,js会默认生成A.prototype对象(对象有一个constructor属性指向A)。但是你在它下面马上改变了它的原型:A.prototype = {  aa:1 }。这时,A.prototype对象的constructor会默认为Object。所以,你必须A.prototype = {  aa:1, constructor:A },把constructor的指向恢复为A。 (大家要区分下这两种方式:A.prototype = {  aa:1 },A.prototype.aa =1.第一种方式,是重新定义A.prototype对象,会覆盖之前对A.prototype对象的赋值。第二种方式,是添加属性,不会覆盖之前的定义,因此也不会改变constructor的指向)

面试官经常会问的问题:new操作发生了什么事?

(1)创建一个空对象instance。(2)instance.proto = instanceClass.prototype。(3)将构造函数里面的this=instance。(4)执行构造函数里面的代码。(5)判定有没有返回值,没有返回值默认为undefined。最后判断返回值的类型,如果为复合数据类型(数组,函数,对象,正则对象,日期对象),则直接返回,如果不是就返回this(instance)。

一些继承库里面的不常见方法和技巧介绍:

/xyz/.test(function(){  xyz;  }) ? /\b_super\b/ : /.*/;

“.”   ->   匹配除“\n”之外的任何单个字符。若要匹配包括“\n”在内的任意字符,请使用诸如“[\s\S]”之类的模式。

“\b”  ->  匹配一个字的边界,即字与空格间的位置。例如,“er\b”匹配“never”中的“er”,但不匹配“verb”中的“er”。

因此上面的/\b_super\b/正则,只匹配_super,而._super.,都不会匹配。

/.*/匹配除了“\n”之外的任何字符。

一般情况下,Function.prototype.toString 会显示函数里面的字符串,比如:function(){  xyz;  },会显示成”function(){  xyz;  }”,这时通过/xyz/.test会返回真。但是safari,mobile opera等浏览器无法显示。

所以上面的代码的意思:当函数里面的内容可以显示时,test就会返回真,然后就返回可以判断函数里面是否有_super属性的正则表达式,否则就返回一个不管判断什么字符都返回true的正则表达式.

这个方法一般在继承中使用,比如,子类继承父类,子类在添加方法时,会先检查之前是否已经有了此方法名,如果有,会先判断此方法是否是父类的,这时就可以通过判断函数里面是否存在_super的字样,如果有,就证明是父类的,就需要重写。没有的话,就说明是子类之前已经添加的,就不需要添加了。

“<”,”>”操作

var a = {

  valueOf:function(){return 1}

};

var b = {

  valueOf:function(){return 2}

};

a < b;  //true

“<”,”>”操作,强制计算前后对象的值,然后比较大小,对象会先调用自身的valueOf方法,也就是调用a,b对象的valueOf方法。

callee,caller的区别

callee是arguments对象的一个属性,它指向的是当前函数。比如:function a(){  arguments.callee ->a  }。

caller是调用函数的函数,比如:function a (){}  function b(){  a();  },b()。当调用b时,b里面会调用a.这时a.caller指的就是b。如果函数是由顶层调用的,那么 caller 包含的就是 null。不过这个属性已经在es5中被废弃的。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值