312

すべてのプログラマーが知っておくべき JavaScript の「隠れた機能」は何だと思いますか?

以下の質問に対する質の高い回答を見た後、JavaScript について質問する時が来たと思いました。

JavaScript は間違いなく現在最も重要なクライアント側言語ですが (Google に聞いてみてください)、ほとんどの Web 開発者が JavaScript が実際にどれほど強力であるかを認識していないのは驚くべきことです。

4

99 に答える 99

373

関数のパラメーターを定義する必要はありません。関数のarguments配列のようなオブジェクトを使用するだけです。

function sum() {
    var retval = 0;
    for (var i = 0, len = arguments.length; i < len; ++i) {
        retval += arguments[i];
    }
    return retval;
}

sum(1, 2, 3) // returns 6
于 2008-09-15T17:43:14.827 に答える
204

Douglas Crockford の優れた本 JavaScript: The Good Partsのほとんどを引用できます。

ただし、1 つだけ取り上げます。andの代わりに常に===andを使用します。!====!=

alert('' == '0'); //false
alert(0 == ''); // true
alert(0 =='0'); // true

==は推移的ではありません。これを使用===すると、予想どおり、これらのすべてのステートメントに対して false が返されます。

于 2008-09-14T18:44:34.873 に答える
188

関数は JavaScript の第一級市民です。

var passFunAndApply = function (fn,x,y,z) { return fn(x,y,z); };

var sum = function(x,y,z) {
  return x+y+z;
};

alert( passFunAndApply(sum,3,4,5) ); // 12

関数型プログラミング手法を使用して、洗練された JavaScript を作成できます

特に、関数はパラメーターとして渡すことができます。たとえば、Array.filter()はコールバックを受け入れます。

[1, 2, -1].filter(function(element, index, array) { return element > 0 });
// -> [1,2]

特定の関数のスコープ内にのみ存在する「プライベート」関数を宣言することもできます。

function PrintName() {
    var privateFunction = function() { return "Steve"; };
    return privateFunction();
}
于 2008-09-14T03:18:53.773 に答える
162

in演算子を使用して、オブジェクトにキーが存在するかどうかを確認できます。

var x = 1;
var y = 3;
var list = {0:0, 1:0, 2:0};
x in list; //true
y in list; //false
1 in list; //true
y in {3:0, 4:0, 5:0}; //true

オブジェクト リテラルがあまりにも醜い場合は、パラメーターなしの関数のヒントと組み合わせることができます。

function list()
 { var x = {};
   for(var i=0; i < arguments.length; ++i) x[arguments[i]] = 0;
   return x
 }

 5 in list(1,2,3,4,5) //true
于 2008-09-15T17:53:54.580 に答える
153

変数へのデフォルト値の割り当て

代入式で論理 or 演算子||を使用して、デフォルト値を指定できます。

var a = b || c;

a変数は、がの場合 ( 、、、、またはの場合)cのみの値を取得し、そうでない場合は の値を取得します。bnullfalseundefined0empty stringNaNab

これは、引数が指定されていない場合に備えて引数にデフォルト値を与えたい場合に、関数でよく役立ちます。

function example(arg1) {
  arg1 || (arg1 = 'default value');
}

イベント ハンドラでの IE フォールバックの例:

function onClick(e) {
    e || (e = window.event);
}

次の言語機能は長い間使用されており、すべての JavaScript 実装でサポートされていますが、ECMAScript 5th Editionまで仕様の一部ではありませんでした:

debuggerステートメント_

説明: § 12.15 デバッガー ステートメント

このステートメントを使用すると、次のようにしてコードにプログラムでブレークポイントを配置できます。

// ...
debugger;
// ...

デバッガーが存在するかアクティブな場合、その行ですぐに中断します。

それ以外の場合、デバッガーが存在しないかアクティブでない場合、このステートメントは目に見える効果がありません。

複数行の文字列リテラル

説明: § 7.8.4 文字列リテラル

var str = "This is a \
really, really \
long line!";

の隣の文字は行末記号で\ なければならない\ため、注意が必要です。たとえば、の後にスペースがある場合、コードはまったく同じように見えますSyntaxErrorが、 .

于 2008-09-14T06:07:56.987 に答える
145

JavaScript にはブロック スコープがありません(ただし、クロージャがあるので、それを呼びましょうか?)。

var x = 1;
{
   var x = 2;
}
alert(x); // outputs 2
于 2008-09-14T07:02:15.263 に答える
144

[]の代わりにオブジェクトのプロパティにアクセスできます.

これにより、変数に一致するプロパティを検索できます。

obj = {a:"test"};
var propname = "a";
var b = obj[propname];  // "test"

これを使用して、名前が正当な識別子ではないオブジェクト プロパティを取得/設定することもできます。

obj["class"] = "test";  // class is a reserved word; obj.class would be illegal.
obj["two words"] = "test2"; // using dot operator not possible with the space.

一部の人々はこれを知らず、このようにeval()を使用することになりますが、これは本当に悪い考えです:

var propname = "a";
var a = eval("obj." + propname);

これは読みにくく、エラーを見つけるのが難しく (jslint を使用できません)、実行が遅く、XSS エクスプロイトにつながる可能性があります。

于 2008-09-14T04:14:40.893 に答える
144

特定のトピックに関する適切な JavaScript リファレンスをグーグルで検索している場合は、クエリに「mdc」キーワードを含めてください。最初の結果は Mozilla Developer Center から取得されます。オフラインの参考資料や本は持ち歩いていません。私は常に「mdc」キーワード トリックを使用して、探しているものに直接アクセスします。例えば:

Google: javascript array sort mdc
(ほとんどの場合、「javascript」は省略できます)

更新: Mozilla Developer Centerは Mozilla Developer Networkに名前が変更されました。「mdc」キーワード トリックは引き続き機能しますが、すぐに代わりに「mdn」を使用する必要があるかもしれません。

于 2008-10-01T04:55:13.287 に答える
143

多分少し明白な人もいます...

Firebugをインストールし、console.log( "hello")を使用します。ランダムなalert();を使用するよりもはるかに優れています。これは、数年前によく行ったことを覚えています。

于 2008-09-15T22:27:58.730 に答える
120

プライベート メソッド

オブジェクトはプライベート メソッドを持つことができます。

function Person(firstName, lastName) {
    this.firstName = firstName;
    this.lastName = lastName;

    // A private method only visible from within this constructor
    function calcFullName() {
       return firstName + " " + lastName;    
    }

    // A public method available to everyone
    this.sayHello = function () {
        alert(calcFullName());
    }
}

//Usage:
var person1 = new Person("Bob", "Loblaw");
person1.sayHello();

// This fails since the method is not visible from this scope
alert(person1.calcFullName());
于 2008-09-14T03:22:43.000 に答える
99

Crockford の「Javascript: The Good Parts」でも言及されています。

parseInt()危険です。適切な基数を通知せずに文字列を渡すと、予期しない数値が返される場合があります。たとえばparseInt('010')、10 ではなく 8 を返します。base を parseInt に渡すと、正しく機能します。

parseInt('010') // returns 8! (in FF3)
parseInt('010', 10); // returns 10 because we've informed it which base to work with.
于 2008-09-22T23:06:53.280 に答える
97

関数はオブジェクトであるため、プロパティを持つことができます。

fn = 関数(x) {
   // ...
}

fn.foo = 1;

fn.next = 関数(y) {
  ///
}
于 2008-09-14T10:48:32.443 に答える
91

私は自己実行関数を言わなければならないでしょう。

(function() { alert("hi there");})();

Javascriptにはブロックスコープがないため、ローカル変数を定義する場合は、自己実行関数を使用できます。

(function() {
  var myvar = 2;
  alert(myvar);
})();

ここで、myvarisはグローバルスコープに干渉したり汚染したりすることはなく、関数が終了すると消えます。

于 2008-09-24T18:17:04.940 に答える
83

関数によって期待されるパラメーターの数を知る

function add_nums(num1, num2, num3 ){
    return num1 + num2 + num3;
}
add_nums.length // 3 is the number of parameters expected.

関数が受け取るパラメーターの数を知る

function add_many_nums(){
    return arguments.length;
}    
add_many_nums(2,1,122,12,21,89); //returns 6
于 2009-09-02T04:22:59.850 に答える
79

