当有人问起你JavaScript有什么特点的时候,你可能立马就想到了单线程、事件驱动、面向对象等一堆词语,但是如果真的让你解释一下这些概念,可能真解释不清楚。有句话这么说:如果你不能向一个6岁小孩解释清楚一个东西,那么你自己也不懂这个东西。这句话或许有点夸张,但是极其有道理。个人觉得,如果需要掌握一门语言,掌握它的API只是学了皮毛,理解这门语言的精髓才是重点。提及JavaScript的精髓,this、闭包、作用域链、函数是当之无愧的。这门语言正式因为这几个东西而变得魅力无穷。

  博客的标题是《JavaScript中的this陷阱的最全收集--没有之一》,很显然这篇博客阐述的是this。相信做过JavaScript开发的人都遇到过不少this的陷阱,我自己本身也遇到过不少坑,但是如果非要给出一个系统的总结的话,还没有足够的底蕴。非常幸运的是,今天早上起来看《Hacker News》的时候,恰巧看到了一篇有关于JavaScript this的解析:all this。于是,本着学习和共享的精神,决定将它翻译成中文。翻译的目的绝对不是为了当大自然的搬运工,在这个过程中会完全弄明白别人的著作,加深认识,同时将好东西分享给别人,才能让更多的学习者站在巨人的肩膀上前进。按照我自己的习惯,会翻译的过程中加上一些自己解释(斜体文字),毕竟中西方人的思考方式是有差异的。当然文章标题所述的最全也不是吹的,文章非常长。

  在正式翻译之前,还是加上一句,翻译不易,如需转载,请加上原文链接http://www.cnblogs.com/yuanzm/p/4150558.html

原文翻译:

  JavaScript来自一门健全的语言,所以你可能觉得JavaScript中的this和其他面向对象的语言如java的this一样,是指存储在实例属性中的值。事实并非如此,在JavaScript中,最好把this当成哈利波特中的博格特的背包,有着深不可测的魔力。

  下面的部分是我希望我的同事在使用JavaScript的this的时候应当知道的。内容很多,是我学习好几年总结出来的。

  JavaScript中很多时候会用到this,下面详细介绍每一种情况。在这里我想首先介绍一下宿主环境这个概念。一门语言在运行的时候,需要一个环境,叫做宿主环境。对于JavaScript,宿主环境最常见的是web浏览器,浏览器提供了一个JavaScript运行的环境,这个环境里面,需要提供一些接口,好让JavaScript引擎能够和宿主环境对接。JavaScript引擎才是真正执行JavaScript代码的地方,常见的引擎有V8(目前最快JavaScript引擎、Google生产)、JavaScript core。JavaScript引擎主要做了下面几件事情:(1)一套与宿主环境相联系的规则;(2)JavaScript引擎内核(基本语法规范、逻辑、命令和算法);(3)一组内置对象和API;(4)其他约定。 但是环境不是唯一的,也就是JavaScript不仅仅能够在浏览器里面跑,也能在其他提供了宿主环境的程序里面跑,最常见的就是nodejs。同样作为一个宿主环境,nodejs也有自己的JavaScript引擎--V8。根据官方的定义 Node.js is a platform built on Chrome’s JavaScript runtime for easily building fast, scalable network applications

global this

  (1) 在浏览器里,在全局范围内,this等价于window对象。

<script type="text/javascript">
console.log(this === window); //true
</script>

  (2) 在浏览器里,在全局范围内,用var声明一个变量和给this或者window添加属性是等价的。

