JavaScriptの動特性(eval,call,appyとbindによって表現される)
13337 ワード
JavaScriptの動特性(eval,call,appyとbindによって表現される)
JavaScriptはオブジェクト指向、関数式、動的プログラミング言語に基づいています.今はブラウザとサーバー端末で使えるようになりました.
ここでは対象に向けたものではなく、関数式プログラミングについても言及せず、単にダイナミック性を議論します.ダイナミックとは何ですか?
言語の動態とは、プログラムが実行される時にその構造を変えることができるということです.
通俗的に言って、実行していません.このコードがどんな状況になるかは分かりません.ある変数と声明の時は違っています.ある関数の作用範囲が変わったかもしれません.ダイナミックな特性があれば、このコードの実行プロセスは経験によってしか判断できない場合が多いです.
JavaScriptのダイナミック性は以下のいくつかの関数でまとめられると思います. eval appyとcall bind 1.eval関数
eval関数のダイナミック性は、シナリオ実行時に動的に何かを変えることができる.
上記の例はこの点を表しています.
次はeval関数のもう一つの比較的お父さんの問題について説明します.
eval関数のデフォルトの変更は、現在のスコープの変数値です.
よくあるブラウザJSエンジンとカーネルのリストを添付します.
会社
ブラウザ
JSエンジン
レンダリングエンジン
Microsoft
IE 6-8
JScrtp
Trident
IE 9-11
Chakra
Trident
Edge
Chakra
Edge
Mozia
Firefox
Jager Monkey
Gecko
Google
Chrome
V 8
Blink
Apple
Safari
Webkit
スクエアFish Extreme
Opera
Opera 12.16+
Blink
カーキマン
これらはJSエンジンとカーネルの一部です.他のバージョンは自分で検索してください.
2.appyとcall
2.1 appyとcallの基本的な使い方
アプリとコールの使用はよく似ています.クリを挙げます.
この例を見てください.
最後に、applyの最も一般的な方法であり、パラメータを他の関数に無留保で伝達する.
2.2 appyとcallの実用的な使い方
2.2.1配列の最大値、最小値を取得する
もしJSで配列の最大値の最小値を求める方法を使えば、遍歴を思い出すかもしれません.規則的かどうか聞いて、半分割でアルゴリズムを探します.でもここの使い方は微妙です.
2.2.2元の配列に項目を追加する
二つの配列を統合するにはどうすればいいですか?
2.2.3認証配列タイプ
ある日、BOSSはABの同僚のコードを再構成して効率を上げるようにします.重複した部分については必ず抽象的に出てきます.うん、両方とも検出配列の動作があります.自然です.
2.2.4類配列用配列の方法
クラスの配列は何ですか?興味のあるものは前の文章を訳して、クラスの配列やarray-likeを探してください.ここで一番多く使われているのは、jQueryと推定されます.jQueryのソースコードの使い方を抽象してみてください.あるいはLookに行ってもいいです.中国語の注釈版のjQueryのソースコードがあります.下のコードは運行できません.理解を深めるだけです.
3.bind関数
3.1 jQueryの中のbind方法
bindというと、ここの本編のテーマですが、bindとは何ですか?古いバージョンのjQueryを使っている方が多いと、よくこのように書くかもしれません.
3.2原生JavaScriptにおけるbind方法
もう一つは、オリジナルのbind関数であり、ECMAScript 5には
次は終わりです.高エネルギーです.ある日ぶらぶらしている時に面白い訳文を見ました.最初に読んでみましたが、よく分からないところがあって、他のことをするために急いでいました.先に置いておきました.後ろに暇があったら、この訳文を見つけました.あるいはコードです.灰色の常に鋭いです.役割も書き方もいたるところにJSの動態特性を徹底的に表しています. bindとcallおよびappyは、関数実行のコンテキストを動的に変えることができ、JavaScriptの動的特性 をよく表していると言えます. JavaScriptの動特性は上のeval()、call/appy、bind()これらの だけではありません.これらのものを使ってみても、JSという言語がよりよく理解できます.コードが優雅になり、コードが多重される確率も高くなります.
5.引用参考:
MDN公式文書——Function.prototype.bind()張小俊128——Javascript中のBind,CallとAppley
JavaScriptはオブジェクト指向、関数式、動的プログラミング言語に基づいています.今はブラウザとサーバー端末で使えるようになりました.
ここでは対象に向けたものではなく、関数式プログラミングについても言及せず、単にダイナミック性を議論します.ダイナミックとは何ですか?
言語の動態とは、プログラムが実行される時にその構造を変えることができるということです.
通俗的に言って、実行していません.このコードがどんな状況になるかは分かりません.ある変数と声明の時は違っています.ある関数の作用範囲が変わったかもしれません.ダイナミックな特性があれば、このコードの実行プロセスは経験によってしか判断できない場合が多いです.
JavaScriptのダイナミック性は以下のいくつかの関数でまとめられると思います.
eval(alert(" !")); // --> !
alert(window.eval === eval); // -->true
alert(eval in window); // -->false
ここでは使い方が分かります.evalはwindowオブジェクトの下にマウントされた関数で、evalは
です.eval関数のダイナミック性は、シナリオ実行時に動的に何かを変えることができる.
上記の例はこの点を表しています.
eval()
はプログラム実行時に何かを動的に変えることができます.次はeval関数のもう一つの比較的お父さんの問題について説明します.
eval
は栗を挙げます.var i = 100;
function myFunc() {
var i = "text";
window.eval('i = "hello"');
alert(i); // text,IE6-8 hello
}
myFunc();
alert(i); // hello,IE6-8 100
どうしてですか?原因は JS eval
です.ここで私たちが指定したwindow.eval
は、iの値をハロー文字列に変更することを意図しています.しかし、別のブラウザJS解析カーネルのエヴァ関数に対する作用領域の設定は異なり、IE 6-8はJScript
を使用しているので、evalはiをmyFunnc関数のvar i = "text"
iと読んで、myFun関数の中のtextをハローに変更した後にハローが表示されます.現代のブラウザは、window.eval
が変化したのはグローバルi=100
の値だと考えている.window.eval
をeval
に変更したら?var i = 100;
function myFunc() {
var i = "text";
eval('i = "hello"');
}
myFunc();
alert(i); // -->100
おめでとうございますここのeval
は、window
作用領域を指定していないので、ブラウザが一括して100を出力する.eval関数のデフォルトの変更は、現在のスコープの変数値です.
よくあるブラウザJSエンジンとカーネルのリストを添付します.
会社
ブラウザ
JSエンジン
レンダリングエンジン
Microsoft
IE 6-8
JScrtp
Trident
IE 9-11
Chakra
Trident
Edge
Chakra
Edge
Mozia
Firefox
Jager Monkey
Gecko
Chrome
V 8
Blink
Apple
Safari
Webkit
スクエアFish Extreme
Opera
Opera 12.16+
Blink
カーキマン
これらはJSエンジンとカーネルの一部です.他のバージョンは自分で検索してください.
2.appyとcall
2.1 appyとcallの基本的な使い方
アプリとコールの使用はよく似ています.クリを挙げます.
var name = "JaminQian",
obj = {
name: "ManfredHu"
};
function myFunc() {
alert(this.name);
}
myFunc(); // -->JaminQian
myFunc.call(obj); // -->ManfredHu
ここの役割はthisの方向を変えることです.thisは実は違う環境での指し示しが違っていることを知っています.場合によってはwindow
グローバルオブジェクトであり、あるオブジェクトであり、appyとcallを通じて、関数の中のthisの指向を任意に変えることができます.この例を見てください.
function Animal(){
this.name = "Animal";
this.args = arguments; //
this.showName = function(){
console.log(this.name);
};
this.getArgsNum = function(){
console.log(this.args);
}
}
function Cat(num1,num2,num3){
Animal.apply(this,arguments); // Animal
this.name = "Cat";
}
function PersianCat(){ //
Cat.apply(this,arguments); // Cat
this.name = "PersianCat";
}
var animal = new Animal();
var cat = new Cat(1,2,3);
var PersianCat = new PersianCat([1,"2",[3]]);
// this.name
animal.showName(); //-->Animal
animal.showName.call(cat); //-->Cat
animal.showName.call(PersianCat); //-->PersianCat
//
animal.getArgsNum(); //-->[]
cat.getArgsNum(); //-->[1,2,3]
PersianCat.getArgsNum();//-->[[1,"2",[3]]]
ここの生物の鎖はAnimal->Cat->PersianCat( )
で、生物学のはよく分かりませんか?その後は、call
を用いて、構造関数で父類の属性を継承していますが、自分の特殊な属性name
もあり、オブジェクト指向の継承と多状態を模倣して実現しました.最後に、applyの最も一般的な方法であり、パラメータを他の関数に無留保で伝達する.
2.2 appyとcallの実用的な使い方
2.2.1配列の最大値、最小値を取得する
もしJSで配列の最大値の最小値を求める方法を使えば、遍歴を思い出すかもしれません.規則的かどうか聞いて、半分割でアルゴリズムを探します.でもここの使い方は微妙です.
var numbers = [5,"30",-1,6, // ,numbers[1] "30"
{
a:20, // , valueOf
valueOf:function() {
return 40
}
},
];
//
var max = Math.max.apply(Math,numbers),
min = Math.min.call(Math,-10,2,6,10);
console.log(max); //-->40
console.log(min); //-->-10
JSは非常に怠惰であることを知っています.文字列が必要なときだけ、Object.prototype.toString()
メソッドを呼び出して文字列に変換します.数値が必要なときは、Object.prototype.valueOf()
メソッドを呼び出して数字に変換します.ここではvalueOf
を用いて文字列"30"
を数値30に変換する.もちろん全部が数字ならもっと簡単ですが、ここでは詳しく説明しません.2.2.2元の配列に項目を追加する
二つの配列を統合するにはどうすればいいですか?
Array.prototype.concat()
方法を思いつくことができます.var arr1 = [22, 'foo', {
age: "21"
}, -2046];
var arr2 = ["do", 55, 100];
var arr3 = arr1.concat(arr2);
console.log(arr3); //-->[22, "foo", Object, -2046, "do", 55, 100]
OK合併が完了したら、アール2を使ってpush
の各項目をアール1に回す方法を考えるかもしれません.優雅な配列の結合方法は?犬の血の脚本はきっと書きます.var arr1 = [22, 'foo', {
age: "21"
}, -2046];
var arr2 = ["do", 55, 100];
Array.prototype.push.apply(arr1,arr2); // apply,
console.log(arr1); //-->[22, "foo", Object, -2046, "do", 55, 100]
四両千斤の足を引っ張るものがありますか?2.2.3認証配列タイプ
ある日、BOSSはABの同僚のコードを再構成して効率を上げるようにします.重複した部分については必ず抽象的に出てきます.うん、両方とも検出配列の動作があります.自然です.
isArray
関数を実装して判断します.それから太ももをたたきますと、また原生の判断のisArray
の方法があるのではありませんか?はい、探してみましたが、お父さんの問題を発見しました.IE 9++にはArray.isArray()
方法があります.OKです.互換性があればいいじゃないですか?function isArray(value) {
if(typeof Array.isArray === "function") { //ES5 ,IE9+
return Array.isArray(value);
} else {
return Object.prototype.toString.call(value) === "[object Array]";
}
}
論理は非常に単純で粗暴であり、以下の互換性のある方法をよく見てください.原理はObject.prototype.toString()
を呼び出したときに"[object Array]"
文字列を返します.もちろん、ここでは、タイプ検出は、基本タイプ検出用typeof
が十分であり、number
、string
、boolean
、undefined
、typof
のいずれもinstanceof
で検出することができる.ユーザー定義の参照タイプについては、Object.prototype.hasOwnProperty
およびconstructor
またはiframe
属性でも十分である.エラーが発生しやすいところは、検出配列と検出関数の2つの場所、特にtypeof foo === "function"
のところで、元の検出方法は無効になりますので、特に注意してください.検出配列は上記のように、比較的に公認されている方法である.検出関数はslice
(fooが関数であると仮定する)で検出される.2.2.4類配列用配列の方法
クラスの配列は何ですか?興味のあるものは前の文章を訳して、クラスの配列やarray-likeを探してください.ここで一番多く使われているのは、jQueryと推定されます.jQueryのソースコードの使い方を抽象してみてください.あるいはLookに行ってもいいです.中国語の注釈版のjQueryのソースコードがあります.下のコードは運行できません.理解を深めるだけです.
var arr = [];
var slice = arr.slice; // slice
toArray: function() {
return slice.call( this ); //
},
クラス配列を配列に変換する方法は、2つにすぎない.1つはconcat
、1つはon
.3.bind関数
3.1 jQueryの中のbind方法
bindというと、ここの本編のテーマですが、bindとは何ですか?古いバージョンのjQueryを使っている方が多いと、よくこのように書くかもしれません.
$( "#foo" ).bind( "click", function() {
alert( "User clicked on 'foo.'" );
});
id
がfoo
の要素バインディングclick
イベントであり、匿名のコールバック関数であることを意味する.もちろんさまざまなタイプのイベントを結びつけることもできます.$( "#foo" ).bind( "mouseenter mouseleave", function() {
$( this ).toggleClass( "entered" );
});
もっと詳しい使い方はjQuery公式サイトの.bind()
のAPIを参照してください.3.2原生JavaScriptにおけるbind方法
もう一つは、オリジナルのbind関数であり、ECMAScript 5には
Function.prototype
にいくつかのオリジナルの拡張方法が追加されており、Function.prototype.bind
が含まれている.信じないなら、Googleやフォックスの下で下記のコードを実行してみてください.IEは比較的に馬鹿です.IE 9+はbind
方法をサポートします.console.log(Function.prototype.bind); //-->bind() { [native code] }
旧式ブラウザのBInd互換性のある方法(MDNから):if (!Function.prototype.bind) {
Function.prototype.bind = function (oThis) {
if (typeof this !== "function") { //
throw new TypeError("Function.prototype.bind() error");
}
var aArgs = Array.prototype.slice.call(arguments, 1),
fToBind = this, // this,
fNOP = function () {},
fBound = function () {
// ,
return fToBind.apply(this instanceof fNOP
&& oThis ? this : oThis
|| window,
aArgs.concat(Array.prototype.slice.call(arguments)));
};
fNOP.prototype = this.prototype;
fBound.prototype = new fNOP();
return fBound;
};
}
以下、JS原生bindの基本的な使い方を見てみましょう.function foo() {
console.log(this.name);
console.log(arguments);
}
var obj = {
name: 'ManfredHu'
}
// foo obj ,
var newFunc = foo.bind(obj, ' 1', ' 2');
newFunc();
//output:( )
//ManfredHu
//Arguments[2] 0: " 1" 1: " 2"
そして、実は使い方も簡単です.原理は簡単に言います.bind
は元の関数copyを一つにまとめ、copyコピーの文脈を結び付けました.もちろん、ここの文脈はthis
の指しを表しています.そして、後は変えたくても変えられません.var obj = {};
function foo() {
return this;
}
var foo2 = foo.bind(obj); //
var obj2 = {};
obj2.foo2 = foo2;
console.log(obj === foo2()); //-->true
console.log(obj === window.foo2()); //-->true
console.log(obj === obj2.foo2()); //-->true
ここでは、関数実行のコンテキストをwindow
およびobj2
で変更しようとしても、成功しませんでした.次は終わりです.高エネルギーです.ある日ぶらぶらしている時に面白い訳文を見ました.最初に読んでみましたが、よく分からないところがあって、他のことをするために急いでいました.先に置いておきました.後ろに暇があったら、この訳文を見つけました.あるいはコードです.灰色の常に鋭いです.役割も書き方もいたるところにJSの動態特性を徹底的に表しています.
var context = { foo: "bar" };
function returnFoo () { // this.foo
return this.foo;
}
returnFoo(); //-->undefined( window.foo )
var bound = returnFoo.bind(context); // bind
bound(); //-->"bar"( , context.foo)
returnFoo.call(context); //--> bar(call )
returnFoo.apply(context); //--> bar
context.returnFoo = returnFoo; // context
context.returnFoo(); //--> bar(returnFoo this context)
//-----------------------------------------------------------------------
// , ,
//-----------------------------------------------------------------------
[1,2,3].slice(0,1); //-->[1]( , )
var slice = Array.prototype.slice; // , slice ,
// ,slice
slice(0, 1); //--> TypeError: can't convert undefined to object
// , ,slice
slice([1,2,3], 0, 1); //--> TypeError: ...
// , [1,2,3].slice(0,1); , slice
slice.call([1,2,3], 0, 1); //--> [1]
// , apply ,
slice.apply([1,2,3], [0,1]); //--> [1]
// , , “ ”,
// slice.call slice
// , JS ,
// slice , call , , ,
slice = Function.prototype.call.bind(Array.prototype.slice);
// slice.call([1,2,3], 0, 1); call slice
slice([1,2,3], 0, 1); //--> [1]
// ,bind.call bind
var bind = Function.prototype.call.bind(Function.prototype.bind);
//OK, ,slice bind
//
var context = { foo: "bar" };
function returnFoo () {
return this.foo;
}
// "bind"
//bind(function,context)
//@function
//@context
//@return
// :returnFoo.bind(context,[args1,args2……])
// ? ?
var amazing = bind(returnFoo, context);
amazing(); // --> bar
4.まとめ5.引用参考:
MDN公式文書——Function.prototype.bind()張小俊128——Javascript中のBind,CallとAppley