Javascript中关键参数this浅析

简介:

自从接触javascript以来,对this参数的理解一直是模棱两可。虽有过深入去理解,但却也总感觉是那种浮于表面,没有完全理清头绪。

但对于this参数,确实会让人产生很多误解。那么this参数到底是何方神圣?

 

   理解this  

this是一个与执行上下文(execution context,也就是作用域)相关的特殊对象。因此,它可以叫作上下文对象(也就是用来指明执行上下文是在哪个上下 文中被触发的对象)。 

任何对象都可以做为上下文中的this的值

在一些对ECMAScript执行上下文和部分this的描述中,this经常被错误的描述成是变量对象的一个属性。 再重复一次:

this是执行上下文的一个属性,而不是变量对象的一个属性。 这个特性非常重要,因为与变量相反,this从不会参与到标识符解析过程。换句话说,在代码中当访问this的时候,它的值是直接从执行上下文中获取的,并不需要任何作用域链查找。this的值只在进入上下文的时候进行一次确定。 

废话不多,先看一个板栗: 

复制代码
 1 var test = function(){};
 2 
 3 test.prototype = {
 4     foo:"apple",
 5     fun:function(){
 6         this.foo="banana";
 7     }
 8 };
 9 
10 var myTest = new test();
11 myTest.fun();
12 
13 console.log(myTest.hasOwnProperty("foo"));  //输出什么    
14 console.log(myTest.hasOwnProperty("fun"));  //输出什么
复制代码
hasOwnProperty:是用来判断一个对象是否有你给出名称的属性或对象。不过需要注意的是,此方法无法检查该对象的原型链中是否具有该属性,该属性必须是对象本身的一个成员。

不知道看官们心里的答案是什么,正确的答案是true,false。

1 console.log(myTest.hasOwnProperty("foo"));
2 console.log(myTest.hasOwnProperty("fun"));
3 
4 true 
5 false 

要弄明白为什么是这样,就必须要理解上面this所扮演的角色,所指代的对象。在《javascript语言精粹》一书中,指出了在javascript中一共有四种调用模式:

  1. 方法调用模式
  2. 函数调用模式
  3. 构造器调用模式
  4. apply调用模式

而在这些模式当中,对于如何初始化关键参数this上是存在不同差异的。

 

   方法调用模式

当一个函数被保存为对象的一个属性时,我们称它为一个方法。当一个方法被调用时,this被绑定到该对象。注意加粗的这句是重点:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// 创建myObject。它有一个value属性和一个increment方法
 
var  myObject = {
     value: 0;
     increment:  function (inc) {
         this .value +=  typeof  inc === 'number' ?inc:1;  // 接受一个可选参数,如果不是数字,则默认为数字1
     }
};
 
myObject.increment();
console.log(myObject.value);     // 1
 
myObject.increment(2);           //传入数字2
console.log(myObject.value);     // 3

这里,方法increment可以使用this去访问myObject对象,所以可以改变value的值。而且,this到对象的绑定发生在调用的时候

  

   函数调用模式

如果一个函数并非一个对象的属性时,那么它被当作一个函数来调用,此时,this被绑定到全局对象,书上说这是js语言设计的一个缺陷。倘若设计正确,当内部函数被调用的时,this应该仍然绑定到外部函数的this变量。抛开对语言设计的正确与否讨论,要当函数调用模式时this变量依旧绑定到该对象,看例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
var  myObject = {
     value: 1,
     getValue:  function () {
         return  this .value;
     },
     double:  function () {
             return  function  (){
                     this .value =  this .value * 2;
             }
     }
};
 
myObject.double()();   // 希望将 value 乘以 2
myObject.getValue();  // 返回 1

因为 ,我们希望调用 myObject.double()() 时,value 乘以 2,但是由于 myObject.double() 返回的是一个函数,而 myObject.double()() 执行了返回的这个函数,此时,this被绑定到了全局 window 而不是 myObject。

有如下经典解决方案:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
var  myObject = {
     value: 1,
     getValue:  function () {
         return  this .value;
     },
     double:  function () {
             var  that =  this ;
             return  function  (){
                     that.value = that.value * 2;
             }
     }
};
 
myObject.double()();
myObject.getValue();  //2

即是给该方法定义一个变量并且把它赋值为this,那么内部函数就可以通过那个变量访问到this,按照约定,给那个变量命名为that。

 

   构造器调用模式