ここにいくつかの興味深いことがあります:

  • 、、をNaN含む何か(でも)との比較NaNは常に偽です。==<>
  • NaNNot a Numberの略ですが、タイプを要求すると、実際には数値が返されます。
  • Array.sortコンパレータ関数を使用でき、クイックソートのようなドライバによって呼び出されます(実装によって異なります)。
  • 正規表現「定数」は、最後に一致したもののように、状態を維持できます。
  • JavaScriptの一部のバージョンでは、正規表現のメンバーにアクセスでき$0ます。$1$2
  • null他のものとは異なります。オブジェクトでも、ブール値でも、数値でも、文字列でも、 。でもありませんundefined。これは「代替」に少し似ていundefinedます。(注typeof null == "object":)
  • 最も外側のコンテキストでthisは、他の方法では名前を付けられない[Global]オブジェクトを生成します。
  • var変数の自動宣言だけに頼るのではなく、で変数を宣言すると、ランタイムはその変数へのアクセスを最適化する本当のチャンスを得ることができます。
  • withコンストラクトはそのような最適化を破壊します
  • 変数名にはUnicode文字を含めることができます。
  • JavaScriptの正規表現は実際には正規表現ではありません。これらはPerlの正規表現に基づいており、評価に非常に長い時間がかかる先読みを使用して式を作成することができます。
  • ブロックにラベルを付けて、のターゲットとして使用できますbreak。ループにラベルを付けて、のターゲットとして使用できますcontinue
  • 配列はスパースではありません。それ以外の場合は空の配列の1000番目の要素を設定すると、それをで埋める必要がありundefinedます。(実装によって異なります)
  • if (new Boolean(false)) {...}{...}ブロック を実行します
  • Javascriptの正規表現エンジンは実装固有です。たとえば、「移植性のない」正規表現を記述できます。

[良いコメントに応えて少し更新しました。コメントをご覧ください]

于 2008-09-22T22:13:25.373 に答える
77

私はパーティーに遅れていることを知っていますが、+演算子の有用性が「何かを数値に変換する」以外に言及されていないとは信じられません. 多分それはそれがどれほどうまく隠されている機能ですか?

// Quick hex to dec conversion:
+"0xFF";              // -> 255

// Get a timestamp for now, the equivalent of `new Date().getTime()`:
+new Date();

// Safer parsing than parseFloat()/parseInt()
parseInt("1,000");    // -> 1, not 1000
+"1,000";             // -> NaN, much better for testing user input
parseInt("010");      // -> 8, because of the octal literal prefix
+"010";               // -> 10, `Number()` doesn't parse octal literals 

// A use case for this would be rare, but still useful in cases
// for shortening something like if (someVar === null) someVar = 0;
+null;                // -> 0;

// Boolean to integer
+true;                // -> 1;
+false;               // -> 0;

// Other useful tidbits:
+"1e10";              // -> 10000000000
+"1e-4";              // -> 0.0001
+"-12";               // -> -12

もちろん、Number()代わりに を使用してこれらすべてを行うこともできますが、+オペレーターの方がはるかにきれいです!

valueOf()プロトタイプのメソッドをオーバーライドして、オブジェクトの数値の戻り値を定義することもできます。そのオブジェクトに対して実行された数値変換はではなく、メソッドNaNの戻り値になります。valueOf()

var rnd = {
    "valueOf": function () { return Math.floor(Math.random()*1000); }
};
+rnd;               // -> 442;
+rnd;               // -> 727;
+rnd;               // -> 718;
于 2010-02-11T10:02:10.953 に答える
74

" JavaScript の拡張メソッド" は、prototype プロパティを介して。

Array.prototype.contains = function(value) {  
    for (var i = 0; i < this.length; i++) {  
        if (this[i] == value) return true;  
    }  
    return false;  
}

containsこれにより、すべてのArrayオブジェクトにメソッドが追加されます。この構文を使用してこのメ​​ソッドを呼び出すことができます

var stringArray = ["foo", "bar", "foobar"];
stringArray.contains("foobar");
于 2008-09-14T04:32:49.633 に答える
60

オブジェクトからプロパティを適切に削除するには、単にundefinedに設定するのではなく、プロパティを削除する必要があります:

var obj = { prop1: 42, prop2: 43 };

obj.prop2 = undefined;

