var currentTime = Date()
能天生一个当前时候的日期对象,var currentTime = new Date()
也能天生一个一样的对象。假如你看过一些框架,那末你会发现有的框架天生对象写法是 new ClassName(),有的框架是 className()。 那末两种体式格局有什么区分呢?
一般函数/要领挪用
假定我们定义了一个函数:
function normalFunc() {
console.log( this );
}
// 第一种调法
normalFunc();
// 第二种调法
normalFunc.call( null );
// 第三种调法
var obj = {
method: normalFunc
}
obj.method();
我们把一个函数被看成一个一般函数或许要领挪用归为一类,其被挪用时发作的重要步骤:
天生一个新的实行上下文和对应的作用域。(假如对实行上下文是什么不相识的话,能够参考我上一篇《什么是作用域和实行上下文》)
把当前函数和这个新的实行上下文和作用域关联起来。
2.1. 假如当前函数是箭头函数,那末把作用域中的 environment record 对象的内部属性[[thisBindingStatus]]
设置成 lexical。把这个实行上下文压入挪用栈的顶部,即设置成运转实行上下文(running execution context)。
接下来处置惩罚当前函数的属性 this 的取值:
4.1. 假如当前函数是箭头函数,那末这步就不做任何处置惩罚(由于已在步骤2.1中做了标志位)。
4.2. 假如不是箭头函数,那末先检察当前函数是不是处在严厉形式下。
4.2.1. 严厉形式:this 的取值取决于怎样挪用当前函数,比如上例代码中第一种调法,取值为 undefined,第二种调法取值为 `normalFunc.call(` 的第一个参数,第三种调法取值为 obj。
4.2.2. 非严厉形式:先按4.2.1的分类取得 this 的取值,假如是 null 或许 undefined,用全局对象替代 null 或许 undefined。假如 this 的取值黑白空值那末把 this 指向这个非空值(注1)。
4.3. 把 this 的取值保存在作用域中的 environment record 对象的内部属性 [[thisValue]]
中(步骤4中并非把 this 直接指向这些取值,而是把值保存在作用域特定内部属性中,this 的寻值历程另有分外一步,下面会申明)。
实行函数体。
把当前实行上下文弹出挪用栈。
假如步骤5有返回,则返回这个效果。假如步骤5没有返回,则返回 undefined。
注1:这里非空值还要推断是原始范例(primitive value),照样对象范例。假如是原始范例,取值还要再把原始范例包装成对象才作为 this 的取值。步骤中防止太烦琐,省略了细节顾专程加上解释。
函数中 this 的取值历程(ResolveThisBinding)
连系上面形貌的步骤,我们来看看当你在函数中运用 this 时(上面的步骤5中 this 已可用),程序时怎样寻觅 this 的:
依据当前实行上下文查找到对应的 enviroment record(execution context -> scope -> environment record)。
推断当前这个 record 是不是存储过
[[thisValue]]
,假如没有的就沿着作用域链向上查找,以全局作用域为尽头。假如找到了,则返回。
如上所述,箭头函数自身的作用域并没有存储[[thisValue]]
,所以其内部运用 this 会去定义箭头函数的处所(函数)去取 this,假如取不到继续向上查找。
函数作为组织函数挪用
// 没有继续关联
function normalFuncAsContructor() {
// return a new object?
// return {}
// or not
// [return]
}
var o = new normalFuncAsContructor();
// 有继续关联
function Parent(){}
function Child(){}
Child.prototype = new Parent();
var c = new Child();
我们把一个函数被看成组织函数,运用 new 操纵符挪用时发作的重要步骤:
新建一个一般对象,把其原型
[[Prototype]]
指向组织函数的 prototype 属性的值。如一般函数挪用的步骤1一样,天生一个新的实行上下文和对应的作用域,并把当前组织函数和二者关联起来。
把这个实行上下文压入挪用栈的顶部。
把第一步天生的对象看成 this 的取值保存到作用域中的 environment record 对象的内部属性
[[thisValue]]
中。实行函数体。
把当前实行上下文弹出挪用栈。
处置惩罚函数实行的效果,即 new 了以后返回啥:
7.1 假如步骤5返回一个对象,那末就把这个对象作为此次 new 操纵的返回值。
7.2 假如返回的不是对象,而且这个函数不是 generator 函数,那末返回第一步天生的对象(generator 就先不在这里议论了)。
知道了二者的区分,我们就能在函数体内里搞文章了,你能够经由过程以下代码检测用户怎样挪用你的函数。假如你知道了用户怎样挪用,你天然能够依据你想要的效果限定用户的运用要领。
function myFunc() {
if ( this && myFunc.prototype.isPrototypeOf( this ) ) {
console.log( 'called by new operator' );
} else {
console.log( 'commonly invoked' );
}
}
myFunc(); // commonly invoked
new myFunc(); // called by new operator
var obj = {
method: myFunc
}
obj.method(); // commonly invoked