欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

JavaScript之深入对象(二)

程序员文章站 2022-05-23 12:14:05
上一篇随笔讲解了构造函数、原型及原型链相关的知识,今天让我们一起来探讨另一个问题:this。 一 this 的指向 1, 函数预编译过程中,this指向window 我们在讲解函数预编译过程的时候提到,函数在将要被执行时,会在[[scope]]属性中插入一个AO对象,AO对象包含了函数的形参、函数内 ......

上一篇随笔讲解了构造函数、原型及原型链相关的知识,今天让我们一起来探讨另一个问题:this。

 

一     this 的指向

1,  函数预编译过程中,this指向window

  我们在讲解函数预编译过程的时候提到,函数在将要被执行时,会在[[scope]]属性中插入一个ao对象,ao对象包含了函数的形参、函数内声明的变量及子函数。实际上ao对象还有两个属性:this和arguments

  arguments用来存储接下来函数执行过程中接受到的实参列表。this用来接受函数中没有被声明就被赋值的变量(未声明访问将报错)。可以简单的理解为javascript的一种容错机制。这里的this就指向window,所以我们才说未声明的变量将被升级成window的属性。

1 function test(a,b){
2     c = 10;
3     console.log(arguments);
4     console.log(c === window.c);
5 }
6 test(1,2);
7 //arguments{0:1,1:2;length:2,...}  类数组
8 //true

2,  全局作用域里this指向window。

  javascript的执行环境就是window,所以在全局作用域里window === this。

1 console.log(this === window);//true

3,  obj.method() 方法中的this指向obj

  如果有对象调用方法,那么方法内的this将指向调用对象。

  如果没有对象调用方法,即函数(方法)空执行,这里面的this还是将指向window。

 1 var name =  'ru';
 2 var obj = {
 3     name:'ren',
 4     method:function(){
 5         console.log(this.name);
 6     }
 7 };
 8 obj.method();//'ren'
 9 var test = obj.method;
10 test();//'ru'

 

二   call/apply/bind

  可以改变函数内部this的指向。

1,  call(mythisarg,agr1,arg2,...)

  call()方法使用一个指定的对象替代函数内原本的this。函数原有的参数依次添加在其后。如果第一个参数是null或者undefined,那么函数内部的this将不被改变。

 1 function person(name,age,sex){
 2     this.name = name;
 3     this.age  = age;
 4     this.sex = sex;
 5 }
 6 /*
 7 function student(name,age,sex,classes,num){
 8     this.name = name;
 9     this.age  = age;
10     this.sex = sex;
11     this.classes = classes;
12     this.num = num;
13 }
14 这种写法当然能够实现我们的功能,但student构造函数的功能完美涵盖了person,我们是否可以在创建student实例时调用person以简化代码呢?当然
15 */
16 function student(name,age,sex,classes,num){
17     person.call(this,name,age,sex);
18     this.classes = classes;
19     this.num =  num;
20 }
21 var student = new student(1,2,3,4,5);
22 console.log(student);//{name:1,age:2,sex:3,classes:4,num:5}
 1 var person = {
 2     name : 'ren',
 3     say : function(){
 4         console.log(this.name);
 5     }
 6 };
 7 var animal = {
 8     name : 'dog'
 9 };
10 person.say();//'ren'
11 animal.say();//typerror:animal.say is not a function
12 //我们怎么才能让dog也能学ren一样说话呢?
13 person.say.call(animal);//'dog'

2,  apply()

  apply()方法的功能和call()完全一样。只是apply以数组形式接受原函数的参数。

1 var arr = [50,-1,-20,2,99,38];
2 //我们怎么拿到arr数组中最大或最小的那个数呢?你可能第一反应当然是数组的sort方法。但今天我们有一个使用更简单的方法!
3 math.max.apply(null,arr);//99
4 math.min.apply(null,arr);//-20 
5 //因为这里不涉及操作this的问题,所以第一个参数为null

3,  bind()

  bind()方法使用方式和call()完全一样,但功能上有所差别。bind执行会返回一个函数,这个函数内部的this已被改变,等待在合适的时候被调用。

call和apply是在函数执行时改变其this的指向,而bind是先改变函数内的this指向,然后返回一个新的函数。

 1 var person = {
 2     name : 'ren',
 3     say : function (){
 4         console.log(this.name);
 5     }
 6 };
 7 var animal = {
 8     name : 'dog'
 9 };
10 person.say.call(animal);//'dog' 立即返回执行结果
11 var test = person.say.bind(animal); //返回一个函数
12 console.log(test);//fn 
13 test();//'dog'

 

三     callee、caller

1,callee

         arguments的一个属性,指向函数本身。

         一般用在立即执行函数的递归调用。因为立即执行函数会忽略函数名,所以在递归调用时可以用callee来解决。

1 var factorial = (function(n){
2     if(n == 1){
3         return 1;
4     }else{
5         return n * arguments.callee(n - 1);
6     }
7 }(50));

2,caller

         函数的一个属性,指向执行时的父函数。全局执行时,fn.caller == null。好像并没有什么卵用?

  另外,这两个属性在严格模式下还不能使用。

 

四   es5严格模式

  关于es5的严格模式这里就不详细讲解了,有兴趣的同学可以去这里: