http://www.cnblogs.com/Wayou/p/all-this.html
《JavaScript语言精粹》
全局this 浏览器宿主的全局环境中,
function f(xx) {
this.x = xx;
}
f(5);
x//
这个时候,函数 f 里的 this 绑定的是全局对象,如果是在浏览器运行的解释器中,一般来说是 window 对象。
所以这里 this.x 访问的其实是 window.x ,当然,如果 window 没有 x 属性,那么你这么一写,按照 js 的坑爹语法,
就是给 window 对象添加了一个 x 属性,同时赋值。 var y=new f(10);
y.x;//
对于实例y this就是运行的这个函数
上面这个函数和正常调用的函数写法上没什么区别,只不过在调用的时候函数名前面加了关键字 new罢了,这么一来,
this 绑定的就不再是前面讲到的全局对象了,而是这里说的创建的新对象,所以说这种方式其实很危险,
因为光看函数,你不会知道这个函数到底是准备拿来当构造函数用的,还是一般函数用的。 bind() 函数 http://developer.51cto.com/art/201503/466978.htm
https://msdn.microsoft.com/zh-cn/library/ff841995
对于给定函数,创建具有与原始函数相同的主体的绑定函数。在绑定函数中,this 对象将解析为传入的对象。绑定函数具有指定的初始参数。 function a(xx) {
this.b = xx;
}
var o = {};
a.apply(o, [5]);
alert(a.b); // undefined
alert(o.b); // 5 上面讲的无论是 call() 也好, apply() 也好,都是立马就调用了对应的函数,而 bind() 不会, bind() 会生成一个新的函数,
bind() 函数的参数跟 call() 一致,第一个参数也是绑定 this 的值,后面接受传递给函数的不定参数。
bind() 生成的新函数返回后,你想什么时候调就什么时候调,看下代码就明白了 bind()会生成一个新的函数,执行新函数后, 那么它传入的主体就继承(不一定对,但是帮助理解)前者对象的属性了。如下测试 function a(xx) {
this.b = xx;
}
var o = {}; var p = {}; var z={}; var d={};
var km=a.bind(p,18);
a.apply(o, [5]);
o;//Object {b: 5}
o.b//
var y=a.apply(z,[20]);
y//undefined
z//Object {b: 20};
z.b//
var mm=a.call(d,100);
mm;//undefined
d:// Object {b: 100}
d.b//
var km=a.bind(p,18);
p;//Object {}
km//bound a() { [native code] }
km();//执行之后
p;//Object {b: 18}
p.b// 函数或方法里的this
JavaScript原型
原型就是相对实例后对象而言。如
function test(){};
var tp=new tes();
tp的原型就是test
同一函数创建的所有实例均共享一个原型。如果你给原型赋值了一个数组,
那么所有实例都能获取到这个数组。除非你在某个实例中对其进行了重写,实事上是进行了覆盖。
function Thing() {
}
Thing.prototype.things = []; var thing1 = new Thing();
var thing2 = new Thing();
thing1.things.push("foo");
console.log(thing2.things); //logs ["foo"]
通常上面的做法是不正确的(译注:改变thing1的同时也影响了thing2)。
如果你想每个实例互不影响,那么请在函数里创建这些值,而不是在原型上。
function Thing() {
this.things = [];
} var thing1 = new Thing();
var thing2 = new Thing();
thing1.things.push("foo");
console.log(thing1.things); //logs ["foo"]
console.log(thing2.things); //logs [] 多个函数可以形成原型链,这样this便会在原型链上逐步往上找直到找到你想引用的值。
function Thing1() {
}
Thing1.prototype.foo = "bar"; function Thing2() {
}
Thing2.prototype = new Thing1(); var thing = new Thing2();
console.log(thing.foo); //logs "bar"
我习惯将赋值到原型上的函数称作方法。上面某些地方便使用了方法这样的字眼,比如logFoo方法。这些方法中的this同样具有在原
型链上查找引用的魔力。通常将最初用来创建实例的函数称作构造函数。原型链方法中的this是从实例中的this开始住上查找整个
原型链的。也就是说,如果原型链中某个地方直接对this进行赋值覆盖了某个变量,那么我们拿到的是覆盖后的值。
function Thing1() {
}
Thing1.prototype.foo = "bar";
Thing1.prototype.logFoo = function () {
console.log(this.foo);
}
function Thing2() {
this.foo = "foo";
}
Thing2.prototype = new Thing1();
var thing = new Thing2();
thing.logFoo(); //logs "foo"; 在JavaScript中,函数可以嵌套函数,也就是你可以在函数里面继续定义函数。但内层函数是通过闭包获取外层函数里定义的变量值的,而不是直接继承this。
function Thing() {
}
Thing.prototype.foo = "bar";
Thing.prototype.logFoo = function () {
var info = "attempting to log this.foo:";
function doIt() {
console.log(info, this.foo);
}
doIt();
} var thing = new Thing();
thing.logFoo(); //logs "attempting to log this.foo: undefined"
上面示例中,doIt 函数中的this指代是全局作用域或者是undefined如果使用了"use strict";声明的话。对于很多新手来说,理解这点是非常头疼的。
还有更奇葩的。把实例的方法作为参数传递时,实例是不会跟着过去的。也就是说,此时方法中的this在调用时指向的是全局this或者是undefined在声明了"use strict";时。
function Thing() {
}
Thing.prototype.foo = "bar";
Thing.prototype.logFoo = function () {
console.log(this.foo);
} function doIt(method) {
method();
} var thing = new Thing();
thing.logFoo(); //logs "bar"
doIt(thing.logFoo); //logs undefined 所以很多人习惯将this缓存起来,用个叫self或者其他什么的变量来保存,以将外层与内层的this区分开来。
function Thing() {
}
Thing.prototype.foo = "bar";
Thing.prototype.logFoo = function () {
var self = this;
var info = "attempting to log this.foo:";
function doIt() {
console.log(info, self.foo);
}
doIt();
}
var thing = new Thing();
thing.logFoo(); //logs "attempting to log this.foo: bar"
...但上面的方式不是万能的,在将方法做为参数传递时,就不起作用了。
function Thing() {
}
Thing.prototype.foo = "bar";
Thing.prototype.logFoo = function () {
var self = this;
function doIt() {
console.log(self.foo);
}
doIt();
} function doItIndirectly(method) {
method();
}
var thing = new Thing();
thing.logFoo(); //logs "bar"
doItIndirectly(thing.logFoo); //logs undefined 避免在构造函数中返回作何东西,因为返回的东西可能覆盖本来该返回的实例。
function Thing() {
return {};
}
Thing.prototype.foo = "bar"; Thing.prototype.logFoo = function () {
console.log(this.foo);
} var thing = new Thing();
thing.logFoo(); //Uncaught TypeError: undefined is not a function
function Thing11() {
return "888888";
}
Thing11.prototype.foo = "bar"; Thing11.prototype.logFoo = function () {
console.log(this.foo);
}
var thing12 = new Thing11();
thing12.logFoo(); //bar
但,如果你在构造函数里返回的是个原始值比如字符串或者数字什么的,上面的错误就不会发生了,返回语句将被忽略。
所以最好别在一个将要通过new来调用的构造函数中返回作何东西,即使你是清醒的。如果你想实现工厂模式,那么请用一
个函数来创建实例,并且不通过new来调用。当然这只是个人建议。
诚然,你也可以使用Object.create从而避免使用new。这样也能创建一个实例。 原型中的this
function Thing() {
}
Thing.prototype.foo = "bar"; Thing.prototype.logFoo = function () {
console.log(this.foo);
}
var thing = Object.create(Thing.prototype);
thing.logFoo(); //logs "bar" 正因为Object.create没有调用构造函数,这在当你想实现一个继承时是非常有用的,随后你可能想要重写构造函数。
function Thing1() {
this.foo = "foo";
}
Thing1.prototype.foo = "bar"; function Thing2() {
this.logFoo(); //logs "bar" 可以理解
Thing1.apply(this);//apply 可以使参数里面对象拥有前者的属性
this.logFoo(); //logs "foo"
}
Thing2.prototype = Object.create(Thing1.prototype);
Thing2.prototype.logFoo = function () {
console.log(this.foo);
} var thing = new Thing2(); 对象中的this
可以在对象的任何方法中使用this来访问该对象的属性。这与用new得到的实例是不一样的。
ar obj = {
foo: "bar",
logFoo: function () {
console.log(this.foo);
}
};
obj.logFoo(); //logs "bar" 注意这里并没有使用new,也没有用Object.create,更没有函数的调用来创建对象。也可以将函数绑定到对象,就好像这个对象是一个实例一样。
var obj = {
foo: "bar"
}; function logFoo() {
console.log(this.foo);
} logFoo.apply(obj); //logs "bar"
此时使用this没有向上查找原型链的复杂工序。通过this所拿到的只是该对象身上的属性而以。
var obj = {
foo: "bar",
deeper: {
logFoo: function () {
console.log(this.foo);
}
}
}; obj.deeper.logFoo(); //logs undefined
也可以不通过this,直接访问对象的属性。
var obj = {
foo: "bar",
deeper: {
logFoo: function () {
console.log(obj.foo);
}
}
};
obj.deeper.logFoo(); //logs "bar" DOM 事件回调中的this
在DOM事件的处理函数中,this指代的是被绑定该事件的DOM元素。
function Listener() {
document.getElementById("foo").addEventListener("click",
this.handleClick);
}
Listener.prototype.handleClick = function (event) {
console.log(this); //logs "<div id="foo"></div>"
} var listener = new Listener();
document.getElementById("foo").click(); HTML中的this
<div id="foo" onclick="console.log(this);"></div>
<script type="text/javascript">
document.getElementById("foo").click(); //logs <div id="foo"...
</script> eval中的this
eval 中也可以正确获取当前的 this。
function Thing () {
}
Thing.prototype.foo = "bar";
Thing.prototype.logFoo = function () {
eval("console.log(this.foo)"); //logs "bar"
} var thing = new Thing();
thing.logFoo();
这里存在安全隐患。最好的办法就是避免使用eval。 使用Function关键字创建的函数也可以获取this: function Thing () {
}
Thing.prototype.foo = "bar";
Thing.prototype.logFoo = new Function("console.log(this.foo);");
var thing = new Thing();
thing.logFoo(); //logs "bar" 使用with时的this
使用with可以将this人为添加到当前执行环境中而不需要显示地引用this。
function Thing () {
}
Thing.prototype.foo = "bar";
Thing.prototype.logFoo = function () {
with (this) {
console.log(foo);
foo = "foo";
}
} var thing = new Thing();
thing.logFoo(); // logs "bar"
console.log(thing.foo); // logs "foo" jQuery中的this
一如HTML DOM元素的事件回调,jQuery库中大多地方的this也是指代的DOM元素。页面上的事件回调和一些便利的静态方法比如$.each 都是这样的。 <div class="foo bar1"></div>
<div class="foo bar2"></div>
<script type="text/javascript">
$(".foo").each(function () {
console.log(this); //logs <div class="foo...
});
$(".foo").on("click", function () {
console.log(this); //logs <div class="foo...
});
$(".foo").each(function () {
this.click();
});
</script> 传递 this
如果你用过underscore.js或者lo-dash你便知道,这两个库中很多方法你可以传递一个参数来显示指定执行的上下文。比如_.each。自ECMAScript 5 标准后,一些原生的JS方法也允许传递上下文,比如forEach。事实上,上文提到的bind,apply还有call 已经给我们手动指定函数执行上下文的能力了。 function Thing(type) {
this.type = type;
}
Thing.prototype.log = function (thing) {
console.log(this.type, thing);
}
Thing.prototype.logThings = function (arr) {
arr.forEach(this.log, this); // logs "fruit apples..."
_.each(arr, this.log, this); //logs "fruit apples..."
} var thing = new Thing("fruit");
thing.logThings(["apples", "oranges", "strawberries", "bananas"]);

