Метод charat() в java

JavaScript

JS Array
concat()
constructor
copyWithin()
entries()
every()
fill()
filter()
find()
findIndex()
forEach()
from()
includes()
indexOf()
isArray()
join()
keys()
length
lastIndexOf()
map()
pop()
prototype
push()
reduce()
reduceRight()
reverse()
shift()
slice()
some()
sort()
splice()
toString()
unshift()
valueOf()

JS Boolean
constructor
prototype
toString()
valueOf()

JS Classes
constructor()
extends
static
super

JS Date
constructor
getDate()
getDay()
getFullYear()
getHours()
getMilliseconds()
getMinutes()
getMonth()
getSeconds()
getTime()
getTimezoneOffset()
getUTCDate()
getUTCDay()
getUTCFullYear()
getUTCHours()
getUTCMilliseconds()
getUTCMinutes()
getUTCMonth()
getUTCSeconds()
now()
parse()
prototype
setDate()
setFullYear()
setHours()
setMilliseconds()
setMinutes()
setMonth()
setSeconds()
setTime()
setUTCDate()
setUTCFullYear()
setUTCHours()
setUTCMilliseconds()
setUTCMinutes()
setUTCMonth()
setUTCSeconds()
toDateString()
toISOString()
toJSON()
toLocaleDateString()
toLocaleTimeString()
toLocaleString()
toString()
toTimeString()
toUTCString()
UTC()
valueOf()

JS Error
name
message

JS Global
decodeURI()
decodeURIComponent()
encodeURI()
encodeURIComponent()
escape()
eval()
Infinity
isFinite()
isNaN()
NaN
Number()
parseFloat()
parseInt()
String()
undefined
unescape()

JS JSON
parse()
stringify()

JS Math
abs()
acos()
acosh()
asin()
asinh()
atan()
atan2()
atanh()
cbrt()
ceil()
cos()
cosh()
E
exp()
floor()
LN2
LN10
log()
LOG2E
LOG10E
max()
min()
PI
pow()
random()
round()
sin()
sqrt()
SQRT1_2
SQRT2
tan()
tanh()
trunc()

JS Number
constructor
isFinite()
isInteger()
isNaN()
isSafeInteger()
MAX_VALUE
MIN_VALUE
NEGATIVE_INFINITY
NaN
POSITIVE_INFINITY
prototype
toExponential()
toFixed()
toLocaleString()
toPrecision()
toString()
valueOf()

JS OperatorsJS RegExp
constructor
compile()
exec()
g
global
i
ignoreCase
lastIndex
m
multiline
n+
n*
n?
n{X}
n{X,Y}
n{X,}
n$
^n
?=n
?!n
source
test()
toString()

(x|y)
.
\w
\W
\d
\D
\s
\S
\b
\B
\0
\n
\f
\r
\t
\v
\xxx
\xdd
\uxxxx

JS Statements
break
class
continue
debugger
do…while
for
for…in
for…of
function
if…else
return
switch
throw
try…catch
var
while

JS String
charAt()
charCodeAt()
concat()
constructor
endsWith()
fromCharCode()
includes()
indexOf()
lastIndexOf()
length
localeCompare()
match()
prototype
repeat()
replace()
search()
slice()
split()
startsWith()
substr()
substring()
toLocaleLowerCase()
toLocaleUpperCase()
toLowerCase()
toString()
toUpperCase()
trim()
valueOf()

Описание

В примере ниже показаны некоторые способы использования оператора .

// Массивы
var trees = new Array("redwood", "bay", "cedar", "oak", "maple");
0 in trees        // true
3 in trees        // true
6 in trees        // false
"bay" in trees    // false (вы должны указать индекс элемента в массиве, а не значение в этом индексе)
"length" in trees // true (length является свойством Array)

// Уже существующие объекты
"PI" in Math      // true

// Пользовательские объекты
var mycar = {make: "Honda", model: "Accord", year: 1998};
"make" in mycar  // true
"model" in mycar // true

Вы должны указать объект справа от оператора . Например, вы можете указать строку, созданную через конструктор объекта , но вы не можете указать строковый литерал.

var color1 = new String("green");
"length" in color1 // returns true

