简体   繁体   English

javascript构造函数如何工作

[英]How do javascript constructors work

I'm reading MDN Javascript for beginners and it's saying you can create a constructor function then make object instances based on that constructor. 我正在阅读面向初学者的MDN Javascript,也就是说您可以创建一个构造函数,然后基于该构造函数创建对象实例。 Now you have access to the properties and methods defined in the constructor. 现在,您可以访问在构造函数中定义的属性和方法。 However, then they go on to say only properties and methods defined on the constructor prototype property are available to object instances, at least as I understand. 但是,然后他们继续说,至少在我看来,对象实例只能使用构造函数原型属性上定义的属性和方法。 Can someone clear this up because the instance seems to have access to these with no prototype property defined in the example. 有人可以解决这个问题吗,因为实例似乎可以在示例中未定义prototype属性的情况下访问它们。 Thank you 谢谢

function Person(first, last, age, gender, interests) {
    this.name = {
        first,
        last
    };
    this.age = age;
    this.gender = gender;
    this.interests = interests;
    this.bio = function() {
        alert(this.name.first + ' ' + this.name.last + 
              ' is ' + this.age + ' years old.'+
              ' He likes ' + this.interests[0] +
              ' and ' + this.interests[1] + '.');
        };
        this.greeting = function() {
            alert('Hi! I\'m ' + this.name.first + '.');
        };
    }

    var person1 = new Person('Bob', 'Smith', 32, 'male', ['music', 'skiing']);

    person1['age']
    person1.interests[1]
    person1.bio()
    // etc.

Anything that's attached to the prototype property of a constructor is shared between all instances created using the constructor. 构造函数的prototype属性附带的所有内容均在使用该构造函数创建的所有实例之间共享 The values are the same in all such objects. 在所有此类对象中,值均相同。

The constructor can also attach individual properties to the object being created. 构造函数还可以将各个属性附加到要创建的对象上。 These are specific to the new instance, and are not shared. 这些特定于新实例,并且不共享。

So, Javascript objects work A LOT differently than in other programming languages. 因此,Javascript对象的工作方式与其他编程语言不同。 Well, most mainstream ones anyway. 好吧,无论如何,大多数主流的。

Here's the deal - a Javascript object is really just a dictionary (aka map). 这很重要-一个Javascript对象实际上只是一个字典(又名地图)。 For example: 例如:

var x = {}; // creates a new blank object
x.something = 42; // creates a property on the object and assigns value to it
x['something'] = 15; // Alternate syntax. Assigns to the same property we just created.
x['yo, this is valid too!'] = true; // Yes, this is valid too.

See what I mean? 明白了吗? It's just a dictionary, you can set whatever you want. 它只是一本字典,您可以设置任何所需的内容。 And unset too - that's what the delete operator does. 并且也未设置-这就是delete运算符的作用。

So what about those constructors and prototypes? 那么那些构造函数和原型呢? Well, any function can be used as a constructor. 好吧,任何函数都可以用作构造函数。 When you go like 当你像

var x = new foo();

What really happens is that Javascript creates a new blank object and then calls the foo() while putting the newly created object in this . 真正发生的是,Javascript创建了一个新的空白对象,然后在将新创建的对象放入this同时调用foo() And lo and behold, it kinda looks like a constructor. 瞧,看起来有点像构造函数。

There's actually a little quirk that needs to be mentioned. 实际上有一点需要说明的怪癖。 If the constructor function return sa value, then Javascript uses that instead of the newly created object. 如果构造函数return一个sa值,则Javascript将使用该值而不是新创建的对象。 So if you do this: 因此,如果您这样做:

function foo() {
    this.meaning = 42;
}

var a = new foo();

Then a will contain the blank object that Javascript created for you. 然后a将包含Javascript为您创建的空白对象。 But if you do this: 但是,如果您这样做:

function foo() {
    this.meaning = 42;
    return {nope: 3};
}

var a = new foo();

Then a will contain the {nope : 3} object instead. 然后a将包含{nope : 3}对象。 OK, but that's rarely used. 好的,但是很少使用。

Anyway, where were we? 无论如何,我们在哪里? Ah, yes, prototypes. 啊,是的,原型。 Oh, wait, first another thing needs to be explained. 哦,等等,首先需要解释另一件事。 In Javascript EVERYTHING is an object. 在Javascript中, 一切都是对象。 So, like, these things are completely valid: 因此,这些事情是完全有效的:

var a = 42;
var b = "hello, world";

a.foo = "yay";
b.bar = 10;

And, just to really blow your mind there, functions are objects too . 而且,只是为了真正打动您, 功能也是对象 First class citizens, so to speak. 可以说是头等公民。 This is all valid: 这都是有效的:

function foo() {
}

foo.bar = "baz";

var x = foo;

Yup, you can treat functions just like any other object. 是的,您可以像对待其他任何对象一样对待函数。 You can put them in variables, pass them to other functions in parameters, assign and delete arbitrary properties to them, you name it. 您可以将它们放在变量中,将它们传递给参数中的其他函数,为其分配和删除任意属性,然后对其进行命名。 This is a feature rarely found in other languages, so it's probably the hardest thing to wrap your mind around. 这是其他语言中很少见的功能,因此,这可能是最难解决的问题。 I know my mind was blown when I first understood this. 我知道我一开始就很震惊。

