惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

AI
AI
O
OpenAI News
Engineering at Meta
Engineering at Meta
F
Fortinet All Blogs
Jina AI
Jina AI
D
Docker
N
News and Events Feed by Topic
TaoSecurity Blog
TaoSecurity Blog
雷峰网
雷峰网
V
V2EX
小众软件
小众软件
N
News | PayPal Newsroom
GbyAI
GbyAI
Recorded Future
Recorded Future
SecWiki News
SecWiki News
WordPress大学
WordPress大学
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
酷 壳 – CoolShell
酷 壳 – CoolShell
Security Latest
Security Latest
Google DeepMind News
Google DeepMind News
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
Hacker News: Ask HN
Hacker News: Ask HN
Project Zero
Project Zero
Cyberwarzone
Cyberwarzone
MyScale Blog
MyScale Blog
T
The Blog of Author Tim Ferriss
U
Unit 42
The Last Watchdog
The Last Watchdog
V
Visual Studio Blog
C
Cisco Blogs
T
Tor Project blog
Google Online Security Blog
Google Online Security Blog
I
InfoQ
Attack and Defense Labs
Attack and Defense Labs
Y
Y Combinator Blog
博客园 - 聂微东
L
LangChain Blog
Blog — PlanetScale
Blog — PlanetScale
Apple Machine Learning Research
Apple Machine Learning Research
S
Schneier on Security
S
Securelist
博客园_首页
W
WeLiveSecurity
P
Privacy International News Feed
S
SegmentFault 最新的问题
博客园 - 【当耐特】
L
LINUX DO - 热门话题
Latest news
Latest news
大猫的无限游戏
大猫的无限游戏
M
MIT News - Artificial intelligence

博客园 - 莫耶

学习RxJS:Cycle.js 学习RxJS: 导入 [Node.js] Node.js项目的持续集成 [Node.js] 使用node-forge保障Javascript应用的传输安全 [Node.js] 对称加密、公钥加密和RSA [Node.js] DSL in action [Node.js] 使用TypeScript编写Node项目 [Node.js] Node.js中的流 [Node.js] 基于Socket.IO 的私聊 [Node.js] 闭包和高阶函数 [Node.js] Promise,Q及Async [Node.js] Express的测试覆盖率 [Node.js] BDD和Mocha框架 [Node.js] ECMAScript 6中的生成器及koa小析 [Node.js] 使用File API 异步上传文件 [Node.js] OAuth 2 和 passport框架 [Node.js] Node + Redis 实现分布式Session方案 [Node.js] Cluster,把多核用起来 Python开源框架Scrapy安装及使用
[Node.js] 也说this
莫耶 · 2014-11-21 · via 博客园 - 莫耶

2014-11-21 19:08  莫耶  阅读(1064)  评论()    收藏  举报

原文地址:http://www.moye.me/2014/11/21/也说this/

引子

Any sufficiently advanced technology is indistinguishable from magic.

— Arthur C.Clarke

老爷子所言不虚,各种技术里都有黑魔法,比如JavaScript,就有着像 this 这样的奇葩存在。

What's this?

this是什么?大概能得到的答案有:

  • 当前方法引用的对象实例
  • 当前调用函数本身
  • 全局上下文(顶层对象)
  • 函数运行的context环境

哪种解释是对的呢?来看段代码:

function foo() {
    console.log(this.a);
}
var a = 2;
var obj = {a: 1};
foo();         // 2 (在Node下是undefined)
foo.call(obj); // 1
obj.foo = foo;
obj.foo();     // 1

在这段代码中,this 呈现了三种可能:

  1. 全局上下文:foo执行时,this 开放式的指向了全局上下文(在node下为undefined,原因在于Global的作用域与浏览器不同
  2. 向方法传递的上下文:Function对象固有的applycall方法,第一个参数均为 thisArg,它将被调用函数做为执行的上下文(在非strict模式,如果这个值为null或undefined,将有污染全局上下文的风险
  3. 方法引用的对象:可以将这个对象看成new创建的对象,函数的this将指向它

看起来是要有无限可能的节奏……好在我提前找到了这本书:

You Don't Know JS: this & Object Prototypes

You Don't Know JS: this & Object Prototypes

To learn this, you first have to learn what this is not, despite any assumptions or misconceptions that may lead you down those paths. this is neither a reference to the function itself, nor is it a reference to the function’s lexical scope.

this is actually a binding that is made when a function is invoked, and what it references is determined entirely by the call-site where thefunction is called.

this 绑定上下文

this 实质上是一种绑定(binding)机制,只关乎函数被调用时所处的 上下文(context),而不关心它在哪里被定义。举个粟子:

function foo(something) {
    this.a = something;
}
var obj1 = {
    foo: foo
};
var obj2 = {};
obj1.foo( 2 );
console.log( obj1.a ); // 2
obj1.foo.call( obj2, 3 );
console.log( obj2.a ); // 3
var bar = new obj1.foo( 4 );
console.log( obj1.a ); // 2
console.log( bar.a ); // 4

this做为一个被绑定的context,甚至与函数依附的对象无关,通过obj1.foo.call( obj2, 3 )一句我们能看清:这个context被引入,函数既可以读也可以修改它,但这里涉及到一个优先级问题,即:为什么 obj1绑定的this.a 没有被foo()改写,却是 obj2的 this.a?

this 绑定优先级

绑定 this 的形式大概有以下几种,它们的优先级如下排列:

  1. 被new过的函数实例,那么函数里的this绑定的就是这个实例对象本身,如 var bar = new foo();
  2. 函数是被 call 或者 apply 调用,那么 this 绑定的是第一个参数: var bar = foo.call( obj2 );
  3. 函数是被某个对象引用的方法,那么它的this 绑定的是这个对象:var bar = obj1.foo();
  4. 最后,就是隐式绑定了,这种情况的this 绑定的是全局上下文,在 strict mode(Node)下是 undefined:var bar = foo();

建议

对于闭包惯用的self = this技俩,You Don't Know JS 一书是不提倡的,它的建议是:

Embrace  this-style mechanisms completely, including using bind(..) where necessary, and try to avoid  self = this ...

Function.prototype.bind,它的实现看起来是这样的:

if (!Function.prototype.bind) {
    Function.prototype.bind = function (oThis) {
        if (typeof this !== "function") {
            // closest thing possible to the ECMAScript 5
            // internal IsCallable function
            throw new TypeError(
                "Function.prototype.bind - what is trying " +
                "to be bound is not callable"
            );
        }
        var aArgs = Array.prototype.slice.call(arguments, 1),
            fToBind = this,
            fNOP = function () {
            },
            fBound = function () {
                return fToBind.apply(
                    (this instanceof fNOP && oThis ? this : oThis),
                    aArgs.concat(Array.prototype.slice.call(arguments))
                )
            };
        fNOP.prototype = this.prototype;
        fBound.prototype = new fNOP();
        return fBound;
    };
}

更多文章请移步我的blog新地址: http://www.moye.me/  

Creative Commons License