构造器调用模式即是我一开头给出的例子所提到的。如果在一个函数前面带上new来调用,那么将创建一个连接到该函数的prototype成员新对象,同时this将会被绑定到那个新对象上。听上去十分拗口且难以理解,先再看个demo:

1
2
3
4
5
6
7
8
9
10
11
12
13
//构造一个名为Quo的构造器函数,带有一个status属性的对象
 
var  Quo =  function (string){
     this .status =string;
};
 
Quo.prototype.get_status =  function (){
     return  this .status;
}
 
var  myQuo = new  Quo( "confuse" );   //构造一个Quo实例
 
console.log(myQuo.get_status());   //confuse

简单来说,Quo对象下的this在被用为构造一个新实例即new时,this指代的是新生成的myQuo对象而不是Quo对象本身。

一句话,重点就是:原型中的this不是指的原型对象,而是调用对象。

再回过头看一开始的demo,就很好理解了,在执行myTest.fun()时,this指代了myTest对象,所以生成了一个foo属性值为“banana”,所以myTest.hasOwnProperty("foo")返回值为true。

  

   Apply调用模式

因为javascript是一门函数式面向对象编程语言,所以函数可以拥有方法。apply方法让我们构建一个参数数组并用其去调用其他函数,apply方法接收两个参数,第一个是将被绑定的this的值,第二个是参数数组。说简单直接一点就是apply方法能劫持另外一个对象的方法,继承另外一个对象的属性. 推荐可以看js中apply方法的使用详细解析 ,就不摆demo了。

 

学识尚浅,若文中有不正确,请务必指出,误人子弟实乃大过。

转载注明出处:http://www.cnblogs.com/coco1s/p/3948151.html


本文转自ChokCoco博客园博客,原文链接:http://www.cnblogs.com/coco1s/p/3948151.html

目录
相关文章
|
12天前
|
前端开发
用html+javascript打造公文一键排版系统3:获取参数设置、公文标题排版
用html+javascript打造公文一键排版系统3:获取参数设置、公文标题排版
|
1月前
|
JavaScript 前端开发
JavaScript基础知识-函数的参数
关于JavaScript函数参数基础知识的介绍。
18 4
JavaScript基础知识-函数的参数
|
17天前
|
JavaScript 前端开发
JavaScript 函数参数
JavaScript 函数参数
24 3
|
15天前
|
前端开发 JavaScript
前端JS截取url上的参数
文章介绍了两种前端JS获取URL参数的方法:手动截取封装和使用URLSearchParams。
28 0
|
3月前
|
JavaScript 前端开发 网络架构
JavaScript编码之路【对象的增强、ES6新特性之函数的默认值设置 、rest参数 (剩余参数)、拓展运算符、对象与数组的解构赋值】
JavaScript编码之路【对象的增强、ES6新特性之函数的默认值设置 、rest参数 (剩余参数)、拓展运算符、对象与数组的解构赋值】
51 1
|
3月前
|
存储 资源调度 前端开发
JavaScript 使用axios库发送 post请求给后端, 给定base64格式的字符串数据和一些其他参数, 使用表单方式提交, 并使用onUploadProgress显示进度
使用 Axios 发送包含 Base64 数据和其他参数的 POST 请求时,可以通过 `onUploadProgress` 监听上传进度。由于整个请求体被视为一个单元,所以进度可能不够精确,但可以模拟进度反馈。前端示例代码展示如何创建一个包含 Base64 图片数据和额外参数的 `FormData` 对象,并在上传时更新进度条。后端使用如 Express 和 Multer 可处理 Base64 数据。注意,实际进度可能不如文件上传精确,显示简单加载状态可能更合适。
|
3月前
|
JavaScript
js 【详解】函数中的 this 指向
js 【详解】函数中的 this 指向
33 0
|
3月前
|
JavaScript 前端开发
|
3月前
|
JavaScript 前端开发 数据格式
URL编码【详解】——Javascript对URL进行编码解码的三种方式的区别和使用场景,axios请求拦截器中对get请求的参数全部进行URL编码
URL编码【详解】——Javascript对URL进行编码解码的三种方式的区别和使用场景,axios请求拦截器中对get请求的参数全部进行URL编码
125 0
|
3月前
|
JavaScript
js 获取并解析 url 中参数的三种方法
js 获取并解析 url 中参数的三种方法
109 0