深入理解Javascript中的this关键字


Posted in Python onMarch 27, 2015

自从接触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中一共有四种调用模式:

1.方法调用模式
2.函数调用模式
3.构造器调用模式
4.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变量依旧绑定到该对象,有如下经典解决方案:

// 给myObject增加一个double方法
var myObject = {

    value: 0;

    increment: function(inc) {

        this.value += typeof inc ==='number'?inc:1; // 接受一个可选参数,如果不是数字,则默认为数字1

    }

};
myObject.increment(2);
myObject.double = function () {

    var that=this;  //解决方法

    

    var helper= function () {

        that.value=add(that.value,that.value);

    };

    helper();

};

myObject.double();  //以方法的形式调用double

console.log(myObject.getValue());   //6

即是给该方法定义一个变量并且把它赋值为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了。

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

Python 相关文章推荐
Python操作串口的方法
Jun 17 Python
Python常用知识点汇总
May 08 Python
python获取酷狗音乐top500的下载地址 MP3格式
Apr 17 Python
pandas.DataFrame删除/选取含有特定数值的行或列实例
Nov 07 Python
Python使用pandas对数据进行差分运算的方法
Dec 22 Python
将string类型的数据类型转换为spark rdd时报错的解决方法
Feb 18 Python
浅谈Pandas Series 和 Numpy array中的相同点
Jun 28 Python
Python3 chardet模块查看编码格式的例子
Aug 14 Python
使用Python实现分别输出每个数组
Dec 06 Python
python应用Axes3D绘图(批量梯度下降算法)
Mar 25 Python
使用Python获取爱奇艺电视剧弹幕数据的示例代码
Jan 12 Python
详解使用scrapy进行模拟登陆三种方式
Feb 21 Python
Python运用于数据分析的简单教程
Mar 27 #Python
Python中下划线的使用方法
Mar 27 #Python
利用Python和OpenCV库将URL转换为OpenCV格式的方法
Mar 27 #Python
python根据出生年份简单计算生肖的方法
Mar 27 #Python
python实现根据月份和日期得到星座的方法
Mar 27 #Python
python根据给定文件返回文件名和扩展名的方法
Mar 27 #Python
python中使用mysql数据库详细介绍
Mar 27 #Python
You might like
浅析PHP中Session可能会引起并发问题
2015/07/23 PHP
PHP购物车类Cart.class.php定义与用法示例
2016/07/20 PHP
php实现文件管理与基础功能操作
2017/03/21 PHP
Laravel中七个非常有用但很少人知道的Carbon方法
2017/09/21 PHP
javascript 原型模式实现OOP的再研究
2009/04/09 Javascript
jquery调用asp.net 页面后台的实现代码
2011/04/27 Javascript
JQUERY1.6 使用方法四 检测浏览器
2011/11/23 Javascript
Javascript 中的 call 和 apply使用介绍
2012/02/22 Javascript
解析瀑布流布局:JS+绝对定位的实现
2013/05/08 Javascript
javascript之typeof、instanceof操作符使用探讨
2013/05/19 Javascript
JavaScript遍历table表格中的某行某列并打印其值
2014/07/08 Javascript
JavaScript中的函数声明和函数表达式区别浅析
2015/03/27 Javascript
jQuery实现按钮的点击 全选/反选 单选框/复选框 文本框 表单验证
2015/06/25 Javascript
JS组件Bootstrap Table使用方法详解
2016/02/02 Javascript
JavaScript获取服务器端时间的方法
2016/11/29 Javascript
详解JS中定时器setInterval和setTImeout的this指向问题
2017/01/06 Javascript
VUE2实现事件驱动弹窗示例
2017/10/21 Javascript
微信小程序实现授权登录
2019/05/15 Javascript
Jquery属性的获取/设置及样式添加/删除操作技巧分析
2019/12/23 jQuery
JavaScript 实现自己的安卓手机自动化工具脚本(推荐)
2020/05/13 Javascript
javascript开发实现贪吃蛇游戏
2020/07/31 Javascript
详解Python中的正则表达式的用法
2015/04/09 Python
使用Python的判断语句模拟三目运算
2015/04/24 Python
python中函数总结之装饰器闭包详解
2016/06/12 Python
Django admin实现图书管理系统菜鸟级教程完整实例
2017/12/12 Python
python得到qq句柄,并显示在前台的方法
2018/10/14 Python
使用WingPro 7 设置Python路径的方法
2019/07/24 Python
aws 通过boto3 python脚本打pach的实现方法
2020/05/10 Python
利用Python实现某OA系统的自动定位功能
2020/05/27 Python
CSS3 实现雷达扫描图的示例代码
2020/09/21 HTML / CSS
90后毕业生的求职信范文
2013/09/21 职场文书
大学毕业生自我鉴定
2013/11/05 职场文书
教师个人自我鉴定
2014/02/08 职场文书
2014年学校工会工作总结
2014/12/06 职场文书
2015应届毕业生求职信范文
2015/03/20 职场文书
人生哲理妙语30条:淡写流年,笑过人生
2019/09/04 职场文书