ホームページ > ウェブフロントエンド > jsチュートリアル > JavaScript の関数呼び出しとコンストラクター呼び出し_JavaScript スキルを学ぶためにフォローしてください

JavaScript の関数呼び出しとコンストラクター呼び出し_JavaScript スキルを学ぶためにフォローしてください

WBOY
リリース: 2016-05-16 15:32:17
オリジナル
1273 人が閲覧しました

1. 関数呼び出し
JavaScript で最も重要なのは間違いなく関数です。 JavaScript では、Function はプロシージャ、メソッド、コンストラクター、さらにはクラスやモジュールの機能を引き受けます。

オブジェクト指向プログラミングでは、関数、メソッド、クラス コンストラクターは 3 つの異なるものであり、異なる構文で実装されることがよくあります。しかし、JavaScript では、これら 3 つの概念は、3 つの異なるモードを通じて関数によって実装されます。

最も単純な使用モードは関数呼び出しです:

function hello(username) { 
  return "hello, " + username; 
} 
hello("Keyser Söze"); // "hello, Keyser Söze" 
ログイン後にコピー

2. メソッド呼び出し

JavaScript におけるメソッドの概念は、オブジェクトの属性が関数であるというものです。これは同じ関数ですが、オブジェクトのメンバーに割り当てた後は異なります。関数をオブジェクトのメンバーに割り当てると、その関数は関数と呼ばれなくなり、メソッドと呼ばれるようになります。

var obj = { 
  hello: function() { 
    return "hello, " + this.username; 
  }, 
  username: "Hans Gruber" 
}; 
obj.hello(); // "hello, Hans Gruber" 
ログイン後にコピー

実際の動作は、呼び出し自体がどのオブジェクトにバインドされるかを決定することです。つまり、
obj1.hello() はこれを obj1 にバインドし、obj2.hello() はこれを obj2 にバインドします。一文を覚えておいてください。誰が電話しても、これは誰を指します

この拘束ルールにより、次のような使用法も可能です:

function hello() { 
  return "hello, " + this.username; 
} 

var obj1 = { 
  hello: hello, 
  username: "Gordon Gekko" 
}; 
obj1.hello(); // "hello, Gordon Gekko" 

var obj2 = { 
  hello: hello, 
  username: "Biff Tannen" 
};_ 
obj2.hello(); // "hello, Biff Tannen" 

ログイン後にコピー

しかし、上記の hello 関数のような通常の関数では、this キーワードを直接呼び出すのは良い方法ではありません。this の指定が問題になります。この場合、これはグローバル オブジェクト (GlobalObject) を指すことが多く、これは通常ブラウザ上のウィンドウ オブジェクトです。
そして、この行動は不確実で意味がありません。

ES5 標準では、厳密モードが使用される場合、これは未定義に設定されます:

function hello() { 
  "use strict"; 
  return "hello, " + this.username; 
} 
hello(); // error: cannot read property "username" of undefined 
ログイン後にコピー

上記のアプローチは、潜在的なエラーをより迅速に発見し、誤操作や見つけにくいバグを回避することです。
通常の関数呼び出しとメソッド呼び出しの違いは、この例を見ると明らかです。

var func = function() {
  alert(this);
};
var o = {};
o.fn = func;
// 比较
alert(o.fn === func);//true
// 调用
func();//[object Window]
o.fn();//[object Object]
ログイン後にコピー

ここでの実行結果は 2 つの関数が同じであるため、出力された結果は true になります。ただし、2 つの関数の呼び出しは異なるため、func の呼び出しでは [object Window] が出力されますが、o.fn の出力結果は [object Object] となります。

関数呼び出しとメソッド呼び出しの違いは次のとおりです。関数呼び出しでは、これは特にグローバル オブジェクト ウィンドウを指しますが、メソッドでは、これは具体的に現在のオブジェクトを指します。つまり、o.fn の this はオブジェクトを指します。ああ。

3. コンストラクターの呼び出し

関数の 3 番目の使用モードは、コンストラクターとして使用することです:

コンストラクター内の

this

次のコードに示すように、この意味を知るにはオブジェクトの作成プロセスを分析する必要があります。

 var Person = function() {
  this.name = "小平果";
 };
 var p = new Person();
ログイン後にコピー
ここで関数 Person を最初に定義します。実行全体を分析してみましょう。

    プログラムがこの文を実行するとき、関数本体は実行されないため、JavaScript インタプリタはこの関数の内容を知りません。
  • 次に、 new キーワードを実行してオブジェクトを作成します。インタプリタはメモリを割り当て、オブジェクトへの参照を取得し、新しいオブジェクトへの参照を関数に渡します。
  • 次に、関数を実行し、渡されたオブジェクト参照を this に渡します。つまり、コンストラクター メソッドでは、これは new によって作成されたばかりのオブジェクトです。
  • 次に、これにメンバーを追加します。つまり、オブジェクトにメンバーを追加します。
  • 最後に、関数は終了し、これを返し、これを左側の変数に渡します。
