この記事では主に JS の新しい呼び出し関数の原理を紹介します。これには特定の参考値があります。必要な友達はそれを参照してください。
コンストラクターは JavaScript でオブジェクトを作成するためによく使用されます。 new 演算子を使用して関数を呼び出す場合)、new
を使用して関数を呼び出すと具体的にはどうなるのでしょうか?舞台裏で何が起こっているかを説明する前に、いくつかの例を見てみましょう。 new
操作符调用一个函数),那在使用 new
调用一个函数的时候到底发生了什么?先看几个例子,再解释背后发生了什么。
构造函数最后没有 return
语句,这也是使用构造函数时默认情况,最后会返回一个新对象,如下:
function Foo(age) { this.age = age; } var o = new Foo(111); console.log(o);
这是常见的使用构造函数创建对象的过程,打印出来的是 {age: 111}
。
构造函数最后 return
对象类型数据:
function Foo(age) { this.age = age; return { type: "我是显式返回的" }; } var o = new Foo(222); console.log(o);
打印出来的是 {type: '我是显式返回的'}
,也就是说,return
之前的工作都白做了,最后返回 return
后面的对象。
那是不是只要构造函数体内最后有 return
,返回都是 return
后面的数据呢?
我们看下返回基本类型数据的情况:
function Foo(age) { this.age = age; return 1; } var o = new Foo(333); console.log(o);
打印出来的是 {age: 333}
,和没有 return
时效果一样。跟预期不一样,背后你原理看下面分析。
当使用 new
操作符创建对象是,ES5 官方文档在 函数定义 一节中做了如下定义 13.2.2 [[Construct]]
:
When the [[Construct]]
internal method for a Function
object F
is called with a possibly empty list of arguments, the following steps are taken:
Let obj be a newly created native ECMAScript object.
Set all the internal methods of obj as specified in 8.12.
Set the [[Class]] internal property of obj to Object.
Set the [[Extensible]] internal property of obj to true.
Let proto be the value of calling the [[Get]] internal property of F with argument "prototype".
If Type(proto) is Object, set the [[Prototype]] internal property of obj to proto.
If Type(proto) is not Object, set the [[Prototype]] internal property of obj to the standard built-in Object prototype object as described in 15.2.4.
Let result be the result of calling the [[Call]] internal property of F, providing obj as the this value and providing the argument list passed into [[Construct]] as args.
If Type(result) is Object then return result.
Return obj.
看第 8、9 步:
8)调用函数F
,将其返回值赋给result
;其中,F
执行时的实参为传递给[[Construct]]
(即F
本身) 的参数,F
内部this
指向obj
;
9)如果result
是Object
类型,返回result
;
这也就解释了如果构造函数显式返回对象类型,则直接返回这个对象,而不是返回最开始创建的对象。
最后在看第 10 步:
10)如果F
返回的不是对象类型(第 9 步不成立),则返回创建的对象obj
。
如果构造函数没有显式返回对象类型(显式返回基本数据类型或者直接不返回),则返回最开始创建的对象。
那如果构造函数是箭头函数怎么办?
箭头函数中没有 [[Construct]]
方法,不能使用 new
调用,会报错。
NOTICE:其中 [[Construct]]
就是指构造函数本身。
相关规范在 ES6 的官方文档 中有提,但自从 ES6 以来的官方文档巨难懂,在此不做表述。
除了箭头函数之外的任何函数,都可以使用 new
return
ステートメントはありません。これもデフォルトです。最後に、次のように新しいオブジェクトが返されます: 🎜function Foo(name) { this.name = name; } var o1 = new Foo("xiaoming"); console.log(o1.__proto__ === Foo.prototype); // true // 重写构造函数原型属性为非对象类型,实例内部 [[Prototype]] 属性指向 Object 原型对象 // 因为实例是一个对象类型的数据,默认会继承内建对象的原型, // 如果构造函数的原型不满足形成原型链的要求,那就跳过直接和内建对象原型关联 Foo.prototype = 1; var o2 = new Foo("xiaohong"); console.log(o2.__proto__ === Foo.prototype); // false console.log(o2.__proto__ === Object.prototype); // true
{age: 111}
です。 >。 🎜return
します: 🎜const Foo = function() {}; const o = new Foo(); o instanceof Foo; // true // 重写 Foo 原型 Foo.prototype = {}; o instanceof Foo; // false
{type: 'I returns it明示的に' }、つまり、<code>return
より前のすべての作業は無駄に行われ、return
の後のオブジェクトが最終的に返されます。 🎜return
がある限り、return
以降のデータは返されるという意味ですか?返されるのか? 🎜🎜基本型データを返す状況を見てみましょう: 🎜rrreee🎜 出力されるのは {age: 333}
で、これは return
がない場合と同じ効果があります。 。期待とは異なります。その原理については、以下の分析を参照してください。 🎜new
演算子を使用してオブジェクトを作成する場合、ES5 公式ドキュメントは関数内です。次の定義は定義セクション 13.2.2 [[Construct]]
で行われます。 🎜🎜When the [[Construct]]
内部メソッドFunction
オブジェクト F
が空の引数リストを使用して呼び出される場合、次の手順が実行されます:🎜8) 関数🎜これは、コンストラクターがオブジェクト タイプを明示的に返す場合、返されるのではなく直接オブジェクトを返すことも説明しています。最初に作成されたオブジェクト。 🎜🎜最後にステップ 10 を見てください: 🎜F
を呼び出し、その戻り値をresult; このうち、<code>F
が実行されるときの実際のパラメータは、[[Construct]]
に渡されるパラメータです (つまり、F 自体)、F
内部のthis
はobj
を指します。
9)result
が次の場合Object
Type, returnresult
;
10)🎜コンストラクターがオブジェクト型を明示的に返さない場合 (基本データ型を明示的に返すか、直接返さない場合)、最初に作成されたオブジェクトが返されます。 🎜F
がオブジェクト タイプを返さない場合 (ステップ 9 が true ではない)、作成されたオブジェクトobj /コード>。
[[Construct]]
メソッドが存在せず、new
を使用して呼び出すことができず、エラーが報告されます。 🎜🎜注意: [[Construct]]
はコンストラクター自体を指します。 🎜関連する仕様はES6の公式ドキュメントに記載されていますが、ES6以降の公式ドキュメントは非常にわかりにくいのでここでは記載しません。
new code> を使用できます。が電話をかけます。舞台裏で何が起こっているかは、前のセクションで英語で非常に明確に説明されており、中国語では次のように説明されています。<p>1)创建 ECMAScript 原生对象 <code>obj
; obj
设置原生对象的内部属性;(和原型属性不同,内部属性表示为 [[PropertyName]]
,两个方括号包裹属性名,并且属性名大写,比如常见 [[Prototype]]
、[[Constructor]]
) obj
的内部属性 [[Class]]
为 Object
; obj
的内部属性 [[Extensible]]
为 true
; proto
的值设置为 F
的 prototype
属性值; proto
是对象类型,则设置 obj
的内部属性 [[Prototype]]
值为 proto
;(进行原型链关联,实现继承的关键) proto
是不对象类型,则设置 obj
的内部属性 [[Prototype]]
值为内建构造函数 Object 的 prototype
值;(函数 prototype
属性可以被改写,如果改成非对象类型,obj
的 [[Prototype]]
就指向 Object 的原型对象) 对于第 7 步的情况,见下面代码:
function Foo(name) { this.name = name; } var o1 = new Foo("xiaoming"); console.log(o1.__proto__ === Foo.prototype); // true // 重写构造函数原型属性为非对象类型,实例内部 [[Prototype]] 属性指向 Object 原型对象 // 因为实例是一个对象类型的数据,默认会继承内建对象的原型, // 如果构造函数的原型不满足形成原型链的要求,那就跳过直接和内建对象原型关联 Foo.prototype = 1; var o2 = new Foo("xiaohong"); console.log(o2.__proto__ === Foo.prototype); // false console.log(o2.__proto__ === Object.prototype); // true
若执行 new Foo()
,过程如下:
1)创建新对象 o
;
2)给新对象的内部属性赋值,关键是给[[Prototype]]
属性赋值,构造原型链(如果构造函数的原型是 Object 类型,则指向构造函数的原型;不然指向 Object 对象的原型);
3)执行函数 Foo
,执行过程中内部 this
指向新创建的对象 o
;
4)如果 Foo
内部显式返回对象类型数据,则,返回该数据,执行结束;不然返回新创建的对象 o
。
关于一个数据是否是 Object
类型,可以通过 instanceof
操作符进行判断:如果 x instanceof Object
返回 true
,则 x
为 Object
类型。
由上可知,null instanceof Object
返回 false
,所以 null
不是 Object
类型,尽管typeof null
返回 "Object"。
instanceof
的工作原理是:在表达式 x instanceof Foo
中,如果 Foo
的原型(即 Foo.prototype
)出现在 x
的原型链中,则返回 true
,不然,返回 false
。
因为函数的原型可以被改写,所以会出现在 x
通过 Foo
new 出来之后完全改写 Foo
的原型 x instanceof Foo
返回 false
的情况。因为实例创建之后重写构造函数原型,实例指向的原型已经不是构造函数的新的原型了,见下面代码:
const Foo = function() {}; const o = new Foo(); o instanceof Foo; // true // 重写 Foo 原型 Foo.prototype = {}; o instanceof Foo; // false
以上就是本文的全部内容,希望对大家的学习有所帮助,更多相关内容请关注PHP中文网!
相关推荐:
以上がJSの新しい関数呼び出し原理の紹介の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。