深入理解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中集合类型(set)学习小结
Jan 28 Python
用Python的Tornado框架结合memcached页面改善博客性能
Apr 24 Python
为Python的web框架编写前端模版的教程
Apr 30 Python
Python的Django框架下管理站点的基本方法
Jul 17 Python
使用Python发送各种形式的邮件的方法汇总
Nov 09 Python
浅谈Python实现2种文件复制的方法
Jan 19 Python
基于Django用户认证系统详解
Feb 21 Python
Python3基本输入与输出操作实例分析
Feb 14 Python
浅谈django 重载str 方法
May 19 Python
Python 字符串池化的前提
Jul 03 Python
分享PyCharm最新激活码(真永久激活方法)不用每月找安装参数或最新激活码了
Dec 27 Python
Appium中scroll和drag_and_drop根据元素位置滑动
Feb 15 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
wordpress之wp-settings.php
2007/08/17 PHP
工厂模式在Zend Framework中应用介绍
2012/07/10 PHP
微博短链接算法php版本实现代码
2012/09/15 PHP
PHP读取数据库并按照中文名称进行排序实现代码
2013/01/29 PHP
PHP迭代器实现斐波纳契数列的函数
2013/11/12 PHP
在win系统安装配置 Memcached for PHP 5.3 图文教程
2015/03/03 PHP
php编写的抽奖程序中奖概率算法
2015/05/14 PHP
老司机传授Ubuntu下Apache+PHP+MySQL环境搭建攻略
2016/03/20 PHP
PHP DB 数据库连接类定义与用法示例
2019/03/11 PHP
jQuery 插件仿百度搜索框智能提示(带Value值)
2013/01/22 Javascript
更快的异步执行(setTimeout多浏览器)
2014/08/12 Javascript
node.js中的fs.chmod方法使用说明
2014/12/18 Javascript
jQuery中nextAll()方法用法实例
2015/01/07 Javascript
js控制文本框输入的字符类型方法汇总
2015/06/19 Javascript
手机端图片缩放旋转全屏查看PhotoSwipe.js插件实现
2016/08/25 Javascript
VUE JS 使用组件实现双向绑定的示例代码
2017/01/10 Javascript
浅谈webpack devtool里的7种SourceMap模式
2019/01/14 Javascript
el-table表头根据内容自适应完美解决表头错位和固定列错位
2021/01/07 Javascript
[06:45]DOTA2卡尔工作室 英雄介绍幻影长矛手篇
2013/07/12 DOTA
C#返回当前系统所有可用驱动器符号的方法
2015/04/18 Python
Python Web框架Tornado运行和部署
2020/10/19 Python
python使用str & repr转换字符串
2016/10/13 Python
Python2.7下安装Scrapy框架步骤教程
2017/12/22 Python
Python语法分析之字符串格式化
2019/06/13 Python
解决启动django,浏览器显示“服务器拒绝访问”的问题
2020/05/13 Python
python3+opencv 使用灰度直方图来判断图片的亮暗操作
2020/06/02 Python
Python虚拟环境的创建和包下载过程分析
2020/06/19 Python
马来西亚银饰品牌:JEOEL
2017/12/15 全球购物
什么情况下你必须要把一个类定义为abstract的
2013/01/06 面试题
建筑设计师岗位职责
2013/11/18 职场文书
简历中个人自我评价分享
2014/03/15 职场文书
我爱祖国演讲稿
2014/09/02 职场文书
四风问题对照检查材料思想汇报
2014/10/07 职场文书
和谐拯救危机观后感
2015/06/15 职场文书
堂吉诃德读书笔记
2015/06/30 职场文书
SQL Server数据库基本概念、组成、常用对象与约束
2022/03/20 SQL Server