我是Javascript的新手并且对以下陈述的结果感到困惑。你能帮助澄清每个结果背后的原因吗?如果您还可以建议明确解释这些情况下预期行为的资源,将不胜感激。
function Person(){
this.a = function(){alert("a")};
}
Person.prototype.b = function(){alert("b")};
Person.c=function(){alert("c")};
var test = new Person();
test.a(); // works
test.b(); // works
test.prototype.b(); //error
Person.prototype.a(); // error (why?)
Person.prototype.b(); //works (why?)
Person.c(); //works
Person();
Person.a(); /* error (Person() call should have set this.a
on the Person object just like the c method,
why doesn’t it work?) */
Person.b();//error (why?)
答案 0 :(得分:1)
我对这是否重复存在两种看法,或者是否应该将它分解为几个不同的问题。然而,由于这吸引了可疑质量的答案,让我们逐行浏览你的代码。
function Person(){
this.a = function(){alert("a")};
}
定义函数Person。没什么特别的。调用它Person()
将取决于它是否以严格模式运行,抛出错误'无法设置属性" a"未定义的'或者它会创建一个全局变量' a' vaue是一个警告' a'。
但是,按照惯例,Javascript中的大写函数应该是构造函数,并使用new
运算符调用。致电new Person()
会为你带来一些魔力。它创建一个新对象并将其设置为构造函数中的this
值。构造函数也隐式返回新对象,这就是它没有return语句的原因。这意味着新人有一种方法,可以提醒他们注意一个'什么时候叫。
但实际上很少这样做,使用原型更为常见。 new
运算符还将新创建的对象的内部原型设置为构造函数的.prototype
属性的值(该对象实际上没有.prototype
{{1} 1}}属性)。构造函数.prototype
对象上定义的任何内容都可用于通过使用new
调用该构造函数创建的每个实例。
Person.prototype.b = function(){alert("b")};
这定义了Person(构造函数)的.prototype
对象上的函数b。它将通过调用new Person()
提供给所有创建的Person实例。它也可以直接调用Person.prototype.b()
。这种方法比用于附加' a'方法,因为所有的人都分享了' b'但他们都有自己的副本' a'。
Person.c=function(){alert("c")};
在Javascript 中,是一个对象,包括函数。对象可以分配属性。在这里,您将为Person函数本身的c属性分配一个函数。如果您习惯使用基于类的语言,则类似于类静态方法。
希望到现在为止,其余部分将变得更加清晰。每个人都包括'测试'会有一个' a'方法,因为构造函数分配它。但是,人的原型没有' a'方法,它只是在构造函数中赋值。人的原型有一个''方法,意味着所有Person实例都可以访问该共享的' b'方法。 Person函数本身有一个' c'方法,但它没有传递给实例,所以'测试'没有' c'方法
答案 1 :(得分:1)
好的,我会试一试。我很快就会采访,所以这是一个很好的做法:)
function Person(){
this.a = function(){alert("a")};
}
Person.prototype.b = function(){alert("b")};
Person.c=function(){alert("c")};
var test = new Person();
test.a(); // works
test.b(); // works
test.prototype.b(); //error
听起来你有这个,但test
是一个对象,而不是构造函数。它没有原型键。
Person.prototype.a(); // error (why?)
Person.prototype.b(); //works (why?)
在这里,事情变得有趣。查看Person()
函数;所有它确实引用传递给它的参数并返回一个新对象。看起来并不复杂。然而,这是JavaScript疯狂的原型继承发挥作用的地方。
假设您在String
上编写了一个更高级别的原型方法,如String.prototype.capitalize = function()...
,并且该方法将字符串大写。您创建的每个新字符串都有capitalize()
方法,但它不像字符串是一个带有该方法键的对象。
这与Person.prototype.a()
和Person.prototype.b()
正在做的事情相同。通过Person()
函数运行对象会创建一个包含这些键的对象。由于Person()
构造函数只返回一个键为a的对象,因此到目前为止这是test
的样子:
console.log(test); // {a: [Function]}
但为什么test.b()
有效?这是因为构造函数创建的任何对象都继承了构造函数 .prototype
上的所有属性。向原型中添加内容并不会更改添加到构造对象的键,而是让其构造的对象可以访问它。在某事物上调用方法首先会查看它的键,然后是构造函数的隐藏[[prototype]]值,然后是它的父级,依此类推。您可以在Chrome中的console.log
中看到这一点。
Person();
Person.a(); /* error (Person() call should have set this.a
on the Person object just like the c method,
why doesn’t it work?) */
Person.b();//error (why?)
这里的错误是Person()
是一个对象。不是;它是一个功能。构造函数中的this
引用引用传递给它的对象;这意味着它被设置为的变量。由于我们只是调用Person()
而未将结果设置为任何内容,因此this
未定义且Person()
的结果未定义,因为没有任何内容可以返回。函数不能有密钥或方法。
希望我能提供帮助。这对我来说也是很好的做法!
答案 2 :(得分:0)
执行Person.c = ...
时,您需要设置静态属性,因此它们不属于原型。
稍后,您尝试将原型方法调用到构造函数,并且它们不存在,因为原型是该构造函数的实例的蓝图。
答案 3 :(得分:0)
class.prototype
就像对象和你的类之间的链接。
class.prototype
您可以分配将在您的类的所有实例之间共享的函数和属性,以及调用函数将在prototype
class
对象上查找的函数和属性
//所以你可以在这里调用原型
Person.prototype.fun;
//但是你直接调用func
test.fun
答案 4 :(得分:0)
我会尽力向您解释,但英语不是我的主要语言。如果您有任何具体问题,请在评论部分询问我,我会详细说明。要完整理解,请阅读more here
test.a(); // works -> Yes because it accessing the property that exists in Person it self
test.b(); // works ->First It will look into test instance properties if it doesn't find it will look one level up into the Person prototype object and it will find it there.
test.prototype.b(); //error because test is an instance and instances do not have a prototype property.
Person.prototype.a(); // error (why?) Because you are going to look for a property a inside Person prototype which does not have it. Property lookup goes only forward not backward.
Person.prototype.b(); //works (why?) because b is a property of the Person prototype.
//typeof Person.prototype is object same as var prototype={} than prototype.b=function(){} so now you can call prototype.b();
Person.c(); //works c is 'static' (more like object literal property assignment because every function in js still is an object) property of Person same as var Person2={};Person2.c=function(){}; that is why you can access it without needing to initialize Person.
Person();
Person.a(); /* error (Person() call should have set this.a
on the Person object just like the c method,
why doesn’t it work?) */ That property requires you to create an instance of Person.
Person.b();//error (why?) it is the same as a but b is a property of prototype of Person