<script type="text/javascript">
var foo = "bar";
console.log(this.foo); //logs "bar"
console.log(window.foo); //logs "bar"
</script>

  (3) 如果你在声明一个变量的时候没有使用var或者let(ECMAScript 6),你就是在给全局的this添加或者改变属性值。

  <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(Read-Eval-Print Loop,简称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环境里,如果执行一个js脚本,在全局范围内,this以一个空对象开始作为最高级的命名空间,这个时候,它和global不是等价的。

  test.js脚本内容:

  console.log(this);
console.log(this === global); REPL运行脚本: $ node test.js
{}
false

  (6) 在node环境里,在全局范围内,如果你用REPL执行一个脚本文件,用var声明一个变量并不会和在浏览器里面一样将这个变量添加给this。

 test.js:

 var foo = "bar";
console.log(this.foo); $ node test.js
undefined

  (7) 但是如果你不是用REPL执行脚本文件,而是直接执行代码,结果和在浏览器里面是一样的(神坑)

 > var foo = "bar";
> this.foo
bar
> global.foo
bar

  (8) 在node环境里,用REPL运行脚本文件的时候,如果在声明变量的时候没有使用var或者let,这个变量会自动添加到global对象,但是不会自动添加给this对象。如果是直接执行代码,则会同时添加给global和this

 test.js

 foo = "bar";
console.log(this.foo);
console.log(global.foo); $ node test.js
undefined
bar

  上面的八种情况可能大家已经绕晕了,总结起来就是:在浏览器里面this是老大,它等价于window对象,如果你声明一些全局变量(不管在任何地方),这些变量都会作为this的属性。在node里面,有两种执行JavaScript代码的方式,一种是直接执行写好的JavaScript文件,另外一种是直接在里面执行一行行代码。对于直接运行一行行JavaScript代码的方式,global才是老大,this和它是等价的。在这种情况下,和浏览器比较相似,也就是声明一些全局变量会自动添加给老大global,顺带也会添加给this。但是在node里面直接脚本文件就不一样了,你声明的全局变量不会自动添加到this,但是会添加到global对象。所以相同点是,在全局范围内,全局变量终究是属于老大的。

function this

  (1) 无论是在浏览器环境还是node环境, 除了在DOM事件处理程序里或者给出了thisArg(接下来会讲到)外,如果不是用new调用,在函数里面使用this都是指代全局范围的this。

  <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

  (2) 除非你使用严格模式,这时候this就会变成undefined。

  <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>

  (3) 如果你在调用函数的时候在前面使用了new,this就会变成一个新的值,和global的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>

  我更喜欢把新的值称作一个实例。

  函数里面的this其实相对比较好理解,如果我们在一个函数里面使用this,需要注意的就是我们调用函数的方式,如果是正常的方式调用函数,this指代全局的this,如果我们加一个new,这个函数就变成了一个构造函数,我们就创建了一个实例,this指代这个实例,这个和其他面向对象的语言很像。另外,写JavaScript很常做的一件事就是绑定事件处理程序,也就是诸如button.addEventListener(‘click’, fn, false)之类的,如果在fn里面需要使用this,this指代事件处理程序对应的对象,也就是button。

 prototype this

  (1) 你创建的每一个函数都是函数对象。它们会自动获得一个特殊的属性prototype,你可以给这个属性赋值。当你用new的方式调用一个函数的时候,你就能通过this访问你给prototype赋的值了。

 function Thing() {
console.log(this.foo);
} Thing.prototype.foo = "bar"; var thing = new Thing(); //logs "bar"
console.log(thing.foo); //logs "bar"

  (2) 当你使用new为你的函数创建多个实例的时候,这些实例会共享你给prototype设定的值。对于下面的例子,当你调用this.foo的时候,都会返回相同的值,除非你在某个实例里面重写了自己的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";

  (3) 实例里面的this是一个特殊的对象。你可以把this想成一种获取prototype的值的一种方式。当你在一个实例里面直接给this添加属性的时候,会隐藏prototype中与之同名的属性。如果你想访问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";

  (4) 或者你也能直接通过引用函数对象的prototype 来获得你需要的值。

  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";

  (5) 通过一个函数创建的实例会共享这个函数的prototype属性的值,如果你给这个函数的prototype赋值一个Array,那么所有的实例都会共享这个Array,除非你在实例里面重写了这个Array,这种情况下,函数的prototype的Array就会被隐藏掉。

 function Thing() {
}
Thing.prototype.things = []; var thing1 = new Thing();
var thing2 = new Thing();
thing1.things.push("foo");
console.log(thing2.things); //logs ["foo"]

  (6) 给一个函数的prototype赋值一个Array通常是一个错误的做法。如果你想每一个实例有他们专属的Array,你应该在函数里面创建而不是在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 []

  (7) 实际上你可以通过把多个函数的prototype链接起来的从而形成一个原型链,因此this就会魔法般地沿着这条原型链往上查找直到找你你需要引用的值。

  function Thing1() {
}
Thing1.prototype.foo = "bar"; function Thing2() {
}
Thing2.prototype = new Thing1(); var thing = new Thing2();
console.log(thing.foo); //logs "bar"

  (8) 一些人利用原型链的特性来在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"

  (9) 我喜欢把被赋值给prototype的函数叫做方法。在上面的例子中,我已经使用过方法了,如logFoo。这些方法有着相同的prototype,即创建这些实力的原始函数。我通常把这些原始函数叫做构造函数。

  在prototype里面定义的方法里面使用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";

  (10) 在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对象或者在严格模式下面是undefined。这是造成很多不熟悉JavaScript的人深陷this陷阱的根源。在这种情况下事情变得非常糟糕,就像你把一个实例的方法当作一个值,把这个值当作函数参数传递给另外一个函数但是却不把这个实例传递给这个函数一样。在这种情况下,一个方法里面的环境变成了全局范围,或者在严格模式下面的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

  (11) 一些人喜欢先把this捕获到一个变量里面,通常这个变量叫做self,来避免上面这种情况的发生。

  博主非常喜欢用这种方式

  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将实例和方法一切传递给函数来解决这个问题,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,即便它没有赋值给实例的初始prototype。

  function Thing() {
2 }
3 Thing.prototype.foo = "bar";
4
5
6 function logFoo(aStr) {
7 console.log(aStr, this.foo);
8 }
9
10
11 var thing = new Thing();
12 logFoo.bind(thing)("using bind"); //logs "using bind bar"
13 logFoo.apply(thing, ["using apply"]); //logs "using apply bar"
14 logFoo.call(thing, "using call"); //logs "using call bar"
15 logFoo("using nothing"); //logs "using nothing undefined"

  (12) 你应该避免在构造函数里面返回任何东西,因为这可能代替本来应该返回的实例。

 1 function Thing() {
2 return {};
3 }
4 Thing.prototype.foo = "bar";
5
6
7 Thing.prototype.logFoo = function () {
8 console.log(this.foo);
9 }
10
11
12 var thing = new Thing();
13 thing.logFoo(); //Uncaught TypeError: undefined is not a function

  奇怪的是,如果你在构造函数里面返回了一个原始值,上面所述的情况并不会发生并且返回语句被忽略了。最好不要在你将通过new调用的构造函数里面返回任何类型的数据,即便你知道自己正在做什么。如果你想创建一个工厂模式,通过一个函数来创建一个实例,这个时候不要使用new来调用函数。当然这个建议是可选的。

  你可以通过使用Object.create来避免使用new,这样同样能够创建一个实例。

 1 function Thing() {
2 }
3 Thing.prototype.foo = "bar";
4
5
6 Thing.prototype.logFoo = function () {
7 console.log(this.foo);
8 }
9
10
11 var thing = Object.create(Thing.prototype);
12 thing.logFoo(); //logs "bar"

  在这种情况下并不会调用构造函数

 1 function Thing() {
2 this.foo = "foo";
3 }
4 Thing.prototype.foo = "bar";
5
6
7 Thing.prototype.logFoo = function () {
8 console.log(this.foo);
9 }
10
11
12 var thing = Object.create(Thing.prototype);
13 thing.logFoo(); //logs "bar"

  因为Object.create不会调用构造函数的特性在你继承模式下你想通过原型链重写构造函数的时候非常有用。

 1 function Thing1() {
2 this.foo = "foo";
3 }
4 Thing1.prototype.foo = "bar";
5
6 function Thing2() {
7 this.logFoo(); //logs "bar"
8 Thing1.apply(this);
9 this.logFoo(); //logs "foo"
10 }
11 Thing2.prototype = Object.create(Thing1.prototype);
12 Thing2.prototype.logFoo = function () {
13 console.log(this.foo);
14 }
15
16 var thing = new Thing2();

 object this

  (1) 在一个对象的一个函数里,你可以通过this来引用这个对象的其他属性。这个用new来新建一个实例是不一样的。

1 var obj = {
2 foo: "bar",
3 logFoo: function () {
4 console.log(this.foo);
5 }
6 };
7
8 obj.logFoo(); //logs "bar"

  注意,没有使用new,没有使用Object.create,也没有使用函数调用创建一个对象。你也可以将对象当作一个实例将函数绑定到上面。

1 var obj = {
2 foo: "bar"
3 };
4
5 function logFoo() {
6 console.log(this.foo);
7 }
8
9 logFoo.apply(obj); //logs "bar"

  (2) 当你用这种方式使用this的时候,并不会越出当前的对象。只有有相同直接父元素的属性才能通过this共享变量

 1 var obj = {
2 foo: "bar",
3 deeper: {
4 logFoo: function () {
5 console.log(this.foo);
6 }
7 }
8 };
9
10 obj.deeper.logFoo(); //logs undefined

  你可以直接通过对象引用你需要的属性

var obj = {
foo: "bar",
deeper: {
logFoo: function () {
console.log(obj.foo);
}
}
}; obj.deeper.logFoo(); //logs "bar"

DOM event this

  在一个HTML DOM事件处理程序里面,this始终指向这个处理程序被所绑定到的HTML DOM节点

 1 function Listener() {
2 document.getElementById("foo").addEventListener("click",
3 this.handleClick);
4 }
5 Listener.prototype.handleClick = function (event) {
6 console.log(this); //logs "<div id="foo"></div>"
7 }
8
9 var listener = new Listener();
10 document.getElementById("foo").click();

  除非你自己通过bind切换了上下文

 1 function Listener() {
2 document.getElementById("foo").addEventListener("click",
3 this.handleClick.bind(this));
4 }
5 Listener.prototype.handleClick = function (event) {
6 console.log(this); //logs Listener {handleClick: function}
7 }
8
9 var listener = new Listener();
10 document.getElementById("foo").click();

HTML this

  在HTML节点的属性里面,你可以放置JavaScript代码,this指向了这个元素

1 <div id="foo" onclick="console.log(this);"></div>
2 <script type="text/javascript">
3 document.getElementById("foo").click(); //logs <div id="foo"...
4 </script>

override this

  你不能重写this,因为它是保留字。

1 function test () {
2 var this = {}; // Uncaught SyntaxError: Unexpected token this
3 }

eval this

  (1)你可以通过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,没有其他方式来避免这个问题。

  (2) 在通过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的属性的时候不需要通过this

 1 function Thing () {
2 }
3 Thing.prototype.foo = "bar";
4 Thing.prototype.logFoo = function () {
5 with (this) {
6 console.log(foo);
7 foo = "foo";
8 }
9 }
10
11 var thing = new Thing();
12 thing.logFoo(); // logs "bar"
13 console.log(thing.foo); // logs "foo"

  许多人认为这样使用是不好的因为with本身就饱受争议。

jQuery this

  和HTML DOM元素节点的事件处理程序一样,在许多情况下JQuery的this都指向HTML元素节点。这在事件处理程序和一些方便的方法中都是管用的,比如$.each

 1 <div class="foo bar1"></div>
2 <div class="foo bar2"></div>
3 <script type="text/javascript">
4 $(".foo").each(function () {
5 console.log(this); //logs <div class="foo...
6 });
7 $(".foo").on("click", function () {
8 console.log(this); //logs <div class="foo...
9 });
10 $(".foo").each(function () {
11 this.click();
12 });
13 </script>

thisArg  this

  如果你用过underscore.js 或者 lo-dash 你可能知道许多类库的方法可以通过一个叫做thisArg 的函数参数来传递实例,这个函数参数会作为this的上下文。举个例子,这适用于_.each。原生的JavaScript在ECMAScript 5的时候也允许函数传递一个thisArg参数了,比如forEach。事实上,之前阐述的bind,apply和call的使用已经给你创造了传递thisArg参数给函数的机会。这个参数将this绑定为你所传递的对象。

 1 function Thing(type) {
2 this.type = type;
3 }
4 Thing.prototype.log = function (thing) {
5 console.log(this.type, thing);
6 }
7 Thing.prototype.logThings = function (arr) {
8 arr.forEach(this.log, this); // logs "fruit apples..."
9 _.each(arr, this.log, this); //logs "fruit apples..."
10 }
11
12 var thing = new Thing("fruit");
13 thing.logThings(["apples", "oranges", "strawberries", "bananas"]);

  这使得代码变得更加简介,因为避免了一大堆bind语句、函数嵌套和this暂存的使用。

 

JavaScript中的this陷阱的更多相关文章

  1. JavaScript中的this陷阱的最全收集 没有之一

    当有人问起你JavaScript有什么特点的时候,你可能立马就想到了单线程.事件驱动.面向对象等一堆词语,但是如果真的让你解释一下这些概 念,可能真解释不清楚.有句话这么说:如果你不能向一个6岁小孩解 ...

  2. 转:JavaScript中的this陷阱的最全收集

    在其他地方看到的,觉得解释的狠详细,特此分享 当有人问起你JavaScript有什么特点的时候,你可能立马就想到了单线程.事件驱动.面向对象等一堆词语,但是如果真的让你解释一下这些概念,可能真解释不清 ...

  3. JavaScript中的this陷阱的最全收集

    JavaScript来自一门健全的语言,所以你可能觉得JavaScript中的this和其他面向对象的语言如java的this一样,是指存储在实例属性中的值.事实并非如此,在JavaScript中,最 ...

  4. JavaScript中的小陷阱(不定期更新。。)

    1. var scores = [1, 2, 3]; var total = 0; for (var score in scores) { total += score; } var mean = t ...

  5. 【JavaScript】JavaScript中的陷阱大集合

    本文主要介绍怪异的Javascript,毋庸置疑,它绝对有怪异的一面.当软件开发者开始使用世界上使用最广泛的语言编写代码时,他们会在这个过 程中发现很多有趣的“特性”.即便是老练的Javascript ...

  6. JavaScript中for..in循环陷阱介绍

    for...in循环中的循环计数器是字符串,而不是数字它包含当前属性的名称或当前数组元素的索引,下面有个不错的示例大家可以参考下   大家都知道在JavaScript中提供了两种方式迭代对象: (1) ...

  7. JavaScript 中 4 种常见的内存泄露陷阱

    了解 JavaScript 的内存泄露和解决方式! 在这篇文章中我们将要探索客户端 JavaScript 代码中常见的一些内存泄漏的情况,并且学习如何使用 Chrome 的开发工具来发现他们.读一读吧 ...

  8. JavaScript 中常见的内存泄露陷阱(摘)

    内存泄露是每个开发者最终都不得不面对的问题.即便使用自动内存管理的语言,你还是会碰到一些内存泄漏的情况.内存泄露会导致一系列问题,比如:运行缓慢,崩溃,高延迟,甚至一些与其他应用相关的问题. 什么是内 ...

  9. javascript中的for in循环和for in循环的使用陷阱

    javascript中的for循环和for...in循环还是有些区别的,比如定义一个数组,然后用for..in循环输出 var array=[1,2,3,4,5,6]; for(var s in ar ...

随机推荐

  1. codevs 1155今明的预算方案(复习有依赖性的背包问题)

    1155 金明的预算方案 [题目大意]买附件必须买主件. 在一定钱数内 求总价值最大. [题解]有依赖性的背包问题. [code] #include<iostream> #include& ...

  2. starUML安装与破解

    安装包百度云: 链接:https://pan.baidu.com/s/1oF_DH7Xh6yun6fFUDB2H3w 密码:1z7e 破解步骤:1. 首先打开你的starUML安装目录,并找到Lice ...

  3. MakeFile 文件的使用

    什么是Makefile? 一个工程中的源文件不计其数,其按类型.功能.模块分别放在若干个目录中,makefile定义了一系列的规则来指定,哪些文件需要先编译,哪些文件需要后编译,哪些文件需要重新编译, ...

  4. JavaScript实现Select选择本周、上周、本季、上季、本年的时间选取

    //转自http://blog.csdn.net/xc_young/article/details/16878849,其上季度有错误,已修改 var MrYangUtil = function () ...

  5. CodeForces 1098F. Ж-function

    题目简述:给定字符串$s[1 \dots n](n \leq 2 \times 10^5)$,以及$Q \leq 2 \times 10^5$个询问,每个询问有两个参数$1 \leq l \leq r ...

  6. 国内互联网公司的开源项目及github地址汇总

    国内互联网公司的开源项目及github地址汇总 阿里 阿里的开源项目很多,这也跟@淘宝正明的开源态度密不可分.有很多重量级的项目,例如LVS.Tengine,或者很有实践价值的中间件,例如 MetaQ ...

  7. qq开放平台可以应用到网页游戏的api整理

    创建角色界面api整理 一.需求描述 1.  创建角色名称可以用qq空间昵称代替 2.  如果玩家是在新区玩的话,赠送老玩家支持礼包 3.  可以看到,好友xxx也在玩,而且到了多少等级,如果加为好友 ...

  8. QDUOJ LC的课后辅导 单调递增栈

    LC的课后辅导 发布时间: 2015年9月19日 21:42   时间限制: 1000ms   内存限制: 256M 描述 有一天,LC给我们出了一道题,如图: 这个图形从左到右由若干个 宽为1 高不 ...

  9. JQuery onload、ready 加载顺序

    // ready 这个方法只是在页面所有的DOM加载完毕后就会触发 // 方式1 $(function(){ // do something }); // 方式2 $(document).ready( ...

  10. lightoj 1422【区间DP·分类区间首元素的情况】

    题意: 给你n天分别要穿的衣服种类,可以套着穿, 一旦脱下来就不能再穿,求n天至少要几件. 思路: 区间DP dp[i][j]代表i到j需要至少几件衣服 第i天的衣服在第i天穿上了,dp[i][j]= ...