JavaScript this 深入理解

最近一段时间看了很多JavaScript 的库源码, 如 prototype, Ext core 等。这些库中大量应用到了这一概念。直到昨天翻了一下《JavaScript王者归来》这本书才算对this有一个深刻的理解。
大至归结一下:
1. 函数调用者与所有者
JavaScript 中函数(function) 存在调用者 与 所有者这两个概念,调用者是指调用函数的对象,通常是一个指向调用了当前函数的函数的引用,如果是顶层调用,那么caller=null, 大部分浏览器的JavaScript实现 可以用 caller 这个属性获得(这不是 ECMAScript 规范的一部分,所有还是慎用)。 从以下的代码能够很好的理解这点:


代码如下:

function a(){
alert('fun a caller=' + a.caller);
}
function b(){
a();
}
a();
b();

-----------
运行结果可以看到两个对话框:
1.
fun a caller=null;
2.
fun a caller=function b(){
a();
}
--------------------------
而对于所有者,则是指调用函数的对象(一个动态的概念), 在函数体中的this就是指向了函数的所有者。在这里的this 与 Java 以及 C++ 中的 this指针是完全不同的两个概念,很多人忽略了这一点,这也是导致 JavaScript中的this无法很好理解的原因之一。看看以下的例子:


代码如下:

var oa = {
x:1,
y:2
}
var ob = {
x:11,
y:12
}
function a(w){
alert(w + "=" + this.x + "," + this.y)
}
a("?");
oa.fun = a;
oa.fun("a");
ob.fun = a;
ob.fun("b");

---------
一开始的调用 a() 这时未指定所有者,一般这种情况 this 是指向浏览器的顶层元素 window 的, 而window中未定义x 与 y 属性。
所以结果显示为: ?=undefined,undefined
oa.fun = a; oa.fun("a"); 将函数引用赋值给对像a的属性fun, 这时再调用函数的所有者变成了a, 则结果显示为:a=1,2
同理 ob.fun("b")则显示:b=11,12。
在JavaScript中要改变一个函数的所有者(this)的方法就是将函数引用赋值给一个对象的属性。
同是在Function对象中也提供了两个原型函数可以实现这一功能: apply, call, 这两个函数的第一个参数就是要指定的所有者对象,它们间的唯一区别就是apply将其后的要传递给函数的形参封装到数组中,或者直接用 arguments对象。而call则直接将形参跟在其后。
因此上面的 oa.fun=a; oa.fun("a") 可以改写成 a.apply(oa, ["a"]) 或 a.call(oa, "a");
ob.fun=b; ob.fun("b") 可以改写成 a.apply(ob, ["b"]) 或 b.call(ob, "b");
知道了以上这此,对于 this 的作用域及其使用就很好理解了。

下面是一些参考文档
javascript this用法小结
http://www.jb51.net/article/16863.htm

JavaScript this 深入理解
http://www.jb51.net/article/19425.htm

JAVASCRIPT THIS详解 面向对象
http://www.jb51.net/article/17584.htm

Javascript this指针
http://www.jb51.net/article/19434.htm

JavaScript中this关键字使用方法详解
http://www.jb51.net/article/7954.htm

Javascript this关键字使用分析
http://www.jb51.net/article/16235.htm

(0)

相关推荐

  • JavaScript this 深入理解

    最近一段时间看了很多JavaScript 的库源码, 如 prototype, Ext core 等.这些库中大量应用到了这一概念.直到昨天翻了一下<JavaScript王者归来>这本书才算对this有一个深刻的理解. 大至归结一下: 1. 函数调用者与所有者 JavaScript 中函数(function) 存在调用者 与 所有者这两个概念,调用者是指调用函数的对象,通常是一个指向调用了当前函数的函数的引用,如果是顶层调用,那么caller=null, 大部分浏览器的JavaScript实现

  • 对javascript继承的理解

    由于javascript原生是不支持类的(ES6已经支持class与extends),更不用谈继承.多态了,为了模拟出一些其它面向对象编程语言的这些特性,有好多大牛写了给出了实现方式,看了John Resig的<Simple JavaScript Inheritance>这篇文章,深深被折服了,原来短短几十行javascript也可以这么强大.优雅,下面以我的理解方式来解读下. 主要实现了继承.访问父类的重名方法(这里的实现方式太妙了),但遗憾的是不能实现成员变量/函数的隐藏. (functi

  • javascript闭包的理解

    1.首先我们要知道变量作用域链 变量的作用域分两种:全局变量和局部变量.没有定义到任何函数中的变量为全局变量,在函数中定义的变量为局部变量,注意在函数内部定义变量时一定要使用var关键字,不带var关键字的变量为全局变量. javascript中每一段代码都有与之关联的作用域链,这个作用域链是一个对象列表或者链表,定义了这段代码"作用域"中的变量.顶层代码的作用域由全局变量组成:不包含嵌套的函数的作用域链有两个对象:一个是定义的函数参数和局部变量的对象,一个是全局变量对象:而嵌套函数的

  • JavaScript 闭包深入理解(closure)

    一.什么是闭包? "官方"的解释是:闭包是一个拥有许多变量和绑定了这些变量的环境的表达式(通常是一个函数),因而这些变量也是该表达式的一部分.相信很少有人能直接看懂这句话,因为他描述的太学术.其实这句话通俗的来说就是:JavaScript中所有的function都是一个闭包.不过一般来说,嵌套的function所产生的闭包更为强大,也是大部分时候我们所谓的"闭包".看下面这段代码: function a() { var i = 0; function b() { a

  • javascript闭包的理解和实例

    顺便提示一下: 词法作用域:变量的作用域是在定义时决定而不是执行时决定,也就是说词法作用域取决于源码,通过静态分析就能确定,因此词法作用域也叫做静态作用域. with和eval除外,所以只能说JS的作用域机制非常接近词法作用域(Lexical scope). 下面是一个简单的使用全局变量的闭包实例: 复制代码 代码如下: var sWord="Hello,Welcome to web前端开发工程师的博客,请多多指教." function disWord(){ alert(sWord);

  • javascript Function函数理解与实战

    Function函数是javascript的基础也是实现功能的一个引爆点,我们通过实例分析让你对Function函数有一个更加深刻的理解以及在实际中的用法讲解. Function 确实是一个对象.而我们定义的任何一个函数其实都是Function 对象的一个实例,也可以理解为指向 Function 对象的一个实例. 既然是对象的一个实例,那肯定指向了Function 类型的一个引用. 既然指向了一个引用类型的内存地址,那你也可以简单的把我们定义的函数理解为一个变量,这个变量指向了一个引用类型的地址

  • 解析Javascript中难以理解的11个问题

    1.原始值与引用值 原始值存放在栈里, 引用值存放在堆里. 如程序: 复制代码 代码如下: function Person(id,name,age){ this.id = id; this.name = name; this.age = age;} var num = 10;var bol = true;var str = "abc";var obj = new Object();var arr = ['a','b','c'];var person = new Person(100,&

  • 全面理解面向对象的 JavaScript(来自ibm)

    当今 JavaScript 大行其道,各种应用对其依赖日深.web 程序员已逐渐习惯使用各种优秀的 JavaScript 框架快速开发 Web 应用,从而忽略了对原生 JavaScript 的学习和深入理解.所以,经常出现的情况是,很多做了多年 JS 开发的程序员对闭包.函数式编程.原型总是说不清道不明,即使使用了框架,其代码组织也非常糟糕.这都是对原生 JavaScript 语言特性理解不够的表现.要掌握好 JavaScript,首先一点是必须摒弃一些其他高级语言如 Java.C# 等类式面向

  • 深入理解JavaScript系列(1) 编写高质量JavaScript代码的基本要点

    具体一点就是编写高质量JavaScript的一些要素,例如避免全局变量,使用单变量声明,在循环中预缓存length(长度),遵循代码阅读,以及更多. 此摘要也包括一些与代码不太相关的习惯,但对整体代码的创建息息相关,包括撰写API文档.执行同行评审以及运行JSLint.这些习惯和最佳做法可以帮助你写出更好的,更易于理解和维护的代码,这些代码在几个月或是几年之后再回过头看看也是会觉得很自豪的. 书写可维护的代码(Writing Maintainable Code ) 软件bug的修复是昂贵的,并且

  • 深入理解JavaScript系列(2) 揭秘命名函数表达式

    前言 网上还没用发现有人对命名函数表达式进去重复深入的讨论,正因为如此,网上出现了各种各样的误解,本文将从原理和实践两个方面来探讨JavaScript关于命名函数表达式的优缺点. 简单的说,命名函数表达式只有一个用户,那就是在Debug或者Profiler分析的时候来描述函数的名称,也可以使用函数名实现递归,但很快你就会发现其实是不切实际的.当然,如果你不关注调试,那就没什么可担心的了,否则,如果你想了解兼容性方面的东西的话,你还是应该继续往下看看. 我们先开始看看,什么叫函数表达式,然后再说一

随机推荐