Javascript:我需要把每个variables的this.var对象?
在我最熟悉的语言C ++中,通常是声明一个像这样的对象:
class foo { public: int bar; int getBar() { return bar; } }
调用getBar()
工作正常(忽略bar
可能未初始化的事实)。 getBar()
的variablesbar
在foo
类的范围内,所以我不需要说this->bar
除非我真的需要说清楚,我是指类的bar
而不是说,一个参数。
现在,我正在尝试开始使用Javascript中的OOP。 所以,我看看如何定义类并尝试相同的事情:
function foo() { this.bar = 0; this.getBar = function() { return bar; } }
它给我的bar is undefined
。 将bar
this.bar
解决这个问题,但是对于每一个variables都这样做会让我的代码变得相当混乱。 这是每个variables的必要吗? 由于我找不到任何与此相关的问题,这让我觉得我正在做一些根本性的错误。
编辑:所以,从评论我得到的是this.bar
,一个对象的属性,引用不同于bar
,局部variables的东西。 有人可以说,为什么这是正确的,在范围和对象方面,如果有另一种方法来定义一个对象,这是不必要的?
JavaScript没有基于类的对象模型。 它使用更强大的原型inheritance,可以模仿类,但不适合它。 一切都是一个对象,而对象[可以]从其他对象inheritance。
构造函数只是一个为新创build的对象分配属性的函数。 可以通过this
关键字 (对于函数来说是本地的)引用该对象(由具有new
关键字的调用创build)。
一个方法也仅仅是一个在对象上调用的函数 – 再次指向这个对象。 至less当该函数作为对象的属性调用时,使用成员操作符 (点,括号)。 这会给新手造成很多困惑,因为如果你绕过这个函数(例如,传递给一个事件监听器),它就会从被访问的对象上“分离”。
现在inheritance权在哪里? “类”的实例从同一个原型对象inheritance。 方法被定义为该对象上的函数属性(而不是每个实例的一个函数),您调用它们的实例只是inheritance该属性。
例:
function Foo() { this.bar = "foo"; // creating a property on the instance } Foo.prototype.foo = 0; // of course you also can define other values to inherit Foo.prototype.getBar = function() { // quite useless return this.bar; } var foo = new Foo; // creates an object which inherits from Foo.prototype, // applies the Foo constructor on it and assigns it to the var foo.getBar(); // "foo" - the inherited function is applied on the object and // returns its "bar" property foo.bar; // "foo" - we could have done this easier. foo[foo.bar]; // 0 - access the "foo" property, which is inherited foo.foo = 1; // and now overwrite it by creating an own property of foo foo[foo.getBar()]; // 1 - gets the overwritten property value. Notice that (new Foo).foo; // is still 0
所以,我们只使用该对象的属性,并且对它感到满意。 但所有这些都是“公开”的,可以被覆盖/更改/删除! 如果那不重要,你是幸运的。 你可以通过在下划线前加上名字来表示属性的“隐私”,但这只是暗示给其他开发者,并且可能不被遵守(特别是在错误中)。
所以,聪明的头脑已经find了一个解决scheme,使用构造函数作为闭包,允许创build私有“属性”。 每个JavaScript函数的执行都会为局部variables创build一个新的variables环境,一旦执行完成,可能会收集垃圾回收。 每个在该范围内声明的函数也可以访问这些variables,只要这些函数可以被调用(例如通过事件监听器),环境就必须持久化。 因此,通过从构造函数中导出本地定义的函数 ,可以使用只能由这些函数访问的局部variables来保留该variables环境。
让我们看看它的行动:
function Foo() { var bar = "foo"; // a local variable this.getBar = function getter() { return bar; // accesses the local variable }; // the assignment to a property makes it available to outside } var foo = new Foo; // an object with one method, inheriting from a [currently] empty prototype foo.getBar(); // "foo" - receives us the value of the "bar" variable in the constructor
这个在构造函数中定义的getter函数现在被称为“ 特权方法”,因为它可以访问“private”(local)“attributes”(variables)。 bar
的价值永远不会改变。 当然,你也可以为它声明一个setter函数,并且可以添加一些validation等。
请注意,原型对象上的方法无法访问构造函数的局部variables,但它们可能会使用特权方法。 我们来添加一个:
Foo.prototype.getFooBar = function() { return this.getBar() + "bar"; // access the "getBar" function on "this" instance } // the inheritance is dynamic, so we can use it on our existing foo object foo.getFooBar(); // "foobar" - concatenated the "bar" value with a custom suffix
所以,你可以结合这两种方法。 请注意,特权方法需要更多的内存,因为您使用不同的作用域链(但代码相同)创build不同的函数对象。 如果您要创build难以置信的大量实例,则只应在原型上定义方法。
当你设置从一个“类”到另一个的inheritance时,它会变得更复杂一些 – 基本上你必须让子对象从父对象inheritance,并且在子对象上应用父构造器来创build“私有属性”。 看看正确的JavaScriptinheritance , 私有variables在inheritance原型 , 定义私人领域成员和inheritance在JAVASCRIPT模块模式和如何实现inheritance在JS揭示原型模式?
明确地说this.foo
意味着(正如你已经很好理解的那样),你对当前引用的对象的属性foo
感兴趣。 所以如果你使用: this.foo = 'bar';
你将把this
等于引用的当前对象的属性foo
设置为bar
。
JavaScript中的this
关键字并不总是和C ++中的一样。 在这里我可以举一个例子:
function Person(name) { this.name = name; console.log(this); //Developer {language: "js", name: "foo"} if called by Developer } function Developer(name, language) { this.language = language; Person.call(this, name); } var dev = new Developer('foo', 'js');
在上面的例子中,我们使用Developer
函数的上下文调用Person
函数,所以this
是引用到Developer
创build的对象。 从console.log
可以看到这个结果来自Developer
。 通过方法call
的第一个参数,我们指定函数将被调用的上下文。
如果你不使用this
简单的话,你创build的属性将是一个局部variables。 正如你可能知道JavaScript有function范围,所以这就是为什么variables将是本地的,只有在它声明的函数可见(当然,所有它是在父项中声明的子函数)。 这里是一个例子:
function foo() { var bar = 'foobar'; this.getBar = function () { return bar; } } var f = new foo(); console.log(f.getBar()); //'foobar'
当你使用var
关键字时,这是真的。 这意味着你将bar
定义为局部variables,如果你忘记var
不幸的是bar
会变成全局的。
function foo() { bar = 'foobar'; this.getBar = function () { return bar; } } var f = new foo(); console.log(window.bar); //'foobar'
确切地说,本地范围可以帮助您实现隐私和封装,这是OOP最大的好处之一。
现实世界的例子:
function ShoppingCart() { var items = []; this.getPrice = function () { var total = 0; for (var i = 0; i < items.length; i += 1) { total += items[i].price; } return total; } this.addItem = function (item) { items.push(item); } this.checkOut = function () { var serializedItems = JSON.strigify(items); //send request to the server... } } var cart = new ShoppingCart(); cart.addItem({ price: 10, type: 'T-shirt' }); cart.addItem({ price: 20, type: 'Pants' }); console.log(cart.getPrice()); //30
模块模式是JavaScript范围的另一个好处。 在模块模式中,您可以使用JavaScript的本地function范围来模拟隐私。 有了这个方法,你可以拥有私有属性和方法。 这里是一个例子:
var module = (function { var privateProperty = 42; function privateMethod() { console.log('I\'m private'); } return { publicMethod: function () { console.log('I\'m public!'); console.log('I\'ll call a private method!'); privateMethod(); }, publicProperty: 1.68, getPrivateProperty: function () { return privateProperty; }, usePublicProperty: function () { console.log('I\'ll get a public property...' + this.publicProperty); } } }()); module.privateMethod(); //TypeError module.publicProperty(); //1.68 module.usePublicProperty(); //I'll get a public property...1.68 module.getPrivateProperty(); //42 module.publicMethod(); /* * I'm public! * I'll call a private method! * I'm private */
有一点奇怪的语法,无父母包装的匿名函数,但暂时忘记它(它只是执行函数后,它正在初始化)。 这个function可以从使用的例子中看出来,但是好处主要与提供一个简单的公共接口有关,而这个公共接口并没有吸引你所有的实现细节。 有关该模式的更多详细说明,请参阅上面的链接。
我希望通过this
:-)信息帮助你理解JavaScript的一些基本主题。
function Foo() { this.bar = 0; this.getBar = function () { return this.bar }; }
当你用new
关键字调用上面的函数 – 像这样…
var foo = new Foo();
… – 几件事情发生:
1)创build一个对象
2)使用this
关键字引用该对象执行该function。
3)该对象返回。
foo
,那么,成为这个对象:
{ bar: 0, getBar: function () { return this.bar; } };
那么,为什么不呢,就这样做:
var foo = { bar: 0, getBar: function () { return this.bar; } };
你会的,如果只是一个简单的对象。
但是用一个构造函数创build一个对象(这就是所谓的)给我们创build了多个“相同”对象的一个很大的优势。
请参阅javascript中的所有函数都是使用原型属性(对象)创build的,并且使用该函数创build的所有对象(通过使用new关键字调用它)链接到该原型对象。 这就是为什么它很酷 – 你可以在原型对象中存储所有常用的方法(和属性,如果你想),并保存大量的内存。 这是如何工作的:
function Foo( bar, bob ) { this.bar = bar; this.bob = bob; } Foo.prototype.calculate = function () { // 'this' points not to the 'prototype' object // as you could've expect, but to the objects // created by calling Foo with the new keyword. // This is what makes it work. return this.bar - this.bob; }; var foo1 = new Foo(9, 5); var foo2 = new Foo(13, 3); var result1 = foo1.calculate(); var result2 = foo2.calculate(); console.log(result1); //logs 4 console.log(result2); //logs 10
而已!
在JavaScript中, this
总是引用该函数的所有者对象。 例如,如果你在一个页面中定义你的函数foo()
,那么owner是javascript对象的windows
; 或者如果你在html元素<body>
上定义了foo()
,那么所有者就是html元素体。 同样如果你定义了元素<a>
onclick函数,那么所有者就是锚点。
在你的情况下,你正在分配一个属性bar
到开始的“所有者”对象,并试图返回本地variablesbar
。
由于你从来没有定义任何本地varialbe bar
,它是给你,因为酒吧是未定义的。
理想情况下,你的代码应该已经定义variables为var bar;
如果你想返回零值。
为了更接近于JavaScript中的OOP,你可能想看看模块devise模式(例如, 这里描述)。
基于闭包效应,这个模式允许在你的对象中模拟私有属性。
有了'私人'属性,你可以通过它的标识符直接引用它们(即没有this
关键字在构造函数中)。
但无论如何,JS中的封闭和devise模式是一个高级的话题。 所以,熟悉基础知识(也在前面提到的书中解释过)。
这就像对象(variables或函数)的公共访问修饰符,而var是私有访问修饰符
例
var x = {}; x.hello = function(){ var k = 'Hello World'; this.m = 'Hello JavaScript'; } var t = new x.hello(); console.log(tk); //undefined console.log(tm); //Hello JavaScript