- 浏览: 5167796 次
- 性别:
- 来自: 天津
博客专栏
-
实战 Groovy
浏览量:29354
文章分类
- 全部博客 (639)
- 代码之谜 (6)
- JavaScript quirks (5)
- 程序员 (92)
- Java (93)
- BT编程 (7)
- html/css (64)
- Groovy&Grails (42)
- Android (20)
- C/C++ (5)
- PHP/Perl/Python (46)
- 经典文章 (51)
- CodeIgniter (14)
- JQuery (10)
- 笑话 (4)
- 其他 (32)
- javascript (69)
- 云计算 (0)
- html5 (7)
- 面试 (8)
- google (3)
- nosql (2)
- nodejs (11)
- go (5)
- erlang (1)
- 小常识 (3)
- 冷知识 (5)
- database (4)
- web (12)
- 架构 (12)
- Exception (0)
最新评论
-
jqw1992:
https://www.chromefor.com/libra ...
[福利] 开发者必备的 Chrome 插件——ChromeSnifferPlus -
litjerk:
初步算了一下,目前最最精简的Win98版是5M,他5个小时多敲 ...
让人目瞪口呆的三位世界级电脑大师 -
379855529:
。。似乎重点没说NIO啊,前面基础只是铺垫的很好的,可是我要的 ...
Java NIO与IO的详细区别(通俗篇) -
springmvc_springjpa:
spring mvc demo教程源代码下载,地址:http: ...
一步步开发 Spring MVC 应用 -
匡建武:
Good
四个程序员的一天
近期群里常有人提一些简单的问题,比如发一段代码乱七八糟的代码,然后说里面某个变量是什么,比如这里就有个很好的例子:
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.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() {
alert(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();
alert(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
。
this的查找
this的查找是很多人迷茫的一点,也似乎有很多人抱有this不稳定这样的看法,实在令人无语。this的查找可以说是3种对象查找中最为简单的,因为其实this对象的确定根本没有一个“查找”的过程。
首先,this对象只会在一个函数中需要确定,如果是在全局域下,this永远为Global对象,在浏览器中通常就是window对象。而在javascript中,函数的调用一共有4种方式:
诸如`foo()`的调用形式被称为Function Invocation Pattern,是函数最直接的使用形式,注意这里的foo是作为单独的变量出现,而不是属性。
在这种模式下,foo函数体中的this永远为Global对象,在浏览器中就是window对象。
诸如`foo.bar()`的调用形式被称为Method Invocation Pattern,注意其特点是被调用的函数作为一个对象的属性出现,必然会有“.”或者“[]”这样的关键符号。
在这种模式下,bar函数体中的this永远为“.”或“[”前的那个对象,如上例中就一定是foo对象。
`new foo()`这种形式的调用被称为Constructor Pattern,其关键字`new`就很能说明问题,非常容易识别。
在这种模式下,foo函数内部的this永远是new foo()返回的对象。
`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。
发表评论
-
Lo-Dash 与 underscore,Prototype 与 jQuery,两段恩怨情仇
2015-12-15 09:35 1681这几天更新我的之前写的 Chrome 插件 ChromeSn ... -
开发者必备的 Chrome 扩展
2014-11-03 15:01 2003Firebug:不用多介绍了吧https://chrome. ... -
开发者福利!ChromeSnifferPlus 插件正式登陆 Chrome Web Store
2014-10-30 21:14 106584今天(2014-10-30)下午,ChromeSniffer ... -
Firebase 相关文章索引
2014-10-23 10:21 2198Awesome Firebase 最近谷歌收购Fireb ... -
JSON API:用 JSON 构建 API 的标准指南中文版
2014-10-14 08:26 19860译文地址:https://github. ... -
前端开发,从菜鸟到大牛的取经之路
2014-07-14 15:15 378876以我的经验,大部分技术,熟读下列四类书籍即可。 入门, ... -
JavaScript Puzzlers 解密(一):为什么 ["1", "2", "3"].map(parseInt) 返回 [1, NaN, NaN]?
2014-02-19 10:58 40416JavaScript Puzzlers! 被称为 javas ... -
JavaScript 的怪癖 4:未知变量名创建全局变量
2013-12-02 15:25 1383原文:JavaScript quirk 4: unknown ... -
JavaScript 的怪癖 5:参数的处理
2013-12-02 15:23 3232原文:JavaScript quirk 5: parame ... -
【ghost初级教程】 怎么搭建一个免费的ghost博客
2013-10-28 14:10 6201ghost博客系统无疑是这个月最火热的话题之一,这个号称” ... -
10 个你需要了解的最佳 javascript 开发实践
2013-10-16 13:54 3595Javascript 的很多扩展的特性是的它变得更加的犀利 ... -
基于 canvas 将图片转化成字符画
2013-09-26 15:05 6576猛点 这里 看高清 ... -
详解一下 javascript 中的比较
2013-09-22 09:30 1914代码1: [] == []; // false ... -
谈 javascript 变量声明
2013-06-14 10:35 1885这篇文章还是对基础的复习,对面试经历的一个总结。 之前的 ... -
[译]Javascript 作用域和变量提升
2013-06-13 13:16 5182下面的程序是什么结果? var fo ... -
javascript:可以运行的噪音
2013-06-01 09:34 9268为我的博客做了一个很有 geek 风格的关于页面。运行下面 ... -
【layoutit!】基于 bootstrap 实现可视化布局工具
2013-05-20 11:23 14618Layout It 是一个在线工具,它可以简单而又快速搭建 ... -
回复:浮点数0.57 0.58 造出的坑爹问题
2013-05-09 11:30 25137今天看到 vb2005xu 提到了一个问题 浮点数0.5 ... -
javascript 中强制执行 toString()
2013-04-26 13:25 1538原文:Enforcing toString() 译文:ja ... -
JavaScript 中的“自动分号插入”机制(ASI)
2013-04-24 08:41 8423原文:Automatic semicolon insert ...
相关推荐
原型链是JavaScript中对象查找机制的核心概念。当尝试访问一个对象的属性时,如果该对象本身没有定义该属性,则JavaScript引擎会沿着该对象的原型链向上查找,直至找到该属性为止。 每个JavaScript对象都有一个内部...
在JavaScript中,数组和对象是两种非常基础且重要的数据结构,它们被广泛应用于各种场景,如数据存储、逻辑处理和对象表示。这篇文章将深入探讨这两种数据类型,以及相关的操作和工具。 **一、数组** 数组在...
- **第三章:JavaScript中的类和对象**:详细介绍如何使用JavaScript创建类和对象。 - **第四章:继承**:探讨JavaScript中实现继承的不同方式。 - **第五章:封装和私有性**:讲解如何在JavaScript中实现封装以及...
当尝试访问对象的一个属性时,JavaScript会首先在当前对象中查找,如果找不到,就会沿着原型链向上查找,直到找到为止。 4. **继承**:JavaScript支持多种继承方式,如原型链继承、构造函数继承、组合继承、原型式...
当试图访问一个对象的属性时,如果该对象自身没有这个属性,JavaScript会查找其原型对象,如果原型对象也没有,会继续查找原型的原型,直到找到属性或者到达原型链的末端(即null)。这就是所谓的原型链。在...
Number对象用于处理数值类型,虽然在JavaScript中数字是基本类型,但Number对象提供了一些有用的静态方法,如`isNaN()`检查是否为非数字值,`parseInt()`和`parseFloat()`用于从字符串中解析数字,以及`toFixed()`...
JavaScript是一种广泛应用于Web开发的脚本语言,尤其在构建交互式网页和动态应用程序时不可或...通过阅读和实践这些案例,你可以逐步掌握如何创建、继承和操作JavaScript对象,从而成为一名更出色的JavaScript开发者。
在本“JavaScript面向对象编程”主题中,我们将深入探讨这一概念及其在JavaScript中的应用。 1. **对象和类的概念**:在面向对象编程中,对象是数据和操作这些数据的方法的集合。在JavaScript中,对象是由键值对...
当试图访问一个对象的属性时,JavaScript会查找该对象自身,然后沿着原型链向上查找,直到找到该属性或到达原型链的顶端。 4. **原型对象的修改** 可以通过`__proto__`属性或`Object.getPrototypeOf`方法获取一个...
下面详细介绍JavaScript对象的知识点: 1. 对象的定义和属性访问 在JavaScript中,对象可以被视为键值对的集合。对象中的每个属性或方法都通过一个唯一的名称(属性名)进行标识。这些属性名可以是任何字符串,包括...
2. **JavaScript对象** 在JavaScript中,一切皆为对象。核心对象如全局对象、Math对象、Date对象、String对象、Array对象等,提供了丰富的内置方法来处理各种操作。例如,Math对象包含各种数学函数,如圆周率π...
JavaScript中的每个对象都有一个指向其原型对象的内部链接,当试图访问一个对象的属性时,如果在当前对象上找不到该属性,解释器会继续在原型对象上查找,这个过程会一直持续到找到该属性或到达原型链的末端。...
由于所有的JavaScript对象都继承自全局对象Object,因此,任何对象都可以调用其他对象的方法,这就实现了多态性。 5. 原型和原型链 在JavaScript中,对象都有一个特殊的内部属性[[Prototype]],通常通过__proto__或...
6. **原型和原型链**:每个JavaScript对象都有一个内置的`__proto__`属性,指向创建该对象的构造函数的原型。通过原型链,对象可以访问其原型上的属性和方法,形成一个连续的对象查找链。 7. **对象字面量和属性...
当查找一个对象的属性时,如果这个对象本身没有这个属性,JavaScript会继续在原型链上查找,直到找到该属性或者到达原型链的末端。 2. **构造函数和new操作符**:构造函数用于创建具有特定初始状态的对象。new操作...
4. **原型链**:当试图访问对象的一个属性时,JavaScript会首先在当前对象中查找,如果没有找到,会继续在它的原型对象中查找,直到找到或到达原型链的末端(null)。这就是原型链的工作原理。 5. **继承**:...
在JavaScript中,对象可以直接创建,无需预先声明类,而且对象的属性和方法可以在运行时动态添加或修改。 **基于静态类的特性** 1. **类与实例**:在基于类的编程中,类是一个模板,用于创建具有相同结构和行为的...