for (var key in obj) {
    ...

プロパティprop2は引き続き反復の一部になります。prop2を完全に取り除きたい場合は、代わりに次のようにする必要があります。

delete obj.prop2;

プロパティを繰り返し処理しているときに、プロパティprop2が表示されなくなります。

于 2008-10-01T01:05:45.957 に答える
57

with.

めったに使用されず、率直に言って、めったに役に立ちません... しかし、限られた状況では、その用途があります。

たとえば、オブジェクト リテラルは、新しいオブジェクトのプロパティをすばやく設定するのに非常に便利です。しかし、既存のオブジェクトのプロパティの半分を変更する必要がある場合はどうすればよいでしょうか?

var user = 
{
   fname: 'Rocket', 
   mname: 'Aloysus',
   lname: 'Squirrel', 
   city: 'Fresno', 
   state: 'California'
};

// ...

with (user)
{
   mname = 'J';
   city = 'Frostbite Falls';
   state = 'Minnesota';
}

Alan Storm は、これはやや危険である可能性があると指摘しています。コンテキストとして使用されるオブジェクトに、割り当てられているプロパティが 1 つも含まれていない場合外側のスコープで解決され、グローバル変数が作成または上書きされる可能性があります。これは、デフォルト値または空の値を持つプロパティが未定義のままになっているオブジェクトを操作するコードを書くことに慣れている場合は特に危険です。

var user = 
{
   fname: "John",
// mname definition skipped - no middle name
   lname: "Doe"
};

with (user)
{
   mname = "Q"; // creates / modifies global variable "mname"
}

withしたがって、このような代入にはステートメントを使用しないことをお勧めします。

参照: JavaScript の「with」ステートメントの正当な使用法はありますか?

于 2008-09-14T04:04:01.357 に答える
51

メソッド (または関数) は、動作するように設計された型ではないオブジェクトで呼び出すことができます。これは、カスタム オブジェクトでネイティブ (高速) メソッドを呼び出すのに最適です。

var listNodes = document.getElementsByTagName('a');
listNodes.sort(function(a, b){ ... });

listNodesではないため、このコードはクラッシュします。Array

Array.prototype.sort.apply(listNodes, [function(a, b){ ... }]);

このコードが機能するlistNodesのは、 によって使用される配列のようなプロパティ (長さ、[] 演算子) が十分に定義されているためsort()です。

于 2008-09-19T21:02:48.733 に答える
43

プロトタイプの継承(Douglas Crockford によって普及) は、Javascript の多くのことについての考え方に完全に革命をもたらします。

Object.beget = (function(Function){
    return function(Object){
        Function.prototype = Object;
        return new Function;
    }
})(function(){});

それはキラーです!ほとんど誰も使っていないのが残念です。

これにより、任意のオブジェクトの新しいインスタンスを「生成」し、それらを拡張しながら、他のプロパティへの (ライブ) プロトタイプ継承リンクを維持できます。例:

var A = {
  foo : 'greetings'
};  
var B = Object.beget(A);

alert(B.foo);     // 'greetings'

// changes and additionns to A are reflected in B
A.foo = 'hello';
alert(B.foo);     // 'hello'

A.bar = 'world';
alert(B.bar);     // 'world'


// ...but not the other way around
B.foo = 'wazzap';
alert(A.foo);     // 'hello'

B.bar = 'universe';
alert(A.bar);     // 'world'
于 2008-10-26T23:10:00.020 に答える
42

これを好みの問題と呼ぶ人もいますが、

aWizz = wizz || "default";
// same as: if (wizz) { aWizz = wizz; } else { aWizz = "default"; }

三項演算子は、Scheme の (cond ...) のように動作するように連鎖できます。

(cond (predicate  (action  ...))
      (predicate2 (action2 ...))
      (#t         default ))

...のように書くことができます

predicate  ? action( ... ) :
predicate2 ? action2( ... ) :
             default;

これは、副作用なしでコードを分岐するため、非常に「機能的」です。したがって、代わりに:

if (predicate) {
  foo = "one";
} else if (predicate2) {
  foo = "two";
} else {
  foo = "default";
}

あなたは書ける:

foo = predicate  ? "one" :
      predicate2 ? "two" :
                   "default";

再帰でもうまく動作します:)

于 2008-09-22T19:00:33.590 に答える
41

数字もオブジェクトです。だからあなたは次のようなクールなことをすることができます:

// convert to base 2
(5).toString(2) // returns "101"

// provide built in iteration
Number.prototype.times = function(funct){
  if(typeof funct === 'function') {
    for(var i = 0;i < Math.floor(this);i++) {
      funct(i);
    }
  }
  return this;
}


(5).times(function(i){
  string += i+" ";
});
// string now equals "0 1 2 3 4 "

var x = 1000;

x.times(function(i){
  document.body.innerHTML += '<p>paragraph #'+i+'</p>';
});
// adds 1000 parapraphs to the document
于 2008-09-20T20:56:04.390 に答える
33

JavaScript のクロージャーはどうですか(C# v2.0+ の匿名メソッドに似ています)。関数または「式」を作成する関数を作成できます。

閉鎖の例:

//Takes a function that filters numbers and calls the function on 
//it to build up a list of numbers that satisfy the function.
function filter(filterFunction, numbers)
{
  var filteredNumbers = [];

  for (var index = 0; index < numbers.length; index++)
  {
    if (filterFunction(numbers[index]) == true)
    {
      filteredNumbers.push(numbers[index]);
    }
  }
  return filteredNumbers;
}

//Creates a function (closure) that will remember the value "lowerBound" 
//that gets passed in and keep a copy of it.
function buildGreaterThanFunction(lowerBound)
{
  return function (numberToCheck) {
    return (numberToCheck > lowerBound) ? true : false;
  };
}

var numbers = [1, 15, 20, 4, 11, 9, 77, 102, 6];

var greaterThan7 = buildGreaterThanFunction(7);
var greaterThan15 = buildGreaterThanFunction(15);

numbers = filter(greaterThan7, numbers);
alert('Greater Than 7: ' + numbers);

numbers = filter(greaterThan15, numbers);
alert('Greater Than 15: ' + numbers);
于 2008-09-14T07:50:26.100 に答える
32

クラスを拡張 (継承)し、 spoon16 で言及したプロトタイプ チェーンを使用してプロパティ/メソッドをオーバーライドすることもできます。

次の例では、クラス Pet を作成し、いくつかのプロパティを定義します。Object から継承された .toString() メソッドもオーバーライドします。

この後、 Pet を拡張し、 .toString() メソッドをオーバーライドして動作を変更する Dog クラスを作成します(ポリモーフィズム)。さらに、子クラスにいくつかのプロパティを追加します。

この後、継承チェーンをチェックして、Dog がまだ Dog 型、Pet 型、Object 型であることを示します。

// Defines a Pet class constructor 
function Pet(name) 
{
    this.getName = function() { return name; };
    this.setName = function(newName) { name = newName; };
}

// Adds the Pet.toString() function for all Pet objects
Pet.prototype.toString = function() 
{
    return 'This pets name is: ' + this.getName();
};
// end of class Pet

// Define Dog class constructor (Dog : Pet) 
function Dog(name, breed) 
{
    // think Dog : base(name) 
    Pet.call(this, name);
    this.getBreed = function() { return breed; };
}

// this makes Dog.prototype inherit from Pet.prototype
Dog.prototype = new Pet();

// Currently Pet.prototype.constructor
// points to Pet. We want our Dog instances'
// constructor to point to Dog.
Dog.prototype.constructor = Dog;

// Now we override Pet.prototype.toString
Dog.prototype.toString = function() 
{
    return 'This dogs name is: ' + this.getName() + 
        ', and its breed is: ' + this.getBreed();
};
// end of class Dog

var parrotty = new Pet('Parrotty the Parrot');
var dog = new Dog('Buddy', 'Great Dane');
// test the new toString()
alert(parrotty);
alert(dog);

// Testing instanceof (similar to the `is` operator)
alert('Is dog instance of Dog? ' + (dog instanceof Dog)); //true
alert('Is dog instance of Pet? ' + (dog instanceof Pet)); //true
alert('Is dog instance of Object? ' + (dog instanceof Object)); //true

この質問に対する両方の回答は、Ray Djajadinata による優れた MSDN 記事から変更されたコードです。

于 2008-09-14T08:16:20.110 に答える
31

頭のてっぺんから...

関数

arguments.calleeは、「arguments」変数をホストする関数を参照するため、無名関数を再帰的に使用できます。

var recurse = function() {
  if (condition) arguments.callee(); //calls recurse() again
}

これは、次のようなことをしたい場合に便利です。

//do something to all array items within an array recursively
myArray.forEach(function(item) {
  if (item instanceof Array) item.forEach(arguments.callee)
  else {/*...*/}
})

オブジェクト

オブジェクトメンバーの興味深い点:名前として任意の文字列を使用できます。

//these are normal object members
var obj = {
  a : function() {},
  b : function() {}
}
//but we can do this too
var rules = {
  ".layout .widget" : function(element) {},
  "a[href]" : function(element) {}
}
/* 
this snippet searches the page for elements that
match the CSS selectors and applies the respective function to them:
*/
for (var item in rules) {
  var elements = document.querySelectorAll(rules[item]);
  for (var e, i = 0; e = elements[i++];) rules[item](e);
}

文字列

String.splitは、正規表現をパラメーターとして受け取ることができます。

"hello world   with  spaces".split(/\s+/g);
//returns an array: ["hello", "world", "with", "spaces"]

String.replaceは、検索パラメーターとして正規表現を取り、置換パラメーターとして関数を受け取ることができます。

var i = 1;
"foo bar baz ".replace(/\s+/g, function() {return i++});
//returns "foo1bar2baz3"
于 2008-09-22T19:37:49.927 に答える
29

ほとんどの場合、スイッチの代わりにオブジェクトを使用できます。

function getInnerText(o){
    return o === null? null : {
        string: o,
        array: o.map(getInnerText).join(""),
        object:getInnerText(o["childNodes"])
    }[typeis(o)];
}

更新:事前に評価されたケースが非効率的であることが心配な場合(プログラムの設計の早い段階で効率が心配なのはなぜですか??)、次のようなことができます。

function getInnerText(o){
    return o === null? null : {
        string: function() { return o;},
        array: function() { return o.map(getInnerText).join(""); },
        object: function () { return getInnerText(o["childNodes"]; ) }
    }[typeis(o)]();
}

これは、スイッチやオブジェクトよりも入力(または読み取り)するのが面倒ですが、以下のコメントセクションで詳しく説明するように、スイッチの代わりにオブジェクトを使用する利点は維持されます。このスタイルはまた、十分に成長したら、これを適切な「クラス」にスピンアウトすることをより簡単にします。

update2:ES.nextの構文拡張が提案されているため、これは次のようになります。

let getInnerText = o -> ({
    string: o -> o,
    array: o -> o.map(getInnerText).join(""),
    object: o -> getInnerText(o["childNodes"])
}[ typeis o ] || (->null) )(o);
于 2009-01-29T01:16:05.893 に答える
25

オブジェクトのプロパティを反復処理するときは、必ずhasOwnPropertyメソッドを使用してください。

for (p in anObject) {
    if (anObject.hasOwnProperty(p)) {
        //Do stuff with p here
    }
}

これは、 anObjectの直接のプロパティにのみアクセスし、プロトタイプ チェーンの下にあるプロパティを使用しないようにするために行われます。

于 2008-12-07T12:50:03.333 に答える
23

パブリック インターフェイスを持つプライベート変数

これは、自己呼び出し関数の定義を使用した巧妙な小さなトリックを使用します。返されたオブジェクト内のすべてが公開インターフェイスで利用可能ですが、それ以外はすべて非公開です。

var test = function () {
    //private members
    var x = 1;
    var y = function () {
        return x * 2;
    };
    //public interface
    return {
        setx : function (newx) {
            x = newx;
        },
        gety : function () {
            return y();
        }
    }
}();

assert(undefined == test.x);
assert(undefined == test.y);
assert(2 == test.gety());
test.setx(5);
assert(10 == test.gety());
于 2008-09-19T18:41:28.903 に答える
21

JavaScript のタイムスタンプ:

// Usual Way
var d = new Date();
timestamp = d.getTime();

// Shorter Way
timestamp = (new Date()).getTime();

// Shortest Way
timestamp = +new Date();
于 2008-09-16T22:54:28.033 に答える
20

左側の [] を使用してローカル変数を割り当てることができます。不必要な配列を作成せずに関数から複数の値を返したい場合に便利です。

function fn(){
    var cat = "meow";
    var dog = "woof";
    return [cat,dog];
};

var [cat,dog] = fn();  // Handy!

alert(cat);
alert(dog);

それはコア JS の一部ですが、どういうわけか私は今年まで気づきませんでした。

于 2009-05-08T18:34:14.173 に答える
19

Javascript のすべてのオブジェクトはハッシュテーブルとして実装されるため、それらのプロパティにはインデクサーを介してアクセスでき、その逆も同様です。また、 for/in演算子を使用してすべてのプロパティを列挙できます。

var x = {a: 0};
x["a"]; //returns 0

x["b"] = 1;
x.b; //returns 1

for (p in x) document.write(p+";"); //writes "a;b;"
于 2008-09-15T17:47:02.367 に答える
17

このスレッドには、プロトタイプを介して Array オブジェクトを拡張する方法を示すいくつかの回答があります。for (i in a)これはステートメントを壊すため、悪い考えです。

for (i in a) では、コードのどこにも使用していなくても大丈夫ですか? 実行しているコードが独自のコードだけである場合に限りますが、これはブラウザー内ではあまりありません。人々がこのように Array オブジェクトを拡張し始めると、スタック オーバーフローが一連の不可解な JavaScript バグであふれ始めるのではないかと心配しています。

役立つ詳細については、こちらをご覧ください。

于 2008-09-23T01:06:46.890 に答える
17

配列から要素を削除したい場合は、次のようにdelete演算子を使用できます。

var numbers = [1,2,3,4,5];
delete numbers[3];
//numbers is now [1,2,3,undefined,5]

ご覧のとおり、要素は削除されましたが、要素が未定義の値に置き換えられたため、配列に穴が残っています。

したがって、この問題を回避するには、 deleteを使用する代わりに、splice配列メソッドを使用します...そのように:

var numbers = [1,2,3,4,5];
numbers.splice(3,1);
//numbers is now [1,2,3,5]

spliceの最初の引数は配列 [index] の序数で、2 番目は削除する要素の数です。

于 2008-12-07T13:01:48.067 に答える
16

関数では、関数自体を返すことができます。

function showSomething(a){
   alert(a);
   return arguments.callee;
}

// Alerts: 'a', 'b', 'c'
showSomething('a')('b')('c');

// Or what about this:
(function (a){
   alert(a);
   return arguments.callee;
}​)('a')('b')('c');​​​​

いつ役立つかはわかりませんが、かなり奇妙で楽しいものです。

var count = function(counter){
   alert(counter);
   if(counter < 10){
      return arguments.callee(counter+1);
   }
   return arguments.callee;
};

count(5)(9); // Will alert 5, 6, 7, 8, 9, 10 and 9, 10

実際、Node.js のFAB フレームワークはこの機能を実装しているようです。たとえば、このトピックを参照してください。

于 2010-04-25T20:11:58.443 に答える
15

JavaScript が Date() で動作する方法は、私を興奮させます!

function isLeapYear(year) {
    return (new Date(year, 1, 29, 0, 0).getMonth() != 2);
}

これはまさに「隠れた機能」です。

編集:「?」を削除しました 丁寧さのコメントで提案されている状態。以前: ... new Date(year, 1, 29, 0, 0).getMonth() != 2 ? true : false ... 詳細はコメントをご覧ください。

于 2008-09-15T17:30:41.533 に答える
13

ここにいくつかのショートカットがあります:

var a = []; // equivalent to new Array()
var o = {}; // equivalent to new Object()
于 2008-09-23T19:13:06.233 に答える
13

私のお気に入りのトリックはapply、オブジェクトのメソッドへのコールバックを実行し、正しい "this" 変数を維持するために を使用することです。

function MakeCallback(obj, method) {
    return function() {
        method.apply(obj, arguments);
    };
}

var SomeClass = function() { 
     this.a = 1;
};
SomeClass.prototype.addXToA = function(x) {
     this.a = this.a + x;
};

var myObj = new SomeClass();

brokenCallback = myObj.addXToA;
brokenCallback(1); // Won't work, wrong "this" variable
alert(myObj.a); // 1


var myCallback = MakeCallback(myObj, myObj.addXToA);
myCallback(1);  // Works as expected because of apply
alert(myObj.a); // 2
于 2009-09-22T19:58:49.643 に答える
13

閉鎖の禅

他の人は閉鎖について言及しています。しかし、クロージャーについて知っていて、クロージャーを使用してコードを書いているにもかかわらず、クロージャーが実際に何であるかについてまだ間違った認識を持っている人がどれだけ多いかは驚くべきことです。一部の人々は、ファーストクラスの関数をクロージャと混同しています。しかし、それを一種の静的変数と見なす人もいます。

私にとって、クロージャーは一種の「プライベート」グローバル変数です。つまり、一部の関数はグローバルとして認識しますが、他の関数は認識できない一種の変数です。今、私はこれが基本的なメカニズムの説明で速くて緩いことを知っていますが、それがどのように感じられ、どのように動作するかです. 説明する:

// Say you want three functions to share a single variable:

// Use a self-calling function to create scope:
(function(){

    var counter = 0; // this is the variable we want to share;

    // Declare global functions using function expressions:
    increment = function(){
        return ++counter;
    }
    decrement = function(){
        return --counter;
    }
    value = function(){
        return counter;
    }
})()

現在、3 つの関数incrementがあり、実際のグローバル変数ではなく変数decrementvalue共有しています。これがクロージャーの本質です。countercounter

increment();
increment();
decrement();
alert(value()); // will output 1

上記は、クロージャーの実際の有用な使用方法ではありません。実際、このように使用することはアンチパターンだと思います。しかし、クロージャーの性質を理解するのに役立ちます。たとえば、次のようなことをしようとすると、ほとんどの人が捕まってしまいます。

for (var i=1;i<=10;i++) {
    document.getElementById('span'+i).onclick = function () {
        alert('this is span number '+i);
    }
}
// ALL spans will generate alert: this span is span number 10

それは、彼らが閉鎖の性質を理解していないからです。彼らはi、実際には関数が単一の変数を共有しているのに、関数に値を渡していると考えていますi。前に言ったように、特別な種類のグローバル変数です。

これを回避するには、 * クロージャをデタッチする必要があります:

function makeClickHandler (j) {
    return function () {alert('this is span number '+j)};
}

for (var i=1;i<=10;i++) {
    document.getElementById('span'+i).onclick = makeClickHandler(i);
}
// this works because i is passed by reference 
// (or value in this case, since it is a number)
// instead of being captured by a closure

*注: ここでの正しい用語はわかりません。

于 2010-01-12T07:31:29.863 に答える
12

eval()グローバル変数名をアセンブルするために使用する必要はありません。

つまり、(何らかの理由で) という名前のグローバルが複数ある場合、 でspec_grapes, spec_applesそれらにアクセスする必要はありませんeval("spec_" + var)

すべてのグローバルは のメンバーなwindow[]ので、実行できますwindow["spec_" + var]

于 2009-03-28T07:21:48.400 に答える
11

Firebug に console.log() を使用する際に、Internet Explorer でのテスト中に迷惑なエラーが発生しないようにします。

function log(message) {
    (console || { log: function(s) { alert(s); }).log(message);
}
于 2008-09-30T10:43:20.477 に答える
11

JavaScript は単純なオブジェクト リテラルを使用します。

var x = { intValue: 5, strValue: "foo" };

これにより、本格的なオブジェクトが構築されます。

JavaScript はプロトタイプベースのオブジェクト指向を使用し、実行時に型を拡張する機能を提供します。

String.prototype.doubleLength = function() {
    return this.length * 2;
}

alert("foo".doubleLength());

オブジェクトは、自身に含まれていない属性へのすべてのアクセスを、その「プロトタイプ」である別のオブジェクトに委譲します。これは継承を実装するために使用できますが、実際にはより強力です (より面倒ではありますが):

/* "Constructor" */
function foo() {
    this.intValue = 5;
}

/* Create the prototype that includes everything
 * common to all objects created be the foo function.
 */
foo.prototype = {
    method: function() {
        alert(this.intValue);
    }
}

var f = new foo();
f.method();
于 2008-09-15T18:25:27.080 に答える
10

私のお気に入りの1つは、コンストラクター型のチェックです。

function getObjectType( obj ) {  
    return obj.constructor.name;  
}  

window.onload = function() {  
    alert( getObjectType( "Hello World!" ) );  
    function Cat() {  
        // some code here...  
    }  
    alert( getObjectType( new Cat() ) );  
}

したがって、typeofキーワードでよく使用される、疲れた古い[Object object]の代わりに、コンストラクターに基づいて実際のオブジェクトタイプを実際に取得できます。

もう1つは、関数を「オーバーロード」する方法として変数引数を使用することです。式を使用して引数の数を検出し、オーバーロードされた出力を返すだけです。

function myFunction( message, iteration ) {  
    if ( arguments.length == 2 ) {  
        for ( i = 0; i < iteration; i++ ) {  
            alert( message );  
        }  
    } else {  
        alert( message );  
    }  
}  

window.onload = function() {  
    myFunction( "Hello World!", 3 );  
}

最後に、代入演算子の省略形を言います。私はこれをjQueryフレームワークのソースから学びました...古い方法:

var a, b, c, d;
b = a;
c = b;
d = c;

新しい(省略形)方法:

var a, b, c, d;
d = c = b = a;

楽しい :)

于 2008-09-16T02:39:06.877 に答える
10

JavaScriptで最速のループはwhile(i--)ループです。すべてのブラウザで。したがって、ループの要素が処理される順序がそれほど重要でない場合は、while(i--)形式を使用する必要があります。

var names = new Array(1024), i = names.length;
while(i--)
  names[i] = "John" + i;

また、今後for()ループを使用する必要がある場合は、常に.lengthプロパティをキャッシュすることを忘れないでください。

var birds = new Array(1024); 
for(var i = 0, j = birds.length; i < j; i++)
  birds[i].fly();

大きな文字列を結合するには、配列を使用します(より高速です)。

var largeString = new Array(1024), i = largeString.length;
while(i--) {
  // It's faster than for() loop with largeString.push(), obviously :)
  largeString[i] = i.toString(16);
}

largeString = largeString.join("");

largeString += "something"ループ内よりもはるかに高速です。

于 2009-06-22T00:28:32.673 に答える
10

ステートメントをコンマで区切ると、括弧の間でほとんど何でもできます。

var z = ( x = "can you do crazy things with parenthesis", ( y = x.split(" "), [ y[1], y[0] ].concat( y.slice(2) ) ).join(" ") )

alert(x + "\n" + y + "\n" + z)

出力:

can you do crazy things with parenthesis
can,you,do,crazy,things,with,parenthesis
you can do crazy things with parenthesis
于 2008-09-21T05:40:50.633 に答える
9

真実と虚偽の値の概念。次のようなことをする必要はありません

if(someVar === 未定義 || someVar === null) ...

単に行う:

if(!someVar)。

すべての値には、対応するブール表現があります。

于 2008-09-21T21:57:23.827 に答える
9

window.nameの値は、ページが変更されても保持され、同じドメイン内にある場合は親ウィンドウで読み取ることができ (iframe 内にある場合はdocument.getElementById("your frame's ID").contentWindow.name、それにアクセスするために使用します)、使用可能なメモリによってのみ制限されます。

于 2008-11-19T16:44:38.013 に答える
9

新しい「オブジェクト」を作成する場合、括弧はオプションです。

function Animal () {

}

var animal = new Animal();
var animal = new Animal;

同じこと。

于 2009-04-08T19:09:53.937 に答える
9

関数文と関数式の扱いは異なります。

function blarg(a) {return a;} // statement
bleep = function(b) {return b;} //expression

すべての関数ステートメントは、コードが実行される前に解析されます。JavaScript ファイルの下部にある関数は、最初のステートメントで使用できます。一方、周囲withのステートメントなど、特定の動的コンテキストを利用することはできませwithん。関数が解析されたときに実行されていません。

関数式は、見つかった場所でインラインで実行されます。それまでは利用できませんが、動的なコンテキストを利用できます。

于 2008-10-22T02:08:05.473 に答える
8

整数プロパティと長さプロパティを持つ「any* オブジェクトを適切な配列に変換して、push、pop、splice、map、filter、reduce などのすべての配列メソッドを与えることができます。

Array.prototype.slice.call({"0":"foo", "1":"bar", 2:"baz", "length":3 }) 

// ["foo", "bar", "baz"] を返す

これは、jQuery オブジェクト、html コレクション、および他のフレームの Array オブジェクトで機能します (配列型全体に対する 1 つの可能な解決策として)。長さのプロパティがあれば、それを配列に変えることができ、それは問題ではありません。引数オブジェクトを超えて、長さプロパティを持つ非配列オブジェクトがたくさんあります。

于 2009-01-29T05:12:21.860 に答える
8

JSON 文字列をやみくもeval()に逆シリアル化すると、問題が発生する可能性があります。

  1. 安全ではありません。文字列には悪意のある関数呼び出しが含まれている可能性があります!
  2. JSON 文字列を括弧で囲まないと、プロパティ名がラベルと間違えられ、予期しない動作や構文エラーが発生する可能性があります。

    eval("{ \"foo\": 42 }"); // syntax error: invalid label
    eval("({ \"foo\": 42 })"); // OK
    
于 2008-10-01T16:20:13.593 に答える
8

Javascript には、関数内に静的変数があります。

function someFunction(){
  var Static = arguments.callee;
  Static.someStaticVariable = (Static.someStaticVariable || 0) + 1;
  alert(Static.someStaticVariable);
}
someFunction() //Alerts 1
someFunction() //Alerts 2
someFunction() //Alerts 3

また、オブジェクト内に静的変数があります。

function Obj(){
  this.Static = arguments.callee;
}
a = new Obj();
a.Static.name = "a";
b = new Obj();
alert(b.Static.name); //Alerts b
于 2008-09-14T19:26:28.410 に答える
8

== 演算子には、非常に特殊なプロパティがあり、この不穏な等式が作成されます (はい、Perl などの他の動的言語ではこの動作が予想されることはわかっていますが、JavaScript は通常、比較を賢くしようとはしません)。

>>> 1 == true
true
>>> 0 == false
true
>>> 2 == true
false
于 2008-09-27T13:45:14.730 に答える
8

すべての関数は、実際には組み込みのFunction型のインスタンスであり、関数定義を含む文字列を受け取るコンストラクターを持っているため、たとえば文字列を連結することにより、実行時に関数を実際に定義できます。

//e.g., createAddFunction("a","b") returns function(a,b) { return a+b; }
function createAddFunction(paramName1, paramName2)
 { return new Function( paramName1, paramName2
                       ,"return "+ paramName1 +" + "+ paramName2 +";");
 }

また、ユーザー定義関数の場合、Function.toString()は関数定義をリテラル文字列として返します。

于 2008-09-15T17:39:23.447 に答える
8

let.

varのブロック スコープの欠如に対応するのはletJavaScript 1.7 で導入された です

  • let ステートメントは、ブロック外の同名の変数の値に影響を与えることなく、ブロックのスコープ内の変数に値を関連付ける方法を提供します。
  • let 式を使用すると、単一の式のみにスコープが設定された変数を確立できます。
  • let 定義は、スコープが定義されているブロックに制限されている変数を定義します。この構文は、var で使用される構文とよく似ています。
  • let を使用して、for ループのコンテキスト内にのみ存在する変数を設定することもできます。
  function varTest() {
        var x = 31;
    if (true) {
      var x = 71;  // same variable!
      alert(x);  // 71
    }
    alert(x);  // 71
  }

  function letTest() {
    let x = 31;
    if (true) {
      let x = 71;  // different variable
      alert(x);  // 71
    }
    alert(x);  // 31
  }

2008 年現在、JavaScript 1.7 は FireFox 2.0+ および Safari 3.x でサポートされています。

于 2008-10-01T00:37:37.227 に答える
8

メソッドがあるかどうかに関係なく、オブジェクトのメソッドを任意のオブジェクトで実行できます。もちろん、常に機能するとは限りません (メソッドがオブジェクトに存在しないものがあると想定している場合) が、非常に便利です。例えば:

function(){
    arguments.push('foo') // This errors, arguments is not a proper array and has no push method
    Array.prototype.push.apply(arguments, ['foo']) // Works!
}
于 2008-09-22T12:54:23.627 に答える
8

JavaScript コードをサンドボックス化し、文字列を評価して JavaScript コードにするあらゆる方法を無効にしようとしている場合は、すべての明白な eval/document.write/new Function/setTimeout/setInterval/innerHTML およびその他の DOM 操作をブロックしないことに注意してください。足りる。

オブジェクト o を指定o.constructor.constructor("alert('hi')")()すると、"hi" という単語を含む警告ダイアログが表示されます。

次のように書き換えることができます

var Z="constructor";
Z[Z][Z]("alert('hi')")();

楽しいもの。

于 2009-06-21T21:43:33.973 に答える
7

Microsoftから JavaScript への贈り物: AJAX

AJAXCall('http://www.abcd.com/')

function AJAXCall(url) {
 var client = new XMLHttpRequest();
 client.onreadystatechange = handlerFunc;
 client.open("GET", url);
 client.send();
}

function handlerFunc() {
 if(this.readyState == 4 && this.status == 200) {
 if(this.responseXML != null)
   document.write(this.responseXML)
 }
}
于 2009-01-05T20:59:30.617 に答える
7

Function.toString() (暗黙的):

function x() {
    alert("Hello World");
}
eval ("x = " + (x + "").replace(
    'Hello World',
    'STACK OVERFLOW BWAHAHA"); x("'));
x();
于 2008-09-16T23:19:37.800 に答える
7

これは Javascript ではなく jQuery の隠れた機能ですが、「jQuery の隠れた機能」という質問は決してないので...

:somethingjQuery で独自のセレクターを定義できます。

$.extend($.expr[':'], {
  foo: function(node, index, args, stack) {
    // decide if selectors matches node, return true or false
  }
});

:fooなどの を使用した選択の場合、セレクターの処理済み部分に一致するすべてのノードに対して$('div.block:foo("bar,baz") span')関数が呼び出されます。foo引数の意味:

  • node現在のノードを保持します
  • indexノード セット内のノードのインデックスです。
  • argsセレクターに引数または複数の名前がある場合に役立つ配列です。
    • args[0]セレクターテキスト全体です (例: :foo("bar, baz"))
    • args[1]セレクター名 (例: foo)
    • args[2]引数をラップするために使用される引用文字 ( "for:foo("bar, baz")など)、または引用符がない場合は空の文字列 ( :foo(bar, baz))、引数がない場合は未定義
    • args[3]引用符を含む引数 (例: "bar, baz")、または引数がない場合は undefined です。
  • stackノードセットです(その時点で一致するすべてのノードを保持する配列)

trueセレクターが一致する場合は関数が返され、falseそうでない場合は返されます。

たとえば、次のコードは、全文正規表現検索に基づいてノードを選択できるようにします。

$.extend($.expr[':'], {
  matches: function(node, index, args, stack) {
    if (!args.re) { // args is a good place for caching
      var re = args[3];
      if (args[2]) { // get rid of quotes
        re = re.slice(1,-1);
      }
      var separator = re[0];
      var pos = re.lastIndexOf(separator);
      var modifiers = re.substr(pos+1);
      var code = re.substr(1, pos-1);
      args.re = new RegExp(code, modifiers);
    }
    return $(node).text().match(args.re);
  }
});

// find the answers on this page which contain /**/-style comments
$('.answer .post-text code:matches(!/\\*[\\s\\S]*\\*/!)');

.filter()のコールバック バージョンでも同様の効果が得られますが、カスタム セレクターははるかに柔軟で、通常は読みやすくなっています。

于 2010-05-27T12:32:30.063 に答える
6

ジェネレーターとイテレーター(Firefox 2+とSafariでのみ機能します)。

function fib() {
  var i = 0, j = 1;
  while (true) {
    yield i;
    var t = i;
    i = j;
    j += t;
  }
}

var g = fib();
for (var i = 0; i < 10; i++) {
  document.write(g.next() + "<br>\n");
}

yield キーワードを含む関数はジェネレーターです。これを呼び出すと、その正式なパラメーターは実際の引数にバインドされますが、その本体は実際には評価されません。代わりに、generator-iteratorが返されます。ジェネレーター-イテレーターの next()メソッドを呼び出すたびに、反復アルゴリズムを介して別のパスが実行されます。各ステップの値は、yieldキーワードで指定された値です。yieldアルゴリズムの各反復間の境界を示す、returnのジェネレーター-イテレーターバージョンと考えてください。を呼び出すたびnext()に、ジェネレータコードは。に続くステートメントから再開しますyield

通常の使用法では、イテレータオブジェクトは「非表示」です。それらを明示的に操作する必要はありませんが、代わりにJavaScriptfor...infor each...inステートメントを使用して、オブジェクトのキーや値を自然にループします。

var objectWithIterator = getObjectSomehow();

for (var i in objectWithIterator)
{
  document.write(objectWithIterator[i] + "<br>\n");
}
于 2008-10-01T00:51:57.940 に答える
6

undefined未定義です。だからあなたはこれを行うことができます:

if (obj.field === undefined) /* ... */
于 2008-09-15T16:25:36.137 に答える
6

訪問:

この JavaScript コードを Web ブラウザのアドレス バーに貼り付けます。

JavaScriptディスコショーをお楽しみください:-p

于 2008-09-22T16:09:12.767 に答える
5

「隠れた」機能はすべて Mozilla wiki にあります: http://developer.mozilla.org/en/JavaScript

コア JavaScript 1.5 リファレンスJavaScript 1.6新機能、JavaScript 1.7の新機能、JavaScript 1.8の新機能があります。実際に機能し、間違っていない例については、これらすべてに目を通してください。

于 2008-09-22T15:41:52.973 に答える
5

これは非常に隠されており、たまにしか役に立たない ;-)

プロトタイプ チェーンを使用して、元のオブジェクトを変更せずに、別のオブジェクトに委任するオブジェクトを作成できます。

var o1 = { foo: 1, bar: 'abc' };
function f() {}
f.prototype = o1;
o2 = new f();
assert( o2.foo === 1 );
assert( o2.bar === 'abc' );
o2.foo = 2;
o2.baz = true;
assert( o2.foo === 2 );
// o1 is unchanged by assignment to o2
assert( o1.foo === 1 );
assert( o2.baz );

これは、o1 の「単純な」値のみを対象としています。配列または別のオブジェクトを変更すると、プロトタイプは元のオブジェクトを「保護」しなくなります。クラス定義/プロトタイプに {} または [] がある場合は常に注意してください。

于 2008-09-16T19:09:50.677 に答える
4

jQuery と JavaScript:

変数名には、奇数の文字を含めることができます。$ 文字を使用して、jQuery オブジェクトを含む変数を識別します。

var $links = $("a");

$links.hide();

オブジェクトをチェーンする jQuery のパターンは非常に優れていますが、このパターンを適用すると少し混乱する可能性があります。幸いなことに、JavaScript では次のように改行できます。

$("a")
.hide()
.fadeIn()
.fadeOut()
.hide();

一般的な JavaScript:

自己実行関数を使用してスコープをエミュレートすると便利です。

function test()
{
    // scope of test()

    (function()
    {
        // scope inside the scope of test()
    }());

    // scope of test()
}
于 2008-10-08T12:30:25.690 に答える
4

それがオブジェクト指向でもあることに気付いていない人がいかに多いかは驚くべきことです。

于 2008-09-14T06:42:19.010 に答える
4

大規模なループは、while-condition および逆方向 (つまり、ループの順序が問題にならない場合) の方が高速です。私のコードの約 50% では、通常そうではありません。

すなわち

var i, len = 100000;

for (var i = 0; i < len; i++) {
  // do stuff
}

より遅い:

i = len;
while (i--) {
  // do stuff
}
于 2009-01-20T11:22:22.033 に答える
3

存在チェック。こんなものをよく見かけます

var a = [0, 1, 2];

// code that might clear the array.

if (a.length > 0) {
 // do something
}

代わりに、たとえば次のようにします。

var a = [0, 1, 2];

// code that might clear the array.

if (a.length) { // if length is not equal to 0, this will be true
 // do something
}

実行できる存在チェックにはさまざまな種類がありますが、これは要点を説明するための単純な例にすぎません。

デフォルト値の使用方法の例を次に示します。

function (someArgument) {
      someArgument || (someArgument = "This is the deault value");
}

それは私の2セントです。他にもナゲットがありますが、今のところはそれだけです。

于 2009-03-14T03:59:25.463 に答える
3

シンタックス シュガー: インライン for ループ クロージャ

var i;

for (i = 0; i < 10; i++) (function ()
{
    // do something with i
}());

Douglas Crockford のコード規則のほとんどすべてを破っていますが、私はそれを見てとてもいいと思います。


別:

var i;

for (i = 0; i < 10; i++) (function (j)
{
    // do something with j
}(i));
于 2009-03-09T09:40:32.873 に答える
3

配列または null で使用されるJavaScripttypeof演算子は常にobject値を返しますが、これは場合によってはプログラマーが期待するものではない可能性があります。

これらのアイテムに対しても適切な値を返す関数を次に示します。配列認識は、Douglas Crockford の著書「JavaScript: The Good Parts」からコピーされました。

function typeOf (value) {
    var type = typeof value;
    if (type === 'object') {
        if (value === null) {
             type = 'null';
        } else if (typeof value.length === 'number' && 
            typeof value.splice === 'function' && 
            !value.propertyIsEnumerable('length')) {
            type = 'array';
        }
    }
    return type;
}
于 2009-07-15T14:00:10.690 に答える
3

Jooseは、CLOS のような感じのクラスベースの OO が必要な場合に最適なオブジェクト システムです。

// Create a class called Point
Class("Point", {
    has: {
        x: {
            is:   "rw",
            init: 0
        },
        y: {
            is:   "rw",
            init: 0
        }
    },
    methods: {
        clear: function () {
            this.setX(0);
            this.setY(0);
        }
    }
})

// Use the class
var point = new Point();
point.setX(10)
point.setY(20);
point.clear();
于 2008-09-22T15:37:02.813 に答える
2

浮動小数点数を整数に変換するには、次の暗号化されたハックのいずれかを使用できます (使用しないでください)。

  1. 3.14 >> 0(経由2.9999999999999999 >> .5? )
  2. 3.14 | 0( JavaScriptで浮動小数点を整数に変換する最良の方法は何ですか?経由)
  3. 3.14 & -1
  4. 3.14 ^ 0
  5. ~~3.14

基本的に、最終値を変更しない二項演算 (恒等関数) を float に適用すると、float が整数に変換されます。

于 2008-10-07T15:52:38.747 に答える
2

Marius がすでに指摘したように、関数内に public static 変数を含めることができます。

通常、これらを使用して、一度だけ実行される関数を作成したり、複雑な計算結果をキャッシュしたりします。

私の古い「シングルトン」アプローチの例を次に示します。

var singleton = function(){ 

  if (typeof arguments.callee.__instance__ == 'undefined') { 

    arguments.callee.__instance__ = new function(){

      //this creates a random private variable.
      //this could be a complicated calculation or DOM traversing that takes long
      //or anything that needs to be "cached"
      var rnd = Math.random();

      //just a "public" function showing the private variable value
      this.smth = function(){ alert('it is an object with a rand num=' + rnd); };

   };

  }

  return arguments.callee.__instance__;

};


var a = new singleton;
var b = new singleton;

a.smth(); 
b.smth();

ご覧のとおり、どちらの場合も、コンストラクターは 1 回だけ実行されます。

たとえば、2004 年に、ページ全体を覆う灰色の背景を持つモーダル ダイアログ ボックス ( Lightboxのようなもの) を作成する必要があったときに、このアプローチを使用しました。Internet Explorer 5.5 および 6 は、「ウィンドウ」の性質により、<select> または <iframe> 要素のスタック コンテキストが最も高くなります。そのため、ページに select 要素が含まれている場合、それらをカバーする唯一の方法は、iframe を作成してページの「上」に配置することでした。そのため、スクリプト全体は非常に複雑で、少し時間がかかりました (filter: 式を使用して、カバーする iframe の不透明度を設定しました)。「shim」スクリプトには「.show()」メソッドが 1 つしかなく、これにより shim が 1 回だけ作成され、静的変数にキャッシュされました :)

于 2008-09-15T17:27:08.623 に答える
2

これは Firefox (SpiderMonkey) でのみ動作するようです。関数内:

  • arguments[-2]引数の数を与える ( と同じarguments.length)
  • arguments[-3]呼び出された関数を与える ( と同じarguments.callee)
于 2009-03-10T02:33:30.613 に答える
2

うーん、トピック全体を読んだわけではありませんが、私にとっては非常に興味深いものですが、少し寄付させてください。

// forget the debug alerts
var alertToFirebugConsole = function() {
    if ( window.console && window.console.log ) {
        window.alert = console.log;
    }
}
于 2009-11-05T19:01:50.220 に答える
2

JavaScript は、そのすべてのオブジェクトを公開するのに非常に優れていると考えられているため、そのウィンドウ オブジェクト自体に関係なく.

したがって、パラメーターとして文字列を受け入れる JQuery/YUI div ポップアップでブラウザー アラートをオーバーライドしたい場合は、次のスニペットを使用するだけで実行できます。


function divPopup(str)
{
    //code to show the divPopup
}
window.alert = divPopup;

この変更により、alert() へのすべての呼び出しは、ブラウザー固有のアラートではなく、適切な新しい div ベースのポップアップを表示します。

于 2010-01-11T13:24:57.247 に答える
2

たぶんあまり知られていないものの1つ:

arguments.callee.caller + Function#toString()

function called(){
    alert("Go called by:\n"+arguments.callee.caller.toString());
}

function iDoTheCall(){
    called();
}

iDoTheCall();

-- Deprecatedのソース コードを出力しますiDoTheCallが、警告が唯一のオプションである場合に役立つことがあります....

于 2009-05-14T21:02:33.437 に答える
2

ほとんど知られていない JavaScript 構文もあります。

var a;
a=alert(5),7;
alert(a);    // alerts undefined
a=7,alert(5);
alert(a);    // alerts 7

a=(3,6);
alert(a);    // alerts 6

詳細については、こちらをご覧ください。

于 2009-01-25T00:03:01.980 に答える
2

JavaScript の多様性 - デフォルト機能のオーバーライド


window.alertjQuery UI のダイアログ ウィジェットで関数 をオーバーライドするコードを次に示します。これを jQuery プラグインとして実行しました。それについては私のブログで読むことができます。パーソナライズされたアラート メッセージ用の jQuery プラグインである altAlert

jQuery.altAlert = function (options)  
{  
    var defaults = {  
        title: "Alert",  
        buttons: {  
            "Ok": function()  
            {  
                jQuery(this).dialog("close");  
            }  
        }  
    };  

    jQuery.extend(defaults, options);  

    delete defaults.autoOpen;  

    window.alert = function ()  
    {  
        jQuery("<div />", {
            html: arguments[0].replace(/\n/, "<br />")
        }).dialog(defaults);  
    };  
};
于 2010-02-20T20:44:00.137 に答える
1

JavaScriptオブジェクトをHTML要素属性としてバインドできます。

<div id="jsTest">Klick Me</div>
<script type="text/javascript">
    var someVariable = 'I was klicked';
    var divElement = document.getElementById('jsTest');
    // binding function/object or anything as attribute
    divElement.controller = function() { someVariable += '*'; alert('You can change instance data:\n' + someVariable ); };
    var onclickFunct = new Function( 'this.controller();' ); // Works in Firefox and Internet Explorer.
    divElement.onclick = onclickFunct;
</script>
于 2009-06-05T13:13:03.503 に答える
1

単純な自己完結型関数の戻り値のキャッシュ:

function isRunningLocally(){
    var runningLocally = ....; // Might be an expensive check, check whatever needs to be checked.

    return (isRunningLocally = function(){
        return runningLocally;
    })();
},

高価な部分は最初の呼び出しでのみ実行され、その後、関数はこの値を返すだけです。もちろん、これは常に同じものを返す関数にのみ役立ちます。

于 2010-03-19T16:47:28.223 に答える
1

私の最初の提出は、プロパティ再定義機能のめったに使用されないアプリケーションほど隠された機能ではありません。オブジェクトのメソッドを再定義できるため、メソッド呼び出しの結果をキャッシュできます。これは、計算にコストがかかり、遅延評価が必要な場合に役立ちます。これにより、最も単純な形式のメモ化が可能になります。

function Circle(r) {
    this.setR(r);
}

Circle.prototype = {
  recalcArea: function() {
        this.area=function() {
            area = this.r * this.r * Math.PI;
            this.area = function() {return area;}
            return area;
        }
    },
  setR: function (r) {
      this.r = r;
      this.invalidateR();
    },
  invalidateR: function() {
        this.recalcArea();
    }
}

結果をメソッドにキャッシュするコードをリファクタリングすると、次のようになります。

Object.prototype.cacheResult = function(name, _get) {
  this[name] = function() {
    var result = _get.apply(this, arguments);
    this[name] = function() {
      return result;
    }
    return result;
  };
};

function Circle(r) {
    this.setR(r);
}

Circle.prototype = {
  recalcArea: function() {
        this.cacheResult('area', function() { return this.r * this.r * Math.PI; });
    },
  setR: function (r) {
      this.r = r;
      this.invalidateR();
    },
  invalidateR: function() {
        this.recalcArea();
    }
}

メモ化された関数が必要な場合は、代わりにそれを使用できます。プロパティの再定義は含まれていません。

Object.prototype.memoize = function(name, implementation) {
    this[name] = function() {
        var argStr = Array.toString.call(arguments);
        if (typeof(this[name].memo[argStr]) == 'undefined') {
            this[name].memo[argStr] = implementation.apply(this, arguments);
        }
        return this[name].memo[argStr];
    }
};

これは標準の配列からStringへの変換に依存しており、多くの場合正しく機能しないことに注意してください。それを修正することは、読者の練習問題として残されています。

私の2番目の提出物はゲッターとセッターです。彼らがまだ言及されていないことに私は驚いています。公式標準は事実上の標準(definePropertyとdefine [GS] etter)とは異なり、Internet Explorerは公式標準をほとんどサポートしていないため、一般的には役に立ちません。たぶんそれが彼らが言及されなかった理由です。ゲッターと結果キャッシュをかなりうまく組み合わせることができることに注意してください。

Object.prototype.defineCacher = function(name, _get) {
    this.__defineGetter__(name, function() {
        var result = _get.call(this);
        this.__defineGetter__(name, function() { return result; });
        return result;
    })
};

function Circle(r) {
    this.r = r;
}

Circle.prototype = {
  invalidateR: function() {
        this.recalcArea();
    },
  recalcArea: function() {
        this.defineCacher('area', function() {return this.r * this.r * Math.PI; });
    },
  get r() { return this._r; }
  set r(r) { this._r = r; this.invalidateR(); }
}

var unit = new Circle(1);
unit.area;

ゲッター、セッター、および結果のキャッシュを効率的に組み合わせるのは、無効化を防ぐか、セットでの自動無効化なしで実行する必要があるため、少し面倒です。これは、次の例のようになります。1つのプロパティを変更すると、他の複数のプロパティが無効になる場合は、ほとんどの場合問題になります(これらの例に「diameter」プロパティがあると想像してください)。

Object.prototype.defineRecalcer = function(name, _get) {
  var recalcFunc;
  this[recalcFunc='recalc'+name.toCapitalized()] = function() {
    this.defineCacher(name, _get);
  };
  this[recalcFunc]();
  this.__defineSetter__(name, function(value) {
      _set.call(this, value);
      this.__defineGetter__(name, function() {return value; });
  });
};

function Circle(r) {
    this.defineRecalcer('area',
             function() {return this.r * this.r * Math.PI;},
             function(area) {this._r = Math.sqrt(area / Math.PI);},
    );
    this.r = r;
}

Circle.prototype = {
  invalidateR: function() {
        this.recalcArea();
    },
  get r() { return this._r; }
  set r(r) { this._r = r; this.invalidateR(); }
}
于 2009-07-24T08:57:34.973 に答える
1

閉鎖:

function f() { 
    var a; 
    function closureGet(){ return a; }
    function closureSet(val){ a=val;}
    return [closureGet,closureSet];
}

[closureGet,closureSet]=f(); 
closureSet(5);
alert(closureGet()); // gives 5

closureSet(15);
alert(closureGet()); // gives 15

ここでのクロージャのことは、いわゆるデストラクチャリング代入([c,d] = [1,3]と同等c=1; d=3;)ではなく、aclosureGetとclosureSetのオカレンスが同じ変数を参照しているという事実です。closureSetがa新しい値を割り当てた後でも!

于 2010-05-27T10:17:11.313 に答える
1

合体演算子は非常にクールで、特にそれを連鎖させると、クリーンで簡潔なコードになりますa || b || c || "default"; 。落とし穴は、nullではなくboolで評価することで機能するため、falseと評価される値が有効である場合、多くの場合、時代は見過ごされます。心配しないでください。これらの場合は、古き良き三項演算子に戻ってください。

静的変数の代わりにグローバル変数をあきらめて使用しているコードをよく目にするので、次のようにします(例では、一般的なシングルトンファクトリと呼ぶことができます)。

var getInstance = function(objectName) {
  if ( !getInstance.instances ) {
    getInstance.instances = {};
  }

  if ( !getInstance.instances[objectName] ) {
    getInstance.instances[objectName] = new window[objectName];
  }

  return getInstance.instances[objectName];
};

また、new window[objectName];オブジェクトを名前で一般的にインスタンス化するための鍵であることに注意してください。私はちょうど2ヶ月前にそれを理解しました。

同じ精神で、DOMを操作するとき、追加する機能を最初に初期化するときに、機能するパラメーターやフラグをDOMノードに埋め込むことがよくあります。誰かがしゃがんだ場合の例を追加します。

驚いたことに、最初のページの誰も言及していませんhasOwnProperty。これは残念です。in反復に使用する場合は、反復されるコンテナーでメソッドを使用して、使用hasOwnPropertyされているメンバー名が期待どおりであることを確認することをお勧めします。

var x = [1,2,3];
for ( i in x ) {
    if ( !x.hasOwnProperty(i) )  { continue; }
    console.log(i, x[i]);
}

詳細については、こちらをお読みください。

最後に、withほとんどの場合、これは悪い考えです。

于 2009-06-22T07:58:58.430 に答える
1

関数はメソッドを持つことができます。

私はこのパターンのAJAXフォーム送信を使用します。

var fn = (function() {
        var ready = true;
        function fnX() {
            ready = false;
            // AJAX return function
            function Success() {
                ready = true;
            }
            Success();
            return "this is a test";
        }

        fnX.IsReady = function() {
            return ready;
        }
        return fnX;
    })();

    if (fn.IsReady()) {
        fn();
    }
于 2009-11-10T23:32:59.430 に答える
1

これが「これ」についての簡単な考え方です。関数内の「これ」は、通常、演算子newで作成された関数の将来のオブジェクトインスタンスを参照します。したがって、明らかに、内部関数の「これ」は、外部関数のインスタンスを参照することはありません。

上記は問題を回避する必要があります。しかし、「これ」でできることはもっと複雑です。


例1:


     function DriveIn()
     {
          this.car = 'Honda';
          alert(this.food);  //'food' is the attribute of a future object 
                             //and DriveIn does not define it.
     }

     var A = {food:'chili', q:DriveIn};  //create object A whose q attribute 
                                         //is the function DriveIn;

     alert(A.car); //displays 'undefined' 
     A.q();        //displays 'chili' but also defines this.car.
     alert(A.car); //displays 'Honda' 


このルール:

関数がオブジェクトの属性として呼び出されるときはいつでも、関数の内部(ただし内部関数の外部)での「this」の出現はオブジェクトを参照します。

演算子newを使用する場合でも、「このルール」が適用されることを明確にする必要があります。舞台裏では、newは、オブジェクトのコンストラクター属性を介して「this」をオブジェクトにアタッチします。


例2:


      function Insect ()
      {
           this.bug = "bee";
           this.bugFood = function()
           {
               alert("nectar");
           }
       }

      var B = new Insect();
      alert(B.constructor); //displays "Insect"; By "The Rule of This" any
                            //ocurrence of 'this' inside Insect now refers 
                            //to B.    

これをさらに明確にするために、演算子newを使用せずにInsectインスタンスを作成できます。

例3:

   
    var C = {constructor:Insect};  //Assign the constructor attribute of C, 
                                   //the value Insect.
    C.constructor();               //Call Insect through the attribute. 
                                   //C is now an Insect instance as though it 
                                   //were created with operator new. [*]
    alert(C.bug);                  //Displays "bee." 
    C.bugFood();                   //Displays "nectar." 

[*]私が識別できる唯一の実際の違いは、例3では、「コンストラクター」が列挙可能な属性であるということです。演算子newを使用すると、「コンストラクター」が属性になりますが、列挙できません。for-in操作"for(var name in object)"が属性の名前を返す場合、属性は列挙可能です。

于 2009-08-23T08:28:39.643 に答える
1

コールバックを書くとき、次のようなコードがたくさんあります:

callback: function(){
  stuff(arg1,arg2);
}

以下の関数を使用して、多少きれいにすることができます。

callback: _(stuff, arg1, arg2) 

これは、javascript の Function オブジェクトのあまり知られていない関数 apply を使用します。

また、関数名として使用できる別の文字 _ も示しています。

function _(){
        var func;
        var args = new Array();
        for(var i = 0; i < arguments.length; i++){
                if( i == 0){
                        func = arguments[i];
                } else {
                        args.push(arguments[i]);
                }
        }
        return function(){
                return func.apply(func, args);
        }
}
于 2010-06-24T14:31:58.317 に答える
1

Function.applyを使用して、関数が動作するオブジェクトを指定します。

クラスがあるとします

function myClass(){
 this.fun = function(){
   do something;
 };
}

後で行う場合:

var a = new myClass();
var b = new myClass();

myClass.fun.apply(b); //this will be like b.fun();

呼び出しパラメーターの配列を 2 番目の引数として指定することもできます

これを見てください: https://developer.mozilla.org/en/Core_JavaScript_1.5_Reference/Global_Objects/Function/apply

于 2009-07-21T23:05:36.493 に答える
1

コンストラクターの変更Arrayや の定義など、ランタイム環境の大部分をオンザフライで再定義できますundefined。すべきことではありませんが、強力な機能になる可能性があります。

これのやや危険性の低い形式は、既存のオブジェクトへのヘルパー メソッドの追加です。たとえば、IE6 で arrays の indexOf を「ネイティブに」サポートするようにすることができます。

于 2008-09-22T22:03:11.763 に答える
0

関数 l(f,n){n&&l(f,n-1,f(n));}

l( 関数 ( ループ ){ アラート ( ループ ); }, 5 );

アラート 5、4、3、2、1

于 2008-10-04T19:38:00.400 に答える
-5

まあ、それは大した機能ではありませんが、非常に便利です:

選択可能な書式設定されたアラートを表示します。

alert(prompt('',something.innerHTML ));
于 2009-09-08T15:28:27.323 に答える