コンストラクターの実行を分析した後、コンストラクター内の this が現在のオブジェクトであることがわかります。

コンストラクターで返す

コンストラクター内の戻り値の意味が変更されました。まず、コンストラクター内でオブジェクトが返される場合、戻り値が数値、ブール値などの非オブジェクトの場合、元の意味が保持されます。文字列の場合、戻り値は this です。return ステートメントがない場合は、これも返されます。次のコードを見てください:

 // 返回一个对象的 return
 var ctr = function() {
  this.name = "赵晓虎";
  return {
  name:"牛亮亮"
  };
 };
 // 创建对象
 var p = new ctr();
 // 访问name属性
 alert(p.name);

 //执行代码,这里打印的结果是"牛亮亮". 因为构造方法中返回的是一个对象,那么保留return的意义,返回内容为return后面的对象. 再看下面代码:

 // 定义返回非对象数据的构造器
 var ctr = function() {
  this.name = "赵晓虎";
  return "牛亮亮";
 };
 // 创建对象
 var p = new ctr();
 // 使用
 alert(p);
 alert(p.name);
ログイン後にコピー
コードを実行した結果、ポップアップ ウィンドウは最初に [object Object] を出力し、次に "Zhao Xiaohu" を出力します。これは、ここでの return は基本型に属する文字列であり、次に return ステートメントが出力されます。 here は無効であり、 this オブジェクトが返されます。 したがって、最初のものは [object Object] を出力しますが、2 つ目は unknown を出力しません。

function User(name, passwordHash) { 
  this.name = name; 
  this.passwordHash = passwordHash; 
} 
var u = new User("sfalken", 
  "0ef33ae791068ec64b502d6cb0191387"); 
u.name; // "sfalken" 
ログイン後にコピー
新しいキーを使用して関数をコンストラクターとして呼び出します。関数やメソッドの呼び出しとは異なり、コンストラクターは新しいオブジェクトを渡してこれにバインドし、そのオブジェクトをコンストラクターの戻り値として返します。コンストラクター関数自体の機能は、オブジェクトを初期化することです。

コンストラクター呼び出しでよくある間違い

私は喜んで次のコンストラクターを定義しました:

var Coder = function( nick ){ 
this.nick = nick; 
}; 
ログイン後にコピー
コンストラクターを定義した後はどうなりますか?そうです、すぐにインスタンス化してください:

var coder = Coder( 'casper' ); 
ログイン後にコピー
このプログラマーの兄弟の名前は何ですか?すぐに印刷してください:

console.log( coder.nick ); //undefined 
= =b 竟然是undefined!!再回过头看看实例化的那个语句,不难发现问题出在哪里:少了个new 
var coder = Coder( 'casper' ); //当作普通的函数来调用,故内部的this指针其实指向window对象 
console.log( window.nick); //输出:casper 
var coder = new Coder( 'casper' ); //加上new,一切皆不同,this正确地指向了当前创建的实例 
console.log( coder.nick ); //输出:casper 
ログイン後にコピー

这样的错误貌似挺低级的,但出现的概率挺高的,肿么去避免或减少这种情况的发生呢?
可以在内部实现里面动下手脚:

var Coder = function( nick ){ 
  if( !(this instanceof Coder) ){ 
    return new Coder( nick ); 
  } 
    this.nick = nick; 
}; 
ログイン後にコピー

其实很简单,实例化的时候,内部判断下,当前this指向的对象的类型即可,如果非当前构造函数的类型,强制重新调用一遍构造函数。
突然觉得Coder这名字不够洋气?想用Hacker,好吧,我改。。。数了下,一共有三处要改,这不科学,有没有办法只把构造函数的名字改了就行?
当然有:

var Coder = function( nick ){ 
  if( !(this instanceof arguments.callee) ){ 
    return new arguments.callee( nick ); 
  } 
  this.nick = nick; 
}; 
ログイン後にコピー

tips:据说在ES 5的严格模式下面arguments.callee会被禁用,不过仅当ES 5普及同时你指定了要使用严格模式,否则还是可以用的发散下思维。

以上就是本文的全部内容,希望对大家学习函数调用、方法调用和构造函数调用有所帮助。

ソース:php.cn
このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
最新の問題
人気のチュートリアル
詳細>
最新のダウンロード
詳細>
ウェブエフェクト
公式サイト
サイト素材
フロントエンドテンプレート