Now we can talk about prototypes. 现在我们可以讨论原型。 You see, every function in Javascript also has a special magical property called prototype . 您会看到,Javascript中的每个函数还具有一个特殊的神奇属性,称为prototype By default, it's set to a blank object. 默认情况下,它设置为空白对象。 But you can set it to another object. 但是您可以将其设置为另一个对象。 Or you can add/delete properties to the existing blank object. 或者,您可以向现有的空白对象添加/删除属性。 It's just another object, nothing fancy about it. 这只是另一个对象,对此没什么幻想。

Furthermore, every object in Javascript has a special magical property called __proto__ . 此外,Javascript中的每个对象都有一个特殊的神奇属性__proto__ Remember that when you call new foo() a new object is created and passed to foo() as this ? 请记住,当你调用new foo()一个新的对象被创建并传递给foo()this Well, that new object has its __proto__ set to whatever foo.prototype was at the time. 好吧,这个新对象的__proto__设置为foo.prototype

Now suppose you do this: 现在假设您这样做:

function foo() {
    this.a = 42;
}

foo.prototype.b = 15;

var x = new foo();

If you then type xa then x has such a property and all is well. 如果您随后输入xax具有这样的属性,一切都很好。 But if you type xb then x doesn't have such a property, and that's where the magic happens. 但是,如果您输入xbx没有这样的属性,这就是发生魔术的地方。 Javascript automatically checks if there is a x.__proto__.b and if there is, returns that! Javascript自动检查是否存在x.__proto__.b ,如果存在,则返回它! And if there isn't, it checks x.__proto__.__proto__.b , etc, until it hits an object with __proto__ == null and then it gives up and just returns undefined since there is no such property. 如果没有,它将检查x.__proto__.__proto__.b等,直到它以__proto__ == null命中一个对象,然后放弃并返回undefined因为没有这样的属性。

On the other hand, when you now do this: 另一方面,当您现在执行此操作时:

x.b = "foobarbaz";

Then the b property is created directly on the x object. 然后,直接在x对象上创建b属性。 The prototype remains unchanged. 原型保持不变。

So this is how you create "inheritance" in Javascript. 因此,这就是在Javascript中创建“继承”的方式。 With the prototypes. 随着原型。 It's different than in your typical class-based language, but no less powerful. 它与典型的基于类的语言不同,但功能同样强大。

There are some other nuances and tricks that could be mentioned, as well copious amounts of examples to help you grok all this, but... I've run out of juice for today. 还可以提及其他一些细微差别和技巧,以及大量示例来帮助您掌握所有这些内容,但是...今天我的果汁已经用光了。 :) This should answer the question as well as hopefully make more sense of whatever other tutorial you are reading. :)这样可以回答问题,并希望您对阅读的其他任何教程有更多的了解。

Jules is right. 朱尔斯是对的。

To go in further detail: You have this constructor. 进一步详细说明:您具有此构造函数。

function Person(first, last, age, gender, interests) {
    this.name = {
        first,
        last
    };
    this.age = age;
    this.gender = gender;
    this.interests = interests;
    this.bio = function() {
        alert(this.name.first + ' ' + this.name.last + ' is ' + this.age + ' years old. He likes ' + this.interests[0] + ' and ' + this.interests[1] + '.');
    };
    this.greeting = function() {
        alert('Hi! I\'m ' + this.name.first + '.');
    };
}

Now you can create to instances of it... 现在您可以创建它的实例了...

var person1 = new Person('Bob', 'Smith', 32, 'male', ['music', 'skiing']);
var person2 = new Person('Anne', 'Smith', 32, 'male', ['music', 'skiing']);

If you access the prototype and change it every other instance will also have this change. 如果访问原型并进行更改,则其他所有实例也将具有此更改。

person1.__proto__.attrX = "Hello World"
alert(person2.attX)

All this Javascript prototype inheritance may be very confusing at first but you actually almost never required. 起初,所有这些Javascript原型继承都可能非常令人困惑,但是实际上您几乎不需要。 I actually wouldn't even recommend it because it is tempting to mess around with. 实际上,我什至不推荐它,因为它很容易弄乱。 For instance you could have the idea to change the prototypes of basic datatypes in JS. 例如,您可能有想法在JS中更改基本数据类型的原型。 For instance like so: 例如这样:

Person.__proto__.arguments = "";

This is very very bad. 这非常非常糟糕。 Especially if you actually wanted to do this: 特别是如果您确实想这样做:

Person.prototype.arguments = "";

If you are not aware of the difference between prototype and __proto__. 如果您不了解原型和__proto__之间的区别。 They are basically the same on different perspectives. 它们在不同的观点上基本相同。

  • __proto__ refers to the constructor of an instance __proto__引用实例的构造函数
  • prototype does the same if you use it on constructors 如果在构造函数上使用原型,原型也会做同样的事情

But because a constructor itself is an instance of function you will always refer to the constructor of function if you call __proto__ on a constructor directly. 但是,因为构造函数本身是函数的实例,所以如果直接在构造函数上调用__proto__,则将始终引用函数的构造函数。 So changing something on the function constructor would change all the function withing JS and this could interfere if you change something so integral to functions such as arguments. 因此,更改函数构造函数中的某些内容将更改带有JS的所有函数,如果您更改了诸如参数之类的函数中不可或缺的内容,则可能会造成干扰。 You see it becomes very nasty if you dive deeper into it... But you can just avoid those things. 如果您深入研究它,它会变得非常讨厌。但是您可以避免这些事情。

javascript对象继承关系

I just learned the javascript object inheritance relationship yesterday and made a graph according to this good description . 我昨天刚刚学习了javascript对象的继承关系,并根据这个良好的描述制作了一个图表。 Hope it is useful to you. 希望对您有用。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM