提问人:Chaosed0 提问时间:11/16/2012 最后编辑:Chaosed0 更新时间:2/1/2016 访问量:10907
Javascript:我需要为对象中的每个变量放置 this.var 吗?
Javascript: Do I need to put this.var for every variable in an object?
问:
在 C++ 中,我最熟悉的语言,通常声明一个对象,如下所示:
class foo
{
public:
int bar;
int getBar() { return bar; }
}
调用工作正常(忽略可能未初始化的事实)。其中的变量在类的范围内,所以我不需要说,除非我真的需要明确指出我指的是类而不是参数。getBar()
bar
bar
getBar()
foo
this->bar
bar
现在,我正在尝试开始使用 Javascript 中的 OOP。因此,我查找了如何定义类并尝试了相同的方法:
function foo()
{
this.bar = 0;
this.getBar = function() { return bar; }
}
它给了我.更改 to 可以解决问题,但对每个变量这样做会使我的代码变得相当混乱。这是每个变量都需要的吗?由于我找不到与此相关的任何问题,这让我觉得我做错了什么。bar is undefined
bar
this.bar
编辑:是的,所以,从评论中得到的是,一个对象的属性,引用的东西与局部变量不同。有人能说出为什么会这样,在范围和对象方面,以及是否有另一种方法可以定义不需要的对象?this.bar
bar
答:
JavaScript 没有基于类的类对象模型。它使用更强大的原型继承,它可以模仿类,但不太适合它。一切都是一个对象,对象[可以]从其他对象继承。
构造函数只是一个将属性分配给新创建的对象的函数。对象(通过使用 new
关键字调用创建)可以通过 this
关键字(函数的本地关键字)进行引用。
方法也只是一个在对象上调用的函数 - 同样指向对象。至少当该函数作为对象的属性调用时,使用成员运算符(点、括号)。这给新手带来了很多困惑,因为如果你传递该函数(例如,传递给事件侦听器),它就会与它被访问的对象“分离”。this
现在遗产在哪里?“类”的实例继承自同一原型对象。方法被定义为该对象的函数属性(而不是每个实例一个函数),调用它们的实例只是继承该属性。
例:
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
因此,我们只使用了该对象的属性,并且对此感到满意。但它们都是“公开的”,可以被覆盖/更改/删除!如果这对你来说无关紧要,那你很幸运。您可以通过在属性名称前加上下划线来表示属性的“私有性”,但这只是对其他开发人员的提示,可能不会被遵守(尤其是在错误的情况下)。
因此,聪明的头脑找到了一种解决方案,该解决方案使用构造函数作为闭包,允许创建私有“属性”。每次执行 javascript 函数都会为局部变量创建一个新的变量环境,一旦执行完成,该环境可能会被垃圾回收。在该范围内声明的每个函数也可以访问这些变量,只要这些函数可以被调用(例如,由事件侦听器调用),环境就必须持久存在。因此,通过从构造函数中导出本地定义的函数,可以使用只能由这些函数访问的局部变量来保留该变量环境。
让我们看看它的实际效果:
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 函数现在被称为“特权方法”,因为它可以访问“私有”(本地)“属性”(变量)。的值永远不会改变。当然,你也可以为它声明一个 setter 函数,并且你可以添加一些验证等。bar
请注意,prototype 对象上的方法无权访问构造函数的局部变量,但它们可能使用特权方法。让我们添加一个:
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
因此,您可以将这两种方法结合起来。请注意,特权方法需要更多的内存,因为您创建具有不同作用域链(但代码相同)的不同函数对象。如果要创建大量实例,则应仅在原型上定义方法。
当你设置从一个“类”到另一个“类”的继承时,它甚至会变得有点复杂——基本上,你必须使子原型对象继承自父原型对象,并在子实例上应用父构造函数以创建“私有属性”。看看正确的javascript继承,继承原型中的私有变量,在JAVASCRIPT模块模式中定义私有字段成员和继承和如何在JS中实现继承揭示原型模式?
评论
this
[
]
[
]
为了更接近 JavaScript 中的 OOP,您可能需要查看模块设计模式(例如,此处描述)。
基于闭包效果,此模式允许模拟对象中的私有属性。
使用“私有”属性,您可以直接通过其标识符引用它们(即,没有像构造函数那样的关键字)。this
但无论如何,JS 中的闭包和设计模式 - 一个高级主题。因此,请熟悉基础知识(在前面提到的书中也有解释)。
评论
在 javascript 中,始终引用函数的所有者对象。例如,如果你在页面中定义你的函数,那么 owner 是 javascript 对象;或者,如果您定义了 on html 元素 ,则所有者是 html 元素主体;同样,如果您定义 element 的函数 onclick ,则所有者就是锚点。this
foo()
windows
foo()
<body>
<a>
在您的例子中,您在开始时将属性分配给“owner”对象,并尝试返回局部变量。bar
bar
由于您从未定义过任何局部变量,因此它为您提供了 bar 未定义。bar
理想情况下,您的代码应该已定义变量,就像您要返回值零一样。var bar;
明确说意味着(正如您已经理解的那样)您对 引用的当前对象的属性感兴趣。因此,如果您使用: 您将把 equals 引用的当前对象的属性设置为 。this.foo
foo
this
this.foo = 'bar';
foo
this
bar
JavaScript 中的关键字并不总是像 C++ 中的关键字一样。这里我可以举个例子:this
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');
在上面的示例中,我们使用函数的上下文调用该函数,因此引用了将由 创建的对象。正如您可能从结果中看到的那样,来自 .使用方法的第一个参数,我们指定调用函数的上下文。Person
Developer
this
Developer
console.log
this
Developer
call
如果不直接使用,则创建的属性将是局部变量。您可能知道,JavaScript 具有函数作用域,因此这就是为什么变量是局部的,仅对声明它的函数可见(当然,所有子函数都在父函数中声明)。下面是一个示例:this
function foo() {
var bar = 'foobar';
this.getBar = function () {
return bar;
}
}
var f = new foo();
console.log(f.getBar()); //'foobar'
当您使用关键字时,这是正确的。这意味着,如果你忘记了,你被定义为局部变量,不幸的是,它将成为全局变量。var
bar
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 作用域优势的另一个示例是模块模式。 在 Module Pattern 中,您可以使用 JavaScript 的本地功能范围来模拟隐私。使用这种方法,您可以同时拥有私有属性和方法。下面是一个示例:
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
*/
无父级包装匿名函数的语法有点奇怪,但暂时忘记它(它只是在初始化后执行函数)。从使用示例中可以看出该功能,但好处主要是提供一个简单的公共接口,该接口不会让您参与所有实现细节。有关该模式的更详细说明,您可以查看我上面的链接。
我希望用:-)信息我帮助您理解了 JavaScript 的一些基本主题。this
function Foo() {
this.bar = 0;
this.getBar = function () { return this.bar };
}
当您使用关键字调用上面的函数时 - 像这样...new
var foo = new Foo();
... - 发生了一些事情:
1) 创建一个
对象 2) 使用引用该对象的关键字执行函数。
3) 返回该对象。this
foo
然后,变成这个对象:
{
bar: 0,
getBar: function () { return this.bar; }
};
那么,为什么不这样做呢:
var foo = {
bar: 0,
getBar: function () { return this.bar; }
};
你会的,如果它只是一个简单的对象。
但是,使用构造函数创建一个对象(这就是它的调用方式)在创建多个“相同”对象方面为我们提供了很大的优势。
看,在 javascript 中,所有函数都是使用原型属性 [对象] 创建的,并且使用该函数创建的所有对象(通过使用 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
就是这样!
这就像对象(变量或函数)的公共访问修饰符,而 var 是私有访问修饰符
例
var x = {};
x.hello = function(){
var k = 'Hello World';
this.m = 'Hello JavaScript';
}
var t = new x.hello();
console.log(t.k); //undefined
console.log(t.m); //Hello JavaScript
评论
.bar
是对象属性,而不是变量。所以是的,要从对象获取属性,您需要通过对该对象的一些引用来实现。如果引用你的对象,那么将给你这个属性。this
this.bar
this.bar
与 不同。但是,您可以这样做,这将作为参考bar
var bar = this.bar
bar
this.bar
this.bar