(转)javascript中的对象查找
本文转自:http://otakustay.com/object-lookup-in-javascript/
---很棒的一篇文章,作者的其他文章还暂时没读,但相信作者是一个谦虚 谨慎的好工程师
近期群里常有人提一些简单的问题,比如发一段代码乱七八糟的代码,然后说里面某个变量是什么,比如这里就有个很好的例子:

function fn(arg) {
console.log(this.arg);
console.log(this);
}
fn(123);
var o = { fn: fn };
o.fn(123);

然后就可能有这样的问题:
为什么
this.arg是undefined?为什么2次调用fn的this是不一样的?
为此,我觉得自己作为一个虽然不成熟的前端,对于一些自己力所能及的事情,还是应该传道授业解惑的。所以,这篇文章,计划从非常肤浅的层面上,来解释一下JavaScript中的对象查找是如何进行的。
注意,本篇文章只是从表象上来介绍对象查找这一行为的过程,文章中的观点并不全正确,甚至存在着一些谬误,但是这也是为了让初学者更好地理解对象查找这一过程。相信如果说得太过抽象、深入,反而会引起一些负面效果。如果有一天,你再回过来,发现这个文章说得并不那么正确,那么恭喜你,那个时候的你已经可以找到正确前进的道路,这篇中的错误也不会再对你有任何影响。
对象的分类
所谓对象查找,即在一段可执行代码的作用域内,找到一个当前需要的对象。在javascript中,需要进行查找的对象大致可以分为3种类型:
- 变量查找,如
foo++;,这里就会去查找一个叫作foo的变量。 - 属性查找,如
foo.bar++;,这里会去查找foo这个变量下的一个叫作bar的属性。 - this查找,即针对
this关键字的处理。
区分这3种类型的对象查找是首先要完成的任务,你可以基于以下原则进行判断:
- 变量仅由变量名组成,即单独的
foo、bar等。 - 属性永远由2种形式去访问,即
foo.bar和foo['bar'],因此看到有.或[]即可当成是属性查找。 this就不用说了,好好的关键字。
看一下这段代码:
var foo = this;
foo.bar();
这2行的代码就体现了3种对象查找,分别为:
- 查找
this对象,并赋值给foo变量。 - 查看
foo变量。 - 查找
foo变量下的bar属性,并将之作为一个函数进行调用。
变量的查找
当确定一个对象的查找为变量查找后,可以按照变量查找的规则来查看。
变量查找,即在作用域链上进行查找,作用域链是javascript非常著名的2条链之一,以下代码体现一个标准的作用域链:

var foo = 1;
function a() {
var bar = 2;
function b() {
foo = 3;
function c() {
console.log(foo + ',' + bar); // 注意这一行
}
c();
}
b();
}
a();

在c函数中,一共进行了2个变量的查找,分别为foo和bar。
变量的查找可以简单地遵守从下向上的原则,即:
- 在函数
c的范围内查找foo和bar,显然在c里面并没有foo和bar的声明,查找失败。 - 在包含
c的函数,即函数b的范围内查找foo和bar,可以看到b里面只有对foo的赋值,并没有声明,查找失败。 - 在包括
b的函数,即函数a的范围内查找foo和bar,可以找到bar的声明,因此确定bar为2。 - 由于
a不被任何函数包含,那么就在全局作用域内查找foo,发现有foo的声明,因此确定foo的值为1。但是由于在函数b中,对这个foo有赋值,所以foo的值被修改为3。 - 完确定
foo的值为3,bar的值为2,因此输出3,2。
总结一下,变量的查找是延着作用域链进行的,作用域链可以简单地看成函数间的包含关系,被包含的函数中不存在某个变量时,在包含他的函数中查找,直到全局作用域。
属性的查找
当确定一个对象的查找为属性查找后,可以按照属性查找的规则来查看。
属性查找,即在原型链上进行查找,原型链是javascript双链的另一条,以下可以表示出一个原型链:

var a = function() {};
var b = function() {};
var c = function() {};
b.prototype = new a();
c.prototype = new b();
a.prototype.foo = 1;
b.prototype.bar = 2;
c.prototype.foo = 3;
var o = new c();
console.log(o.foo + ',' + o.bar); // 这一行进行查找