var color2 = "coral";
// сгенерирует ошибку (color2 is not a String object)
"length" in color2

Использование оператора с неопределенными или с уже удаленными свойствами

Если вы удалили свойство при помощи оператора , то оператор возвратит для этого свойства.

var mycar = {make: "Honda", model: "Accord", year: 1998};
delete mycar.make;
"make" in mycar;  // false

var trees = new Array("redwood", "bay", "cedar", "oak", "maple");
delete trees;
3 in trees; // false

Если вы зададите свойству значение , но не удалите его, то для этого свойства оператор вернет значение .

var mycar = {make: "Honda", model: "Accord", year: 1998};
mycar.make = undefined;
"make" in mycar;  // true
var trees = new Array("redwood", "bay", "cedar", "oak", "maple");
trees = undefined;
3 in trees; // returns true

Наследуемые свойства

Оператор возвратит для свойств, которые унаследованы по цепочке прототипов. (Если вы хотите проверить только не наследованные свойства, используйте .)

"toString" in {}; // true

实用的闭包

闭包很有用,因为它允许将函数与其所操作的某些数据(环境)关联起来。这显然类似于面向对象编程。在面向对象编程中,对象允许我们将某些数据(对象的属性)与一个或者多个方法相关联。

因此,通常你使用只有一个方法的对象的地方,都可以使用闭包。

在 Web 中,你想要这样做的情况特别常见。大部分我们所写的 JavaScript 代码都是基于事件的 — 定义某种行为,然后将其添加到用户触发的事件之上(比如点击或者按键)。我们的代码通常作为回调:为响应事件而执行的函数。

假如,我们想在页面上添加一些可以调整字号的按钮。一种方法是以像素为单位指定 元素的 ,然后通过相对的 单位设置页面中其它元素(例如)的字号:

body {
  font-family: Helvetica, Arial, sans-serif;
  font-size: 12px;
}

h1 {
  font-size: 1.5em;
}

h2 {
  font-size: 1.2em;
}

我们的文本尺寸调整按钮可以修改 元素的 属性,由于我们使用相对单位,页面中的其它元素也会相应地调整。

以下是 JavaScript:

function makeSizer(size) {
  return function() {
    document.body.style.fontSize = size + 'px';
  };
}

var size12 = makeSizer(12);
var size14 = makeSizer(14);
var size16 = makeSizer(16);

, 和 三个函数将分别把  文本调整为 12,14,16 像素。我们可以将它们分别添加到按钮的点击事件上。如下所示:

document.getElementById('size-12').onclick = size12;
document.getElementById('size-14').onclick = size14;
document.getElementById('size-16').onclick = size16;
<a href="#" id="size-12">12</a>
<a href="#" id="size-14">14</a>
<a href="#" id="size-16">16</a> 

函数

学习 JavaScript 最重要的就是要理解对象和函数两个部分。最简单的函数就像下面这个这么简单:

function add(x, y) {
    var total = x + y;
    return total;
}

这个例子包括你需要了解的关于基本函数的所有部分。一个 JavaScript 函数可以包含 0 个或多个已命名的变量。函数体中的表达式数量也没有限制。你可以声明函数自己的局部变量。 语句在返回一个值并结束函数。如果没有使用 语句,或者一个没有值的 语句,JavaScript 会返回 。

已命名的参数更像是一个指示而没有其他作用。如果调用函数时没有提供足够的参数,缺少的参数会被 替代。

add(); // NaN 
// 不能在 undefined 对象上进行加法操作

你还可以传入多于函数本身需要参数个数的参数:

add(2, 3, 4); // 5
 // 将前两个值相加,4 被忽略了

这看上去有点蠢。函数实际上是访问了函数体中一个名为 的内部对象,这个对象就如同一个类似于数组的对象一样,包括了所有被传入的参数。让我们重写一下上面的函数,使它可以接收任意个数的参数:

function add() {
    var sum = 0;
    for (var i = 0, j = arguments.length; i < j; i++) {
        sum += arguments;
    }
    return sum;
}

add(2, 3, 4, 5); // 14

这跟直接写成 也没什么区别。我们还是创建一个求平均数的函数吧:

