Javascript中关键参数this浅析
自从接触javascript以来,对this参数的理解一直是模棱两可。虽有过深入去理解,但却也总感觉是那种浮于表面,没有完全理清头绪。
但对于this参数,确实会让人产生很多误解。那么this参数到底是何方神圣?
理解this
this是一个与执行上下文(execution context,也就是作用域)相关的特殊对象。因此,它可以叫作上下文对象(也就是用来指明执行上下文是在哪个上下 文中被触发的对象)。
任何对象都可以做为上下文中的this的值
在一些对ECMAScript执行上下文和部分this的描述中,this经常被错误的描述成是变量对象的一个属性。 再重复一次:
this是执行上下文的一个属性,而不是变量对象的一个属性。 这个特性非常重要,因为与变量相反,this从不会参与到标识符解析过程。换句话说,在代码中当访问this的时候,它的值是直接从执行上下文中获取的,并不需要任何作用域链查找。this的值只在进入上下文的时候进行一次确定。
废话不多,先看一个板栗:
var test = function(){}; test.prototype = {
foo:"apple",
fun:function(){
this.foo="banana";
}
}; var myTest = new test();
myTest.fun(); console.log(myTest.hasOwnProperty("foo")); //输出什么
console.log(myTest.hasOwnProperty("fun")); //输出什么
hasOwnProperty:是用来判断一个对象是否有你给出名称的属性或对象。不过需要注意的是,此方法无法检查该对象的原型链中是否具有该属性,该属性必须是对象本身的一个成员。
不知道看官们心里的答案是什么,正确的答案是true,false。
console.log(myTest.hasOwnProperty("foo"));
console.log(myTest.hasOwnProperty("fun")); true
false
要弄明白为什么是这样,就必须要理解上面this所扮演的角色,所指代的对象。在《javascript语言精粹》一书中,指出了在javascript中一共有四种调用模式:
- 方法调用模式
- 函数调用模式
- 构造器调用模式
- apply调用模式
而在这些模式当中,对于如何初始化关键参数this上是存在不同差异的。
方法调用模式
当一个函数被保存为对象的一个属性时,我们称它为一个方法。当一个方法被调用时,this被绑定到该对象。注意加粗的这句是重点:
// 创建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变量依旧绑定到该对象,看例子:
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。
有如下经典解决方案:
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:
//构造一个名为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
Javascript中关键参数this浅析的更多相关文章
- JavaScript中函数参数的按值传递与按引用传递(即按地址传递)
首先声明一句:JavaScript中所有函数的参数都是按值传递的!不存在按引用传递! 在讲传递参数之前我们先来讲一下指针. 学过C指针的应该都知道,指针变量中保存的是一个地址,程序可以根据所保存的地址 ...
- Javascript中的Callback方法浅析
什么是callback? 回调函数就是一个通过函数指针调用的函数.如果你把函数的指针(地址)作为参数传递给另一个函数,当这个指针被用为调用它所指向的函数时,我们就说这是回调函数.回调函数不是由该函数 ...
- JavaScript中的Function类型浅析
1. Function类型是js中引用类型之一,每个函数实际上都是Function类型的实例对象,具有自己的属性和方法.正因为函数式对象,所以函数名实际上也是一个指向函数对象的指针. 2. 常用的函数 ...
- JavaScript中函数参数的值传递和引用传递
结论: 对于数字.字符串等基本类型变量,是将它们的值传递给了函数参数,函数参数的改变不会影响函数外部的变量. 对于数组和对象等是将对象(数组)的变量的值传递给了函数参数,这个变量保存的指向对象(数组) ...
- Java中带参数的方法和JavaScript中带参数的函数有什么不同?
javascript是动态语言,是弱类型语言,其参数的使用很灵活:java则是强类型语言,参数的类型必须明确的
- 理解javascript中参数的按值传递
有人认为 JS 中参数传递:基本数据类型按值传递:引用类型按引用传递.呵呵 javascript中所有参数是按值传递的 但是当传入的参数是引用类型时,便带来了疑惑 引用类型值保存在内存中,而JS是不能 ...
- 理解javascript中的回调函数(callback)【转】
在JavaScrip中,function是内置的类对象,也就是说它是一种类型的对象,可以和其它String.Array.Number.Object类的对象一样用于内置对象的管理.因为function实 ...
- javascript中遇到的字符串对象处理
在javascript中对参数处理: 1 <script> 2 function getParam() 3 { 4 urlInfo=window.location.href; //获取当前 ...
- JavaScript 神奇的参数
JS函数的参数,和其他语言区别非常大.它不在乎你传过来多少个参数,也不在乎传过来的参数是什么类型.即使你定义的函数只接受两个参数,你调用这个函数的时候可以传递一个.三个甚至不传参数.这是因为JavaS ...
随机推荐
- printf的特殊用法
printf的特殊用法:对于m.n的格式可以用如下方法表示 前边的 * 定义的是总的宽度,后边的 * 定义的是输出的个数.分别对应外面的参数m和n .这种方法的好处是可以在语句之外对参数m和n赋值 ...
- 如何对tableview进行自定义多选
前言: 很多入门不久的程序员或许都会遇到系统自带的tableview多选时cell选择时不能选择自己想要的点击时的颜色或者图片,这让初级开发者们很烦恼.今天,我试着花了几个小时的时间用了自己的想法,去 ...
- openGL实现二维图形和三维图形
openGL是一个强大的底层图形库,其命令最初的时候使用C语言实现的.openGL定义了一个图形程序接口,常用于制作处理三维图像,功能强大,调用方便,在图像处理十分受欢迎. 实现图形主要使用的是ope ...
- ARM 编译 phddns
参考博文http://bluegemyf.blog.163.com/blog/static/11816340201310472751513/ 1.安装必要的开发包 sudo apt-get inst ...
- angularjs provider 供应商服务
今天学习了angularjs的provider的供应商服务,写了个例子(自定义供应商服务,也可使用angularjs内部提供的服务) var starterApp = angular.module(' ...
- js中的变量类型
js 中输出定义变量的类型 typeof 变量名. var u: --underfined类型 var s = "你是一个好人": --string类型 var n = ...
- 动态Web API层
返回总目录 本篇目录 构建动态Web API控制器 ForAll 方法 重写ForAll 方法 Http动词 动态Javascript代理 Ajax参数 单一服务脚本 Angular支持 Durand ...
- DRY(Don't Repeat Yourself )原则
凡是写过一些代码的程序猿都能够意识到应该避免重复的代码和逻辑.我们通过提取方法,提取抽象类等等措施来达到这一目的.我们总能时不时的听到类似这样的话:”把这些公用的类放到shared项目去,别的项目还要 ...
- java中文乱码解决之道(三)-----编码详情:伟大的创想---Unicode编码
随着计算机的发展.普及,世界各国为了适应本国的语言和字符都会自己设计一套自己的编码风格,正是由于这种乱,导致存在很多种编码方式,以至于同一个二进制数字可能会被解释成不同的符号.为了解决这种不兼容的问题 ...
- Hibernate的三种状态及对象生命周期
理解Hibernate的三种状态,更利于理解Hibernate的运行机制,这些可以让你在开发中对疑点问题的定位产生关键性的帮助. 三种状态 临时状态(Transient):在通过new关键字, ...