1.在浏览器中,在一个全局环境中,this
就是window
对象。javascript
<script type="text/javascript"> console.log(this === window); //true </script>
2.在浏览器中,在全局中使用var
至关于分配给this
或者window
java
<script type="text/javascript"> var foo = "bar"; console.log(this.foo); //logs "bar" console.log(window.foo); //logs "bar" </script>
3.假如你建立一个新的变量,不使用var
或者let
(ECMAScript6),你是添加或者改变全局this
的属性node
<script type="text/javascript"> foo = "bar"; function testThis() { foo = "foo"; } console.log(this.foo); //logs "bar" testThis(); console.log(this.foo); //logs "foo" </script>
4.在node中使用repl,this
是最顶级的命名空间,你能够认为是global
数组
> this { ArrayBuffer: [Function: ArrayBuffer], Int8Array: { [Function: Int8Array] BYTES_PER_ELEMENT: 1 }, Uint8Array: { [Function: Uint8Array] BYTES_PER_ELEMENT: 1 }, ... > global === this true
5.在node中执行脚本,在全局中this
是一个空对象,而不与global
相等浏览器
test.js: console.log(this); console.log(this === global);
$ node test.js {} false
6.在node中,全局环境中的var
并不是像在浏览器中执行脚本同样,分配给this
。安全
test.js: var foo = "bar"; console.log(this.foo);
$ node test.js undefined
可是在repl中是同样的app
> var foo = "bar"; > this.foo bar > global.foo bar
7.在node中,使用脚本执行,不用var
或者let
建立的变量会添加到global
而不是this
.函数
test.js foo = "bar"; console.log(this.foo); console.log(global.foo);
$ node test.js undefined bar
在repl中,它是分配到这两个上的。this
除了DOM事件处理程序或者一个thisArg
已经设置的状况外,在node和浏览器中,函数中(不实例化new
)的this是全局范围的。prototype
<script type="text/javascript"> foo = "bar"; function testThis() { this.foo = "foo"; } console.log(this.foo); //logs "bar" testThis(); console.log(this.foo); //logs "foo" </script>
test.js: foo = "bar"; function testThis () { this.foo = "foo"; } console.log(global.foo); testThis(); console.log(global.foo);
$ node test.js bar foo
除非你使用user strict
,this
会变为underfined
<script type="text/javascript"> foo = "bar"; function testThis() { "use strict"; this.foo = "foo"; } console.log(this.foo); //logs "bar" testThis(); //Uncaught TypeError: Cannot set property 'foo' of undefined </script>
当你new
一个函数的时候,this
会成为一个新的上下文,不等同于全局this
<script type="text/javascript"> foo = "bar"; function testThis() { this.foo = "foo"; } console.log(this.foo); //logs "bar" new testThis(); console.log(this.foo); //logs "bar" console.log(new testThis().foo); //logs "foo" </script>
函数对象有一个特殊的属性prototype
,当你建立一个函数实例,能够访问prototype
属性,可使用this
进行访问
function Thing() { console.log(this.foo); } Thing.prototype.foo = "bar"; var thing = new Thing(); //logs "bar" console.log(thing.foo); //logs "bar"
加入建立多个实例化,它们共享原型上的值,this.foo
都会返回相同的值,除非你在实例化函数上进行覆盖。
function Thing() { } Thing.prototype.foo = "bar"; Thing.prototype.logFoo = function () { console.log(this.foo); } Thing.prototype.setFoo = function (newFoo) { this.foo = newFoo; } var thing1 = new Thing(); var thing2 = new Thing(); thing1.logFoo(); //logs "bar" thing2.logFoo(); //logs "bar" thing1.setFoo("foo"); thing1.logFoo(); //logs "foo"; thing2.logFoo(); //logs "bar"; thing2.foo = "foobar"; thing1.logFoo(); //logs "foo"; thing2.logFoo(); //logs "foobar";
this
在一个实例中是一个特殊的对象,this
实际是一个关键字,能够认为this
做为一种方法去访问prototype
,直接分配给this
,将会覆盖原来prototype
上的方法。你能够删除this
挂接的方法,从而恢复访问默认prototype
function Thing() { } Thing.prototype.foo = "bar"; Thing.prototype.logFoo = function () { console.log(this.foo); } Thing.prototype.setFoo = function (newFoo) { this.foo = newFoo; } Thing.prototype.deleteFoo = function () { delete this.foo; } var thing = new Thing(); thing.setFoo("foo"); thing.logFoo(); //logs "foo"; thing.deleteFoo(); thing.logFoo(); //logs "bar"; thing.foo = "foobar"; thing.logFoo(); //logs "foobar"; delete thing.foo; thing.logFoo(); //logs "bar";
或者直接引用函数对象的原型。
function Thing() { } Thing.prototype.foo = "bar"; Thing.prototype.logFoo = function () { console.log(this.foo, Thing.prototype.foo); } var thing = new Thing(); thing.foo = "foo"; thing.logFoo(); //logs "foo bar";
建立的实例都共享相同的属性和方法,若是给prototype
分配一个数组,全部实例都可以访问。
function Thing() { } Thing.prototype.things = []; var thing1 = new Thing(); var thing2 = new Thing(); thing1.things.push("foo"); console.log(thing2.things); //logs ["foo"]
在prototype
上分配一个数组一般是一个错误,若是但愿每一个实例都有本身的数组,那在函数中建立。
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"
在javascript中可使用原型链模拟传统面向对象继承。
使用函数内含有绑定this
的方法或者属性去建立原型链,将会隐藏上层原型链定义的内容。
function Thing1() { } Thing1.prototype.foo = "bar"; function Thing2() { this.foo = "foo"; } Thing2.prototype = new Thing1(); function Thing3() { } Thing3.prototype = new Thing2(); var thing = new Thing3(); console.log(thing.foo); //logs "foo"
我喜欢叫绑定在原型上的函数为methods.在methods中使用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
指向global
,在use strict
下则为undefined
,这是不少不熟悉this
用法的人痛苦的根源之一。
更坏的状况是,将一个实例方法做为参数传入函数。this
将指向global
,在use strict
下则为undefined
。
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
指向global
这个问题。
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
解决这个方法,可使用函数绑定的方法bind
。
function Thing() { } Thing.prototype.foo = "bar"; Thing.prototype.logFoo = function () { console.log(this.foo); } function doIt(method) { method(); } var thing = new Thing(); doIt(thing.logFoo.bind(thing)); //logs bar
你也可使用apply
或者call
在新的上下文环境中调用方法或者函数。
function Thing() { } Thing.prototype.foo = "bar"; Thing.prototype.logFoo = function () { function doIt() { console.log(this.foo); } doIt.apply(this); } function doItIndirectly(method) { method(); } var thing = new Thing(); doItIndirectly(thing.logFoo.bind(thing)); //logs bar
可使用bind
替换this
,适用于任何函数或方法,即便没有在实例原型上定义。
function Thing() { } Thing.prototype.foo = "bar"; function logFoo(aStr) { console.log(aStr, this.foo); } var thing = new Thing(); logFoo.bind(thing)("using bind"); //logs "using bind bar" logFoo.apply(thing, ["using apply"]); //logs "using apply bar" logFoo.call(thing, "using call"); //logs "using call bar" logFoo("using nothing"); //logs "using nothing 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
奇怪的是,假如你返回的是原始值(string或者number),返回语句将会被忽略。最好不要从你打算调用的构造函数中返回任何东西,即便你知道你在作什么。若是你想建立一个工厂模式,使用一个函数来建立实例,不要用new
的。固然,这只是我的观点。
避免使用new
`,使用Object.create
也能建立一个实例
function Thing() { } Thing.prototype.foo = "bar"; Thing.prototype.logFoo = function () { console.log(this.foo); } var thing = Object.create(Thing.prototype); thing.logFoo(); //logs "bar"
然而这不会调用构造函数。
function Thing() { this.foo = "foo"; } 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); this.logFoo(); //logs "foo" } Thing2.prototype = Object.create(Thing1.prototype); Thing2.prototype.logFoo = function () { console.log(this.foo); } var thing = new Thing2();
能够在对象的任何函数中使用this
来引用该对象上的其余属性。这与使用new
实例不一样。
var obj = { foo: "bar", logFoo: function () { console.log(this.foo); } }; obj.logFoo(); //logs "bar"
不使用new
,Object.create
,function
去建立一个对象,也能够像实例化同样绑定到对象上。
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
你能够直接使用你想要的属性。
var obj = { foo: "bar", deeper: { logFoo: function () { console.log(obj.foo); } } }; obj.deeper.logFoo(); //logs "bar"
在一个HTML DOM event处理程序中,this
一般是指DOM element event绑定的对象
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();
除非你绑定新的上下文
function Listener() { document.getElementById("foo").addEventListener("click", this.handleClick.bind(this)); } Listener.prototype.handleClick = function (event) { console.log(this); //logs Listener {handleClick: function} } var listener = new Listener(); document.getElementById("foo").click();
在HTML属性中能够放js代码,this
指向当前的元素
<div id="foo" onclick="console.log(this);"></div> <script type="text/javascript"> document.getElementById("foo").click(); //logs <div id="foo"... </script>
this的覆盖
你不可以复写this
,由于它是一个关键词
function test () { var this = {}; // Uncaught SyntaxError: Unexpected token this }
可使用eavl
访问this
function Thing () { } Thing.prototype.foo = "bar"; Thing.prototype.logFoo = function () { eval("console.log(this.foo)"); //logs "bar" } var thing = new Thing(); thing.logFoo();
这种作法有安全隐患,可使用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
添加到当前的范围来读取和写入值,而不用显式调用。
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"
不少人认为这是错的作法,鉴于with
引发的歧义。
像HTML DOM elements的事件处理程序同样,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>
鉴于笔者翻译水平有限,有什么问题欢迎提出指教。
原文地址:all this