下面的示例代码是John Resig的Learning Advnaced JavaScript中的#36。 http://ejohn.org/apps/learn/#36
It is called We need to make sure the new operator is always used.
六个问题 - 我希望尽可能多地提供详细信息
1)此代码中是否实际调用了function User
?我注意到,当它显示assert(user...)
时,用户是小写的。如果函数被调用,怎么样?当它断言变量user时会调用它,该变量用户附加了一个函数调用,即User("John," name)
2)如果我m correct in assuming that function User is never called, is there a way that the code
this.name = first +“”+ last;`运行?
3)如果调用了User函数,或者调用了它,可以在函数User中解释操作的顺序。例如,它返回新用户this.name = first + " " + last;
如果调用或调用此函数,它将如何工作?
4)!(this instanceof User)
如果是真的,以什么方式。由于函数User是对象,不会“这个”总是它自己的一个实例吗?
5)关于第一个断言,即assert(user, "this was defined correctly, even if it was by mistake")
,你能否解释一下它是如何被正确定义的,重要的是,请解释一下这是怎么一个错误?它应该如何完成所以它不是一个错误?
6)关于第二个断言,为什么值得注意的是保留了正确的名称? ISN t it as simple as variable
名为having been assigned
Resig`。您可能以何种方式改变名称?
function User(first, last){
if ( !(this instanceof User) )
return new User(first, last);
this.name = first + " " + last;
}
var name = "Resig";
var user = User("John", name);
assert( user, "This was defined correctly, even if it was by mistake." );
assert( name == "Resig", "The right name was maintained." );
答案 0 :(得分:3)
此示例演示了JavaScript设计中的一个基本缺陷,即调用函数用作没有new
运算符的构造函数可能会导致无意中修改全局对象。
User
:var user = User("John", name);
。小写user
包含对新的大写User
实例的引用。
见#1。
如果在没有User
的情况下调用new
,则this
将不会是instanceof
User
。发生这种情况时,我们会立即致电new User(...)
。在第二次调用中,this
将一个instanceof
User
,因此跳过条件块,我们继续使用构造函数,创建一个新实例User
最初的意图。
在没有new
运算符的情况下调用它时,函数中this
的值只是引用全局对象,即浏览器中的window
。这是JavaScript设计中的一个严重错误,本练习演示了一种解决方法。
因为User
构造函数没有明确的返回(没有instanceof
检查的阻止),如果在没有User
的情况下调用new
,它将返回{ {1}} undefined
会失败。 assert
检查会阻止此操作。
如果没有instanceof
检查的保护,则在没有instanceof
的情况下调用User
会导致意外结果。由于new
会引用this
,因此window
的分配将更新this.name
,而不会更新新window.name
实例的name
属性,并且User
会失败。
答案 1 :(得分:3)
任何给定的函数对象都可以使用两种方式。
差异是this
绑定的值。当您使用函数作为构造函数时,this
绑定将是从构造函数的公共原型继承的新对象。通常调用函数会将this
绑定设置为全局对象。 (在ES5中使用严格模式,这不会发生。)
第二个断言非常重要,因为您知道this
绑定可以强制转换为全局对象。
简化调用构造函数
function ConstructUser(fname, lname) {
var obj = {}; // Empty Object
// In reality a special internal Prototype property
// is assigned rather than 'obj.prototype'.
if (User.prototype instanceof Object) {
obj.prototype = User.prototype;
} else {
obj.prototype = Object.prototype;
}
// Now call the User function with the
// new object as the 'this' binding.
User.call(obj, fname, lname);
return obj;
}
答案 2 :(得分:2)
1)是否在此代码中实际调用过用户函数?我注意到当它说assert(用户...)时,用户是小写的。如果函数被调用,怎么样?当它断言变量user时会调用它,该变量user附加了一个函数调用User(“John,”name)
是。首先调用绑定到全局对象的this
(请参阅下面的警告),然后使用空白对象调用自身,其原型为User.prototype
绑定到this
。
第一个“call”调用内置函数调用操作符,第二个“call”调用内置函数构造操作符。对于用户定义的函数,两者是相同的,但规范确实区分了两者。
2)如果我认为函数User从未被调用是正确的,那么有没有办法运行代码
this.name = first + " " + last;
?
是。第二次调用将达到,因为在第二次调用中this
是User
。
3)如果调用了User函数,或者调用了它,可以在函数User中解释操作的顺序。例如,它在执行此操作之前返回新用户.name = first +“”+ last;如果调用或调用此函数,它将如何工作?
在身体完成之前,呼叫不会返回。所以“调用”调用开始,它启动“构造”调用,返回,产生新的User
,然后由第一次调用返回。
4)以什么方式可以!(这个用户实例)如果是真的。由于函数User是对象,不会“这个”总是它自己的一个实例吗?
没有。如果if
语句不存在,User.call({}, "John", "Doe")
会导致User
被“调用”,this
绑定到空白对象。尝试运行
var notAUser = {};
User.call(notAUser, "John", "Doe")
alert(JSON.stringify(notAUser));
你应该
{ "name": "John Doe" }
5)关于第一个断言,即断言(用户,“这是正确定义的,即使它是错误的”),你能解释一下它是如何被正确定义的,更重要的是,请解释它是怎么一个错误?它应该如何完成所以它不是一个错误?
作者认为,在new
之前放User
是程序员错误。
6)关于第二个断言,为什么值得注意的是保留了正确的名称?它不像变量名称一样简单,已经被赋予了.Resig`。您可能以何种方式改变名称?
全局变量name
是全局对象的属性。如果this
绑定到全局对象,则分配this.name
将更改全局变量。
警告:
语言律师,
根据语言规范,当您将函数作为函数调用而不是作为方法时,this
绑定到null
。规范的另一部分说当你阅读this
时,如果它是null
,你得到的是全局对象。这种差异在EcmaScript 5严格模式的情况下很重要,因为这会改变第二部分,因此在阅读this
时不会有任何有趣的东西。如果this
为空,则读取它会返回值null
。
编辑:
构造运算符仅在JavaScript规范中定义。 JavaScript语言中的new
运算符就是您调用它的方式。
对于用户定义的函数,它的工作方式如下:
new f(arg1, arg2)
prototype
设置为f.prototype
。f
,this
设置为新对象,arg1
和arg2
作为实际参数。f
返回一个对象,则会将其用作new
的结果。new
的结果。答案 3 :(得分:1)
1.在 var user = User(“John”,name);
中调用用户函数2.pass
3.我不明白你的问题。
4
user = User(“a”,“b”); 会这样做。
5.user = new User(“a”,“b”);是正确的。
6.我不知道。