JavaScript中几个重要的属性(this、constructor、prototype)

this 
this表示当前对象,如果在全局作用范围内使用this,则指代当前页面对象window; 如果在函数中使用this,则this指代什么是根据运行时此函数在什么对象上被调用。 我们还可以使用apply和call两个全局方法来改变函数中this的具体指向。 
先看一个在全局作用范围内使用this的例子: 
  1. <script type=>   
                 console.log( === window);    
                 console.log(window.alert === .alert);    
                 console.log(.parseInt(, 10));    
    </script>  

函数中的this是在运行时决定的,而不是函数定义时,如下:

  1.         
     foo() {   
                 console.log(.fruit);   
             }    
             fruit = ;            
             foo();             
             pack = {   
                 fruit: ,   
                 foo: foo   
             };           
             pack.foo();   

全局函数apply和call可以用来改变函数中this的指向,如下:    
  1.          
    foo() {   
                 console.log(.fruit);   
             }           
             fruit = ;           
             pack = {   
                 fruit:   
             };   
            foo.apply(window);    
            foo.apply(pack);      

注:apply和call两个函数的作用相同,唯一的区别是两个函数的参数定义不同。 
因为在JavaScript中函数也是对象,所以我们可以看到如下有趣的例子: 

  1.         
    foo() {   
                ( === window) {   
                    console.log();   
                }   
            }                  
            foo.boo = () {   
                ( === foo) {   
                    console.log();   
                } ( === window) {   
                    console.log();   
                }   
            };           
            foo();    
            foo.boo();            
            foo.boo.apply(window);  

prototype 

prototype本质上还是一个JavaScript对象。 并且每个函数都有一个默认的prototype属性。 
如果这个函数被用在创建自定义对象的场景中,我们称这个函数为构造函数。 比如下面一个简单的场景:     

  1.  Person(name) {   
              .name = name;   
           }        
           Person.prototype = {   
               getName: () {   
                   .name;   
               }   
           }   
           zhang = Person();   
           console.log(zhang.getName());   

作为类比,我们考虑下JavaScript中的数据类型 - 字符串(String)、数字(Number)、数组(Array)、对象(Object)、日期(Date)等。 我们有理由相信,在JavaScript内部这些类型都是作为构造函数来实现的,比如:

  1.   
  2.         Array() {            
  3.         }   
  4.                  
  5.         arr1 = Array(1, 56, 34, 12);         
  6.         arr2 = [1, 56, 34, 12];

同时对数组操作的很多方法(比如concat、join、push)应该也是在prototype属性中定义的。 
实际上,JavaScript所有的固有数据类型都具有只读的prototype属性(这是可以理解的:因为如果修改了这些类型的prototype属性,则哪些预定义的方法就消失了), 但是我们可以向其中添加自己的扩展方法。

  1.   
  2.          Array.prototype.min = () {   
  3.              min = [0];   
  4.              ( i = 1; i < .length; i++) {   
  5.                  ([i] < min) {   
  6.                      min = [i];   
  7.                  }   
  8.              }   
  9.              min;   
  10.          };                 
  11.          console.log([1, 56, 34, 12].min());    

注意:这里有一个陷阱,向Array的原型中添加扩展方法后,当使用for-in循环数组时,这个扩展方法也会被循环出来。 
下面的代码说明这一点(假设已经向Array的原型中扩展了min方法):


  1. arr = [1, 56, 34, 12];   
  2.          total = 0;   
  3.          ( i arr) {   
  4.              total += parseInt(arr[i], 10);   
  5.          }   
  6.          console.log(total);     

解决方法也很简单:


  1. arr = [1, 56, 34, 12];   
  2.         total = 0;   
  3.         ( i arr) {   
  4.             (arr.hasOwnProperty(i)) {   
  5.                 total += parseInt(arr[i], 10);   
  6.             }   
  7.         }   
  8.         console.log(total);     

constructor 
constructor始终指向创建当前对象的构造函数。比如下面例子:

  1.         arr = [1, 56, 34, 12];   
            console.log(arr.constructor === Array);           
            Foo = () { };   
            console.log(Foo.constructor === Function);          
            obj = Foo();   
            console.log(obj.constructor === Foo);        
            console.log(obj.constructor.constructor === Function);   

但是当constructor遇到prototype时,有趣的事情就发生了。 
我们知道每个函数都有一个默认的属性prototype,而这个prototype的constructor默认指向这个函数。如下例所示:

  1. Person(name) {   
                .name = name;   
             };   
             Person.prototype.getName = () {   
                 .name;   
             };   
             p = Person();           
             console.log(p.constructor === Person);    
             console.log(Person.prototype.constructor === Person);           
             console.log(p.constructor.prototype.constructor === Person);
    当时当我们重新定义函数的prototype时(注意:和上例的区别,这里不是修改而是覆盖), constructor的行为就有点奇怪了,如下示例:
  1. Person(name) {   
                .name = name;   
             };   
             Person.prototype = {   
                 getName: () {   
                     .name;   
                 }   
             };   
             p = Person();   
             console.log(p.constructor === Person);    
             console.log(Person.prototype.constructor === Person);   
             console.log(p.constructor.prototype.constructor === Person);  

为什么呢? 
原来是因为覆盖Person.prototype时,等价于进行如下代码操作:

  1. Person.prototype = Object({   
                getName: () {   
                    .name;   
                }   
            });  
    而constructor始终指向创建自身的构造函数,所以此时Person.prototype.constructor === Object,即是:
  1. Person(name) {   
                .name = name;   
             };   
             Person.prototype = {   
                 getName: () {   
                     .name;   
                 }   
             };   
             p = Person();   
             console.log(p.constructor === Object);    
             console.log(Person.prototype.constructor === Object);   
             console.log(p.constructor.prototype.constructor === Object);   
    怎么修正这种问题呢?方法也很简单,重新覆盖Person.prototype.constructor即可:
  1. Person(name) {   
               .name = name;   
            };   
            Person.prototype = Object({   
                getName: () {   
                    .name;   
                }   
            });   
            Person.prototype.constructor = Person;   
            p = Person();   
            console.log(p.constructor === Person);    
            console.log(Person.prototype.constructor === Person);   
            console.log(p.constructor.prototype.constructor === Person);   


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值