属性查找是一个不断寻找prototype的过程,即:
- 查找
c.prototype中,有没有显示定义foo和bar,发现定义了foo,其值为3。 - 发现
c.prototype就是new b()得到的对象,那么查找b.prototype中,有没有显示定义bar,发现定义了,其值为2。 - 因此确定
foo的值为3,bar的值为2,输出"3,2"。
总结一下,属性查找是延着原型链进行的,原型链的具体知识这里不作详细解释,可以另找文章进行参考。所有的对象,其原型链最终会是Object.prototype,再向上就是null了。
this的查找
this的查找是很多人迷茫的一点,也似乎有很多人抱有this不稳定这样的看法,实在令人无语。this的查找可以说是3种对象查找中最为简单的,因为其实this对象的确定根本没有一个“查找”的过程。
首先,this对象只会在一个函数中需要确定,如果是在全局域下,this永远为Global对象,在浏览器中通常就是window对象。而在javascript中,函数的调用一共有4种方式:
Function Invocation Pattern
诸如
foo()的调用形式被称为Function Invocation Pattern,是函数最直接的使用形式,注意这里的foo是作为单独的变量出现,而不是属性。在这种模式下,foo函数体中的this永远为Global对象,在浏览器中就是window对象。
Method Invocation Pattern
诸如
foo.bar()的调用形式被称为Method Invocation Pattern,注意其特点是被调用的函数作为一个对象的属性出现,必然会有“.”或者“[]”这样的关键符号。在这种模式下,bar函数体中的this永远为“.”或“[”前的那个对象,如上例中就一定是foo对象。
Constructor Pattern
new foo()这种形式的调用被称为Constructor Pattern,其关键字new就很能说明问题,非常容易识别。在这种模式下,foo函数内部的this永远是new foo()返回的对象。
Apply Pattern
foo.call(thisObject)和foo.apply(thisObject)的形式被称为Apply Pattern,使用了内置的call和apply函数。在这种模式下,
call和apply的第一个参数就是foo函数体内的this,如果thisObject是null或undefined,那么会变成Global对象。
应用以上4种方式,确定一个函数是使用什么样的Pattern进行调用的,就能很容易确定this是什么。
另外,this是永远不会延作用域链或原型链出现一个“查找”的过程的,只会在函数调用时就完全确认。
总结
对于一个对象的查找:
- 确定是变量查找、属性查找还是this查找。
- 如果是变量查找,则延作用域链找,找不到就是
ReferenceError。 - 如果是属性查找,就延原型链找,找不以就是
undefined。 - 如果是
this查找,去找调用函数的代码,根据调用的形式来确定this是什么。
注意把一次查找过程拆分开来,比如this.foo.bar.yahoo(),可以拆分成这样的代码,就能更清楚了:
var o = this; // this查找
var foo = o.this; // 属性查找
var bar = foo.bar; // 属性查找
bar.yahoo(); // 属性查找,加Method Invocation Pattern
最后,如果有一天你可以了解这些东西,这篇文章对你用户也就不大了:
- 为什么延作用域查找不到会有
ReferenceError。 - 其实变量也是属性,一个特殊对象的属性。
this也许不是Global,也许会是undefined。
(转)javascript中的对象查找的更多相关文章
- javascript中的对象,原型,原型链和面向对象
一.javascript中的属性.方法 1.首先,关于javascript中的函数/“方法”,说明两点: 1)如果访问的对象属性是一个函数,有些开发者容易认为该函数属于这个对象,因此把“属性访问”叫做 ...
- Javascript中的对象和原型(3)
在Javascript中的对象和原型(二)中我们提到,用构造函数创建的对象里面,每个对象之间都是独立的,这样就会降低系统资源的利用率,解决这样问题,我们就要用到下面提到的原型对象. 一 原型对象 原型 ...
- JavaScript中String对象的match()、replace() 配合正则表达式使用
正则表达式由来已久,查找替换功能非常强大,但模板难记复杂. JavaScript中String对象的match().replace()这2个方法都要使用正则表达式的模板.当模板内容与字符串不相匹配时, ...
- Javascript中的对象和原型(三)(转载)
在Javascript中的对象和原型(二)中我们提到,用构造函数创建的对象里面,每个对象之间都是独立的,这样就会降低系统资源的利用率,解决这样问题,我们就要用到下面提到的原型对象. 一 原型对象 原型 ...
- JavaScript中的对象与原型—你不知道的JavaScript上卷读书笔记(四)
一.对象 对象可以通过两种形式定义:声明(文字)形式和构造形式.即: var myObj = { key: value // ... }; 或: var myObj = new Object(); m ...
- Javascript 中判断对象为空
发现了一个巧妙的实现: 需要检查一个对象(Object)是否为空,即不包含任何元素.Javascript 中的对象就是一个字典,其中包含了一系列的键值对(Key Value Pair).检查一个对象是 ...
- JavaScript 中的对象
JavaScript 中的对象 在 JavaScript 中,对象是数据(变量),拥有属性和方法. JavaScript 中的所有事物都是对象:字符串.数字.数组.日期,等等. 访问对象的属性 访 ...
- javascript中Date对象的应用——简易日历的实现
× 目录 [1]效果 [2]HTML [3]CSS[4]JS 前面的话 简易日历作为javascript中Date对象的常见应用,用途较广泛.本文将详细说明简易日历的实现思路 效果演示 HTML说明 ...
- JavaScript中判断对象类型方法大全1
我们知道,JavaScript中检测对象类型的运算符有:typeof.instanceof,还有对象的constructor属性: 1) typeof 运算符 typeof 是一元运算符,返回结果是一 ...
随机推荐
- Javascript 事件对象(二)event事件
Event事件: <!DOCTYPE HTML> <html> <head> <meta http-equiv="Content-Type" ...
- windows7共享硬盘 虚拟机Mac访问windows7硬盘
选择本地磁盘(G)-->右键-->共享-->高级共享点击高级共享 确定 完成共享 虚拟机Mac 访问共享磁盘 2.苹果MAC系统,点击桌面.打开顶部菜单 “前往”. 3.菜单 ...
- Node.js高级编程读书笔记 - 5 数据库 - Never
Outline 6 连接数据库 6.1 使用node-mysql连接MySQL数据库 6.2 使用Nano连接CouchDB数据库 6.3 使用Mongoose连接MongoDB数据库 6 连接数据库 ...
- [转]SQLServer2008日志文件无法收缩处理方法
问题描述 发现有的数据库日志文件太大,无论如何收缩执行几次SQL语句都不行.事务日志达30+G,而且使用常规的截断.收缩方法均无法减小日志物理文件的尺寸,经过一番寻找,终于找到了解决方法. 查 ...
- Excel中如何提取字符串中的数字
取字符串中的数字,假如数据在A列,提取公式为 =LOOKUP(9^9,--MID(A1,MIN(FIND({1,2,3,4,5,6,7,8,9,0},A1&5^19)),ROW($1:$99) ...
- eclipse 使用(一)单步调试
昨天终于将取数据的流程走通了.但是没有成功获得数据.原因是,把服务器中的数据库还原到了本地.而测试数据是写到了本地.把数据给覆盖了.早上来了之后,赶紧在服务器上把数据弄了一下. 之后开始跑代码. 项目 ...
- 二、Spring——AoP
AOP概述 AOP是OOP的有益补充,他为程序开发提供了一个崭新的思考角度,可以将重复性的横切逻辑抽取到统一的模块中,通过OOP的纵向抽象和AOP的横向抽取,程序才能真正解决复杂性代码问题. Spri ...
- PHP入门part2
PHP的数据类型 php数据类型分为三大类, 标量类型:整型.浮点型.布尔型和字符串型 复合类型:数组型和对象(object) 特殊类型:空类型和资源型 !资源型以后会讲 整形(int)就是整数的数值 ...
- Zookeeper全解析——Paxos作为灵魂(转)
原计划在介绍完ZK Client之后就着手ZK Server的介绍,但是发现ZK Server所包含的内容实在太多,并不是简简单单一篇Blog就能搞定的.于是决定从基础搞起比较好. 那么ZK Serv ...
- oracle控制文件丢失恢复
在学习群里有个同学误删除了控制文件,于是我也把自己数据库的控制文件删除了,看看能不能进行恢复,以下是整个实验的过程~~在做之前,先看看控制文件的备份方式:1.生成可以重建控制文件的脚本.2.备份二进制 ...