另一篇理解

this的面面观的更多相关文章

  1. 比Redis更快:Berkeley DB面面观

    比Redis更快:Berkeley DB面面观 Redis很火,最近大家用的多.从两年前开始,Memcached转向Redis逐渐成为潮流:而Berkeley DB可能很多朋友还很陌生,首先,我们简单 ...

  2. 《火球——UML大战需求分析》(第2章 耗尽脑汁的需求分析工作)——2.1 需求分析面面观

    说明: <火球——UML大战需求分析>是我撰写的一本关于需求分析及UML方面的书,我将会在CSDN上为大家分享前面几章的内容,总字数在几万以上,图片有数十张.欢迎你按文章的序号顺序阅读,谢 ...

  3. 【夯实PHP基础】PHP数组,字符串,对象等基础面面观

    本文地址 分享提纲 1.数组篇 2.字符创篇 3.函数篇 4.面向对象篇 5.其他篇 /*************************** 一.数组篇 Begin***************** ...

  4. C#单元测试面面观

    标题有点标题党,但相信各位看完这篇文章一定会所收获,如果之前没有接触过单元测试或了解不深通过本文都能对单元测试有个全新认识.本文的特点是不脱离实际,所测试的代码都是常见的模式. 写完这篇文章后,我看了 ...

  5. 【Nginx 大系】Nginx服务器面面观

    Nginx官方文档中文版 1. 先看看百度百科对Nginx 的解释: nginx_百度百科 2. 下面的博客就是讲 Nginx的安装方法和 具体的配置文件的使用介绍的很详细,可以仔细阅读下 [好]Ng ...

  6. 【Apache大系】Apache服务器面面观

    Apache 2.2 中文官方文档 1. 先看看百度百科对Apache的解释: apache(Web服务器)_百度百科 2. apache服务器本质上说是一个TCP socket服务,socket模型 ...

  7. C++的那些事:const用法面面观

    一.const是什么 在 C/C++ 语言中,const关键字是一种修饰符.所谓“修饰符”,就是在编译器进行编译的过程中,给编译器一些“要求”或“提示”,但修饰符本身,并不产生任何实际代码.就 con ...

  8. log4net面面观之工作原理

    转自:逗逼的博客:http://itrust.cnblogs.com/archive/2005/01/25/97225.html 要知道Log4net究竟是咋干活的,咱们可以从下面这个脉络简图入手.你 ...

  9. log4net面面观之Repository

    转:http://itrust.cnblogs.com/archive/2006/07/17/452895.html 上回说道:Repository可以说成基于一个log4net配置节创建的log4n ...

随机推荐

  1. MVVM Command Binding: InvokeCommandAction v.s. EventToCommand

    This gives you the ability to create a trigger on an event and bind it to an ICommand on the view mo ...

  2. [CareerCup] 17.1 Swap Number In Place 互换位置

    17.1 Write a function to swap a number in place (that is, without temporary variables). 这道题让我们交换两个数, ...

  3. css限制div字符超出部分,简单有方便

    text-overflow: -o-ellipsis-lastline;overflow: hidden;text-overflow: ellipsis;display: -webkit-box;-w ...

  4. html中a标签做容器的问题

    今天试验了一下a标签当作容器的问题,若a包含的容器中没有a标签的话,a标签是可以被当作成容器使用的,在谷歌浏览器这种浏览器中是可行的,但是在低版本的IE中会有bug出现,就是浏览器在解析的时候会把a标 ...

  5. svn学习笔记(2)操作----还原,重命名,冲突处理,权限配置等

    1.查看某个文件的所有版本信息 2.版本还原,还原到之前的某一个版本 通过show log查看 查看某个文件的所有版本后,可以在这些版本之间自由切换 3.文件改名 文件改名字给我们一个教训: 如:in ...

  6. 表单的enctype property

    enctype 属性规定在发送到服务器之前应该如何对表单数据进行编码. 默认地,表单数据会编码为 "application/x-www-form-urlencoded".就是说,在 ...

  7. scrum站立会议学习

    项目:连连看游戏 小组名称:临时小组 组长:张政 小组成员: 李权 武志远 张政 张金生 MASTER:张政 会议内容: 一.已完成项: 1.根据先前的安排和计划完成了项目主要环境的搭建,配置好了基本 ...

  8. BizTalk开发系列(二十六) 使用Web Service

    Web Service是在构建SOA平台中广泛使用的技术.在BizTalk开发过程中使用SOAP适配器接收和发送 Web Services 请求.业务流程可以发布为 Web Services 并使用外 ...

  9. BizTalk开发系列(十一) 在Orchestration中执行Pipeline

    由于开发需要有时要在流程中执行Pipeline.比如从DB的某个字段中取消息的字符串并在流程中构造消息.该需要通过pipeline进行升级 属性字段,验证消息等处理.BizTalk架构已经开放了此接口 ...

  10. BizTalk开发系列(四) 深入Map测试

    在BizTalk的开发过程中XML消息间的映射是一个很重要的内容.如果只是一般的从源节点的值复制到目标节点的话,BizTalk项目提供的 MAP测试和验证就已经可以满足需求了.但是很多时候需要在映射的 ...