function avg() {
    var sum = 0;
    for (var i = 0, j = arguments.length; i < j; i++) {
        sum += arguments;
    }
    return sum / arguments.length;
}
avg(2, 3, 4, 5); // 3.5

这个就有用多了,但是却有些冗长。为了使代码变短一些,我们可以使用剩余参数来替换arguments的使用。在这方法中,我们可以传递任意数量的参数到函数中同时尽量减少我们的代码。这个剩余参数操作符在函数中以:…variable 的形式被使用,它将包含在调用函数时使用的未捕获整个参数列表到这个变量中。我们同样也可以将 for 循环替换为 for…of 循环来返回我们变量的值。

function avg(...args) {
  var sum = 0;
  for (let value of args) {
    sum += value;
  }
  return sum / args.length;
}

avg(2, 3, 4, 5); // 3.5

在上面这段代码中,所有被传入该函数的参数都被变量 args 所持有。

需要注意的是,无论“剩余参数操作符”被放置到函数声明的哪里,它都会把除了自己之前的所有参数存储起来。比如函数:function avg(firstValue, …args) 会把传入函数的第一个值存入 firstValue,其他的参数存入 args。这是虽然一个很有用的语言特性,却也会带来新的问题。 函数只接受逗号分开的参数列表 — 但是如果你想要获取一个数组的平均值怎么办?一种方法是将函数按照如下方式重写:

function avgArray(arr) {
    var sum = 0;
    for (var i = 0, j = arr.length; i < j; i++) {
        sum += arr;
    }
    return sum / arr.length;
}
avgArray(); // 3.5

但如果能重用我们已经创建的那个函数不是更好吗?幸运的是 JavaScript 允许你通过任意函数对象的  方法来传递给它一个数组作为参数列表。

avg.apply(null, ); // 3.5

传给 的第二个参数是一个数组,它将被当作 的参数列表使用,至于第一个参数 ,我们将在后面讨论。这也正说明了一个事实——函数也是对象。

通过使用展开语法,你也可以获得同样的效果。

比如说:

JavaScript 允许你创建匿名函数:

var avg = function() {
    var sum = 0;
    for (var i = 0, j = arguments.length; i < j; i++) {
        sum += arguments;
    }
    return sum / arguments.length;
};

这个函数在语义上与 相同。你可以在代码中的任何地方定义这个函数,就像写普通的表达式一样。基于这个特性,有人发明出一些有趣的技巧。与 C 中的块级作用域类似,下面这个例子隐藏了局部变量:

var a = 1;
var b = 2;
(function() {
    var b = 3;
    a += b;
})();

a; // 4
b; // 2

JavaScript 允许以递归方式调用函数。递归在处理树形结构(比如浏览器 DOM)时非常有用。

function countChars(elm) {
    if (elm.nodeType == 3) { //  文本节点
        return elm.nodeValue.length;
    }
    var count = 0;
    for (var i = 0, child; child = elm.childNodes; i++) {
        count += countChars(child);
    }
    return count;
}

这里需要说明一个潜在问题——既然匿名函数没有名字,那该怎么递归调用它呢?在这一点上,JavaScript 允许你命名这个函数表达式。你可以命名立即调用的函数表达式(IIFE——Immediately Invoked Function Expression),如下所示:

var charsInBody = (function counter(elm) {
    if (elm.nodeType == 3) { // 文本节点
        return elm.nodeValue.length;
    }
    var count = 0;
    for (var i = 0, child; child = elm.childNodes; i++) {
        count += counter(child);
    }
    return count;
})(document.body);

如上所提供的函数表达式的名称的作用域仅仅是该函数自身。这允许引擎去做更多的优化,并且这种实现更可读、友好。该名称也显示在调试器和一些堆栈跟踪中,节省了调试时的时间。

需要注意的是 JavaScript 函数是它们本身的对象——就和 JavaScript 其他一切一样——你可以给它们添加属性或者更改它们的属性,这与前面的对象部分一样。

第2条 定義

