编辑点评:本文作者为大家介绍Javascript中的对象查找一些问题,希望有所帮助。

  近期群里常有人提一些简单的问题,比如发一段代码乱七八糟的代码,然后说里面某个变量是什么,比如这里就有个很好的例子:

function fn(arg) {
alert(this.arg);
alert(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.barfoo['bar'],因此看到有“.”或“[]”即可当成是属性查找。
  • this就不用说了,好好的关键字。

  看一下这段代码:

var foo = this;
foo.bar();

  这2行的代码就体现了3种对象查找,分别为:

  1. 查找this对象,并赋值给foo变量。
  2. 查看foo变量。
  3. 查找foo变量下的bar属性,并将之作为一个函数进行调用。

  变量的查找

  当确定一个对象的查找为变量查找后,可以按照变量查找的规则来查看。

  变量查找,即在作用域链上进行查找,作用域链是javascript非常著名的2条链之一,以下代码体现一个标准的作用域链:

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

  在c函数中,一共进行了2个变量的查找,分别为foo和bar。

  变量的查找可以简单地遵守“从下向上”的原则,即:

  1. 在函数c的范围内查找foo和bar,显然在c里面并没有foo和bar的声明,查找失败。
  2. 在包含c的函数,即函数b的范围内查找foo和bar,可以看到b里面只有对foo的赋值,并没有声明,查找失败。
  3. 在包括b的函数,即函数a的范围内查找foo和bar,可以找到bar的声明,因此确定bar为2。
  4. 由于a不被任何函数包含,那么就在全局作用域内查找foo,发现有foo的声明,因此确定foo的值为1。但是由于在函数b中,对这个foo有赋值,所以foo的值被修改为3。
  5. 完确定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();
alert(o.foo + ',' + o.bar); // 这一行进行查找

  属性查找是一个不断寻找prototype的过程,即:

  1. 查找c.prototype中,有没有显示定义foo和和bar,发现定义了foo,其值为3。
  2. 发现c.prototype就是new b()得到的对象,那么查找b.prototype中,有没有显示定义bar,发现定义了,其值为2。
  3. 因此确定foo的值为3,bar的值为2,输出"3,2"

  总结一下,属性查找是延着原型链进行的,原型链的具体知识这里不作详细解释,可以另找文章进行参考。所有的对象,其原型链最终会是Object.prototype

  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是永远不会延作用域链或原型链出现一个“查找”的过程的,只会在函数调用时就完全确认。

  总结

  对于一个对象的查找:

  1. 确定是变量查找、属性查找还是this查找。
  2. 如果是变量查找,则延作用域链找,找不到就是ReferenceError。
  3. 如果是属性查找,就延原型链找,找歪以就是undefined。
  4. 如果是this查找,去找调用函数的代码,根据调用的形式来确定this是什么。
  5. 注意把一次查找过程拆分开来,比如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。

转载于:https://www.cnblogs.com/tangge/archive/2011/04/26/2029295.html

Javascript中的对象查找【转】相关推荐

  1. JavaScript 中遍历对象的属性

    原文链接 JavaScript 中遍历对象的属性 参考 JavaScript中的属性:如何遍历属性 <JavaScript 高级程序设计> 概述 遍历 JavaScript 对象中的属性没 ...

  2. JavaScript 中遍历对象的属性 1

    JavaScript 中遍历对象的属性 原文链接 JavaScript 中遍历对象的属性 参考 JavaScript中的属性:如何遍历属性 <JavaScript 高级程序设计> 概述 遍 ...

  3. JavaScript中Object对象方法超详细讲解举例说明仅此一篇

    JavaScript中Object对象方法超详细讲解举例说明仅此一篇 Object.assign() Object.create() Object.values() Object.entries() ...

  4. 创建健壮的isArray()函数(JavaScript中判断对象类型的种种方法)

    我们知道,JavaScript中检测对象类型的运算符有:typeof.instanceof,还有对象的constructor属性: 1) typeof 运算符 typeof 是一元运算符,返回结果是一 ...

  5. 在JavaScript中删除对象

    本文翻译自:Deleting Objects in JavaScript I'm a bit confused with JavaScript's delete operator. 我对JavaScr ...

  6. 如何在Javascript中访问对象的第一个属性?

    本文翻译自:How to access the first property of an object in Javascript? Is there an elegant way to access ...

  7. 检查值是否是JavaScript中的对象

    如何检查值是否是JavaScript中的Object? #1楼 尝试这个 if (objectName instanceof Object == false) {alert('Not an objec ...

  8. Javascript中的对象和原型(一)(转载)

    面向对象的语言(如Java)中有类的概念,而通过类可以创建任意多个具有相同属性和方法的对象.但是,JavaScript 没有类的概念,因此它的对象也与基于类的语言中的对象有所不同. 要了解面向对象,首 ...

  9. name optimize is not defined 怎么解决_Web前端:怎么在JavaScript中比较对象?

    大家好,我来了,本期为大家带来的前端开发知识是"Web前端:怎么在JavaScript中比较对象?",有兴趣做前端的朋友,一起来看看吧! 比较JavaScript中的原始值很简单. ...

最新文章

  1. 《深入理解Android:Wi-Fi,NFC和GPS》章节连载[节选]--第六章 深入理解wi-Fi Simple Configuration...
  2. Redis进阶-List底层数据结构精讲
  3. 不仅仅是浏览器 走近Chrome开发人员工具
  4. JS_arguments
  5. 都说Python库千千万,这几个你认识不?
  6. 特岗招聘计算机专业要求,咨询特岗教师招聘专业设置问题
  7. 数据库每日一题 2020.05.09
  8. 排序-选择类排序--堆排序简介
  9. 【前端】第三章 Vue
  10. CSS基础——浮动(float)【学习笔记】
  11. MWeb建立静态网站/博客的基础教程
  12. iptables常用
  13. pic系列单片机c语言编程与应用实例,PIC单片机C语言编程实例
  14. php有个schost.exe_windows找不到svchost.exe(附图)
  15. 神经网络软件有哪些,神经网络分析软件
  16. [转]ceph pg peering过程分析
  17. idea服务器与项目连接,idea服务器与项目连接数据库
  18. 确定自动驾驶汽车安全评估指标的挑战
  19. tp5微信公众号开发(1) 申请公众号配置token验证
  20. 如何让溢出的文字省略号显示

热门文章

  1. CPU乱序执行(指令重排序)
  2. MySQL使用精确匹配和范围查询的效率差别
  3. 【报表技术】IReport 图形化报表开发工具安装教程
  4. JTextPane设置颜色出现的问题
  5. 微信支付分申请接入流程
  6. 在Azure安装nginx后反向代理出现的错误
  7. Qt+VS2013编译报错:'cl' 不是内部或外部命令,也不是可运行的程序
  8. python改变字符串类型_python – Sklearn将字符串类标签更改为int
  9. 6.4 你真的了解电子邮件系统的组成和结构吗?(SMTP、POP3、IMAP、MIME……)
  10. 1.1.10 从二分查找BinarySearch开启算法学习之路---《java算法第四版》