本規約において使用する用語の意義は、次の各号に定めるとおりとします。

  • 「本サイト」とは、当社が運営する「CHARAT」と称するウェブサイト(https://charat.me/)をいいます。
  • 「本サービス」とは、本サイト上で提供される全てのサービスをいいます。
  • 「ユーザー」とは、会員登録の有無に関わらず、本サイト及び本サービスを利用した者をいいます。
  • 「登録ユーザー」とは、第5条に基づき、本サービスへの利用登録を行ったユーザーのことをいいます。
  • 「クリエイター」とは、第5条に基づき、本サービスへの利用登録を行い、画像メーカーの作成を行ったユーザーのことをいいます。
  • 「画像メーカー」とは、本サイト上で提供している、画像素材を組み合わせて新しい画像データを作成するシステムのことをいいます。
  • 「画像素材」とは、クリエイターが本サービスに提供した素材をいいます。
  • 「作成画像」とは、本サイト及び本サービスを使用して作成された画像データ及び情報をいいます。
  • 「登録メールアドレス」とは、本サービスの提供を受ける目的で、ユーザーが当社に提供したメールアドレスの情報をいいます。
  • 「パスワード」とは、本サービスを利用するに当たって、登録メールアドレスと照合して本人を識別するための文字列をいいます。
  • 「投稿」とは、本サービスを利用したユーザーの作成データを本サービス又は外部サービスへとアップロードする行為をいいます。

Совместимость с браузерами

Update compatibility data on GitHub

Chrome Edge Firefox Internet Explorer Opera Safari Android webview Chrome для Android Firefox для Android Opera для Android Safari on iOS Samsung Internet Node.js
Chrome
Полная поддержка

1
Edge
Полная поддержка

12
Firefox
Полная поддержка

1
IE
Полная поддержка

5.5
Opera
Полная поддержка

4
Safari
Полная поддержка

1
WebView Android
Полная поддержка

1
Chrome Android
Полная поддержка

18
Firefox Android
Полная поддержка

4
Opera Android
Полная поддержка

10.1
Safari iOS
Полная поддержка

1
Samsung Internet Android
Полная поддержка

1.0
nodejs
Полная поддержка

0.1.100

数字

根据语言规范,JavaScript 采用“遵循 IEEE 754 标准的双精度 64 位格式”(»double-precision 64-bit format IEEE 754 values»)表示数字。——在JavaScript(除了)当中,并不存在整数/整型(Integer)。因此在处理如下的场景时候,您一定要小心:

console.log(3 / 2);             // 1.5,not 1
console.log(Math.floor(3 / 2)); // 1

一个看上去是整数的东西,其实都是浮点数。

当然,您也需要小心这种情况:

0.1 + 0.2 = 0.30000000000000004

在具体实现时,整数值通常被视为32位整型变量,在个别实现(如某些浏览器)中也以32位整型变量的形式进行存储,直到它被用于执行某些32位整型不支持的操作,这是为了便于进行位操作。

JavaScript 支持标准的算术运算符,包括加法、减法、取模(或取余)等等。还有一个之前没有提及的内置对象 (数学对象),用以处理更多的高级数学函数和常数:

Math.sin(3.5);
var circumference = 2 * Math.PI * r;

你可以使用内置函数 将字符串转换为整型。该函数的第二个可选参数表示字符串所表示数字的基(进制):

parseInt("123", 10); // 123
parseInt("010", 10); // 10

一些老版本的浏览器会将首字符为“0”的字符串当做八进制数字,2013 年以前的 JavaScript 实现会返回一个意外的结果:

这是因为字符串以数字 0 开头,函数会把这样的字符串视作八进制数字;同理,0x开头的字符串则视为十六进制数字。

如果想把一个二进制数字字符串转换成整数值,只要把第二个参数设置为 2 就可以了:

parseInt("11", 2); // 3

JavaScript 还有一个类似的内置函数 ,用以解析浮点数字符串,与不同的地方是, 只应用于解析十进制数字。

单元运算符 + 也可以把数字字符串转换成数值:

如果给定的字符串不存在数值形式,函数会返回一个特殊的值 (Not a Number 的缩写):

parseInt("hello", 10); // NaN

要小心NaN:如果把 作为参数进行任何数学运算,结果也会是 :

NaN + 5; //NaN

可以使用内置函数 来判断一个变量是否为 :

isNaN(NaN); // true

JavaScript 还有两个特殊值:(正无穷)和 (负无穷):

1 / 0; //  Infinity
-1 / 0; // -Infinity

可以使用内置函数 来判断一个变量是否是一个有穷数, 如果类型为, 或 :

isFinite(1/0); // false
isFinite(Infinity); // false
isFinite(-Infinity); // false
isFinite(NaN); // false

isFinite(0); // true
isFinite(2e64); // true

isFinite("0"); // true
// 如果是纯数值类型的检测,则返回 false:
Number.isFinite("0"); // false

备注: 和 函数会尝试逐个解析字符串中的字符,直到遇上一个无法被解析成数字的字符,然后返回该字符前所有数字字符组成的数字。但是运算符 «+»对字符串的转换方式与之不同, 只要字符串含有无法被解析成数字的字符,该字符串就将被转换成 。可分别使用这两种方法解析“10.2abc”这一字符串,并比较得到的结果,来理解这两种方法的区别。

性能考量

如果不是某些特定任务需要使用闭包,在其它函数中创建函数是不明智的,因为闭包在处理速度和内存消耗方面对脚本性能具有负面影响。

例如,在创建新的对象或者类时,方法通常应该关联于对象的原型,而不是定义到对象的构造器中。原因是这将导致每次构造器被调用时,方法都会被重新赋值一次(也就是说,对于每个对象的创建,方法都会被重新赋值)。

考虑以下示例:

function MyObject(name, message) {
  this.name = name.toString();
  this.message = message.toString();
  this.getName = function() {
    return this.name;
  };

  this.getMessage = function() {
    return this.message;
  };
}

在上面的代码中,我们并没有利用到闭包的好处,因此可以避免使用闭包。修改成如下:

function MyObject(name, message) {
  this.name = name.toString();
  this.message = message.toString();
}
MyObject.prototype = {
  getName: function() {
    return this.name;
  },
  getMessage: function() {
    return this.message;
  }
};

但我们不建议重新定义原型。可改成如下例子:

function MyObject(name, message) {
  this.name = name.toString();
  this.message = message.toString();
}
MyObject.prototype.getName = function() {
  return this.name;
};
MyObject.prototype.getMessage = function() {
  return this.message;
};

在前面的两个示例中,继承的原型可以为所有对象共享,不必在每一次创建对象时定义方法。参见 对象模型的细节 一章可以了解更为详细的信息。

概览

JavaScript 是一种多范式的动态语言,它包含类型、运算符、标准内置( built-in)对象和方法。它的语法来源于 Java 和 C,所以这两种语言的许多语法特性同样适用于 JavaScript。JavaScript 通过原型链而不是类来支持面向对象编程(有关 ES6 类的内容参考这里,有关对象原型参考见此继承与原型链)。JavaScript同样支持函数式编程——因为它们也是对象,函数也可以被保存在变量中,并且像其他对象一样被传递。

先从任何编程语言都不可缺少的组成部分——“类型”开始。JavaScript 程序可以修改值(value),这些值都有各自的类型。JavaScript 中的类型包括:

  • (数字)
  • (字符串)
  • (布尔)
  • (函数)
  • (对象)
  • (ES2015 新增)

…哦,还有看上去有些…奇怪的 (未定义)类型和 (空)类型。此外还有(数组)类型,以及分别用于表示日期和正则表达式的 (日期)和 (正则表达式),这三种类型都是特殊的对象。严格意义上说,Function(函数)也是一种特殊的对象。所以准确来说,JavaScript 中的类型应该包括这些:

  • (数字)
  • (字符串)
  • (布尔)
  • (符号)(ES2015 新增)
  • (对象)

    • (函数)
    • (数组)
    • (日期)
    • (正则表达式)
  • (空)
  • (未定义)

JavaScript 还有一种内置的 (错误)类型。但是,如果我们继续使用上面的分类,事情便容易得多;所以,现在,我们先讨论上面这些类型。

第10条 禁止行為

ユーザーは、本サービス及び関連サービスの利用にあたり、以下の各号に該当する事項を行ってはならないものとします。
禁止行為に違反した場合には、強制退会、利用停止、データの全部もしくは一部の削除、又は公開範囲の変更等の不利益な措置を採ることがあります
(但し、当社はこれらの措置をとる義務を負うものではなく、また、これらの措置を講じた理由を開示する義務を負うものではありません。)。

  • 法令または公序良俗に違反する行為。
  • 犯罪に関連する行為。
  • 当社または第三者の著作権、商標権などの知的財産権、その他法令上または契約上の権利を侵害する行為、又は侵害する恐れのある行為。
  • 当社または第三者の財産、プライバシーもしくは肖像権を侵害する行為、又は侵害する恐れのある行為。
  • 画像データを他のストックサービスに提供する行為
  • 画像データに直接リンクする利用(必ずダウンロードして利用してください)
  • 運営者に成りすます行為。
  • 複数のIDを取得する行為。(但し、許可を得た場合は除く)
  • 通常の範囲を超えて本サービス及び関連サービスのサーバーに負担をかける行為、もしくは、本サービススの運営やネットワーク・システムに支障を与える行為、又はこれらの恐れのある行為。
  • 反社会的勢力に対して直接または間接に利益を供与する行為。
  • 他のユーザーに関する個人情報等を収集または蓄積する行為。
  • 未成年者が法定代理人(親権者)の同意を得ずに、本サービスを利用する行為。
  • 当社およびその他第三者の名誉を傷つけ、業務を妨害する行為。
  • 同様の質問を必要以上に繰り返す等、当社に対し不当な問い合わせまたは要求をする行為。
  • 本サイトに記載されている記事、データを不正に改竄、書き換え、又は消去する行為。
  • 公職選挙法に抵触する行為。
  • アダルト/風俗/性的描写/児童ポルノ/宗教/麻薬/ストライキ/デモ/反発団体/ドラッグ/ナイトサービス/出会い系サービス(婚活/マッチング/出会い系情報/異性紹介事業/)などの利用。
  • 当社の許諾を得ない営利目的使用(販売、オークション、配布、金銭支払やその他の類似行為)。
  • 上記のいずれかに該当する行為を援助または助長する行為。
  • その他、当社が不適当と判断した行為。

Логические

Логическое И. Возвращает последний операнд, если все операнды верны. Если хоть один из операндов неверен, то возвратит первый неверный операнд.

Например, :

Оператор И обычно используется, чтобы избежать ошибок при получении вложенных свойств объекта.

Например, нужно свойство или ложное значение, если такого свойства нет.

Безопасный способ:

var rabbit = petShop && petShop.animals && petShop.animals.rabbit

Этот код корректно выполнится, даже если , в то время как

var rabbit = petShop.animals.rabbit

выдаст ошибку(бросит исключение) об отсутствующем свойстве.

||

Оператор логического ИЛИ возвращает первое верное значение. А если верных значений вообще нет, то последнее неверное.
Это удобно использовать так:

var e = event || window.event // если event не событие, то берем window.event

Логическое НЕ, также удобно для преобразования в .

var str = "something"
// эквивалентные записи
var test = Boolean(str)
var test = !!str

第13条 知的財産権の帰属及び使用許諾

  • 本サービス及び関連サービスに付随する情報、サービス、及びプログラム等に関する知的財産権及びその他の権利は当社らに帰属します。
  • 本サービス及び関連サービスを利用して投稿された画像素材及び作成画像の情報の著作権その他一切の権利は、当該画像素材を創作したクリエイターに帰属します。
  • クリエイターは、画像素材の提供の際に、画像素材及び作成画像について、当社が定める「利用可能範囲」を承諾するものとします。
  • クリエイターは、ユーザーに対し、利用可能範囲において、画像素材及び作成画像を無償で使用許諾するものとし、著作者人格権を行使しないものとします。
  • ユーザーは、作成画像の全ての著作権(著作権法第27条及び第28条の権利を含む)を、素材を提供したクリエイターに無償で譲渡するものとし、本件画像の著作者人格権を行使しないものとします。
  • ユーザーは、作成画像を、当社が定める「利用可能範囲」及びクリエイターが定める利用可能範囲でのみ使用することができます。
  • 当社は、画像素材及び作成画像、並びに、その他、ユーザーの投稿画像及びテキスト等について、本サービス及び関連サービスの円滑な提供、利用促進、広告・宣伝、当社システムの構築、改良、メンテナンスに必要な範囲内で、無償かつ非独占的に使用及び改変等をすることができるものとし、ユーザー及びクリエイターは、これを許諾し、かつ、著作者人格権を行使しないものとします。
  • 当社が前項に定める形で画像素材及び作成画像、並びに、その他、ユーザーの投稿画像及びテキスト等の情報を使用するにあたっては、情報の一部又は氏名表示を省略することができるものとします。

JS Tutorial

JS HOMEJS IntroductionJS Where ToJS OutputJS StatementsJS SyntaxJS CommentsJS VariablesJS OperatorsJS ArithmeticJS AssignmentJS Data TypesJS FunctionsJS ObjectsJS EventsJS StringsJS String MethodsJS NumbersJS Number MethodsJS ArraysJS Array MethodsJS Array SortJS Array IterationJS DatesJS Date FormatsJS Date Get MethodsJS Date Set MethodsJS MathJS RandomJS BooleansJS ComparisonsJS ConditionsJS SwitchJS Loop ForJS Loop WhileJS BreakJS Type ConversionJS BitwiseJS RegExpJS ErrorsJS ScopeJS HoistingJS Strict ModeJS this KeywordJS LetJS ConstJS Arrow FunctionJS DebuggingJS Style GuideJS Best PracticesJS MistakesJS PerformanceJS Reserved WordsJS VersionsJS Version ES5JS Version ES6JS JSON

在循环中创建闭包:一个常见错误

在 ECMAScript 2015 引入 关键字 之前,在循环中有一个常见的闭包创建问题。参考下面的示例:

<p id="help">Helpful notes will appear here</p>
<p>E-mail: <input type="text" id="email" name="email"></p>
<p>Name: <input type="text" id="name" name="name"></p>
<p>Age: <input type="text" id="age" name="age"></p>
function showHelp(help) {
  document.getElementById('help').innerHTML = help;
}

function setupHelp() {
  var helpText = ;

  for (var i = 0; i < helpText.length; i++) {
    var item = helpText;
    document.getElementById(item.id).onfocus = function() {
      showHelp(item.help);
    }
  }
}

setupHelp(); 

数组 中定义了三个有用的提示信息,每一个都关联于对应的文档中的 的 ID。通过循环这三项定义,依次为相应添加了一个  事件处理函数,以便显示帮助信息。

运行这段代码后,您会发现它没有达到想要的效果。无论焦点在哪个上,显示的都是关于年龄的信息。

原因是赋值给 的是闭包。这些闭包是由他们的函数定义和在 作用域中捕获的环境所组成的。这三个闭包在循环中被创建,但他们共享了同一个词法作用域,在这个作用域中存在一个变量item。这是因为变量item使用var进行声明,由于变量提升,所以具有函数作用域。当的回调执行时,的值被决定。由于循环在事件触发之前早已执行完毕,变量对象(被三个闭包所共享)已经指向了的最后一项。

解决这个问题的一种方案是使用更多的闭包:特别是使用前面所述的函数工厂:

function showHelp(help) {
  document.getElementById('help').innerHTML = help;
}

function makeHelpCallback(help) {
  return function() {
    showHelp(help);
  };
}

function setupHelp() {
  var helpText = ;

  for (var i = 0; i < helpText.length; i++) {
    var item = helpText;
    document.getElementById(item.id).onfocus = makeHelpCallback(item.help);
  }
}

setupHelp(); 

这段代码可以如我们所期望的那样工作。所有的回调不再共享同一个环境, 函数为每一个回调创建一个新的词法环境。在这些环境中, 指向 数组中对应的字符串。

另一种方法使用了匿名闭包:

function showHelp(help) {
  document.getElementById('help').innerHTML = help;
}

function setupHelp() {
  var helpText = ;

  for (var i = 0; i < helpText.length; i++) {
    (function() {
       var item = helpText;
       document.getElementById(item.id).onfocus = function() {
         showHelp(item.help);
       }
    })(); // 马上把当前循环项的item与事件回调相关联起来
  }
}

setupHelp();

如果不想使用过多的闭包,你可以用ES2015引入的let关键词:

function showHelp(help) {
  document.getElementById('help').innerHTML = help;
}

function setupHelp() {
  var helpText = ;

  for (var i = 0; i < helpText.length; i++) {
    let item = helpText;
    document.getElementById(item.id).onfocus = function() {
      showHelp(item.help);
    }
  }
}

setupHelp();

这个例子使用而不是,因此每个闭包都绑定了块作用域的变量,这意味着不再需要额外的闭包。

另一个可选方案是使用 来遍历数组并给每一个添加一个监听器,如下所示:

function showHelp(help) {
  document.getElementById('help').innerHTML = help;
}

function setupHelp() {
  var helpText = ;

  helpText.forEach(function(text) {
    document.getElementById(text.id).onfocus = function() {
      showHelp(text.help);
    }
  });
}

setupHelp();

JavaScript

JS Array
concat()
constructor
copyWithin()
entries()
every()
fill()
filter()
find()
findIndex()
forEach()
from()
includes()
indexOf()
isArray()
join()
keys()
length
lastIndexOf()
map()
pop()
prototype
push()
reduce()
reduceRight()
reverse()
shift()
slice()
some()
sort()
splice()
toString()
unshift()
valueOf()

JS Boolean
constructor
prototype
toString()
valueOf()

JS Classes
constructor()
extends
static
super

JS Date
constructor
getDate()
getDay()
getFullYear()
getHours()
getMilliseconds()
getMinutes()
getMonth()
getSeconds()
getTime()
getTimezoneOffset()
getUTCDate()
getUTCDay()
getUTCFullYear()
getUTCHours()
getUTCMilliseconds()
getUTCMinutes()
getUTCMonth()
getUTCSeconds()
now()
parse()
prototype
setDate()
setFullYear()
setHours()
setMilliseconds()
setMinutes()
setMonth()
setSeconds()
setTime()
setUTCDate()
setUTCFullYear()
setUTCHours()
setUTCMilliseconds()
setUTCMinutes()
setUTCMonth()
setUTCSeconds()
toDateString()
toISOString()
toJSON()
toLocaleDateString()
toLocaleTimeString()
toLocaleString()
toString()
toTimeString()
toUTCString()
UTC()
valueOf()

JS Error
name
message

JS Global
decodeURI()
decodeURIComponent()
encodeURI()
encodeURIComponent()
escape()
eval()
Infinity
isFinite()
isNaN()
NaN
Number()
parseFloat()
parseInt()
String()
undefined
unescape()

JS JSON
parse()
stringify()

JS Math
abs()
acos()
acosh()
asin()
asinh()
atan()
atan2()
atanh()
cbrt()
ceil()
cos()
cosh()
E
exp()
floor()
LN2
LN10
log()
LOG2E
LOG10E
max()
min()
PI
pow()
random()
round()
sin()
sqrt()
SQRT1_2
SQRT2
tan()
tanh()
trunc()

JS Number
constructor
isFinite()
isInteger()
isNaN()
isSafeInteger()
MAX_VALUE
MIN_VALUE
NEGATIVE_INFINITY
NaN
POSITIVE_INFINITY
prototype
toExponential()
toFixed()
toLocaleString()
toPrecision()
toString()
valueOf()

JS OperatorsJS RegExp
constructor
compile()
exec()
g
global
i
ignoreCase
lastIndex
m
multiline
n+
n*
n?
n{X}
n{X,Y}
n{X,}
n$
^n
?=n
?!n
source
test()
toString()

(x|y)
.
\w
\W
\d
\D
\s
\S
\b
\B
\0
\n
\f
\r
\t
\v
\xxx
\xdd
\uxxxx

JS Statements
break
class
continue
debugger
do…while
for
for…in
for…of
function
if…else
return
switch
throw
try…catch
var
while

JS String
charAt()
charCodeAt()
concat()
constructor
endsWith()
fromCharCode()
includes()
indexOf()
lastIndexOf()
length
localeCompare()
match()
prototype
repeat()
replace()
search()
slice()
split()
startsWith()
substr()
substring()
toLocaleLowerCase()
toLocaleUpperCase()
toLowerCase()
toString()
toUpperCase()
trim()
valueOf()

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *