struct Person { char *firstName; char *lastName; int yearOfBirth; } // Compute person's age in a given year. void computeAge(struct Person *person, int currentYear); // Set a new last name, possibly deallocating the old one. void setLastName(struct Person *person, char *newLastName);
class Person { char *firstName; char *lastName; int yearOfBirth; void computeAge(int currentYear); void setLastName(char *newLastName); }
struct Person *p = malloc(sizeof(*p)); setLastName(p, "Poupkine"); printf("Person's age is %d\n", computeAge(p, 2013));
Person *p = new Person; p->setLastName("Poupkine"); printf("Person's age is %d\n", p->computeAge(2013));
setLastName
, computeAge
(behavior) to change or poll the state of an object (state). We can access the created object at any time through the pointer p (identity). If we create another Person *m = new Person
object Person *m = new Person
, then we can use the methods of the new object, accessing it through the pointer m. Pointers p and m will point to different objects, each with its own state, albeit with the same set of methods (behavior).struct Person
Data data structure and friendly functions somewhere nearby. In another case, we syntactically put both data and functions into the same class Person
. class Person { // computeAge setLastName: private: char *firstName; char *lastName; int yearOfBirth; // () : public: void computeAge(int currentYear); void setLastName(char *newLastName); }
ponyComputeAge()
, for the other personComputeAge()
. In the C ++ version, we can simply remember that calculating the age of any object is done through computeAge()
. That is, we introduce a single interface for calculating the age, and use it as an application to many objects. It's comfortable. function createPerson(first, last, born) { var person = { firstName: first, lastName: last, yearOfBirth: born }; return person; } function computeAge(p, currentYear) { return currentYear - p.yearOfBirth; } function setLastName(p, newLastName) { p.lastName = newLastName; } // Create a new person and get their age: var p = createPerson("Anne", "Hathaway", 1982); console.log(p); console.log(computeAge(p, 2013));
node
program (having previously installed the Node.JS project) and see what it displays.setLastName()
and computeAge()
methods “inside” the object. By this we will “unload” the global namespace, we will not litter it: function createPerson(first, last, born) { var computeAgeMethod = function(p, currentYear) { return currentYear - p.yearOfBirth; } var setLastNameMethod = function(p, newLastName) { p.lastName = newLastName; } var person = { firstName: first, lastName: last, yearOfBirth: born, computeAge: computeAgeMethod, setLastName: setLastNameMethod }; return person; } // Create a new person and get their age: var p = createPerson("Anne", "Hathaway", 1982); // Note the p.computeAge(p) syntax, instead of just computeAge(p). console.log(p.computeAge(p, 2013)); console.log(p["computeAge"](p, 2013));
createPerson
inwards. The body of the function has not changed. That is, each function still expects an argument p
, with which it will work. The method of calling these methods has not changed much: yes, instead of calling the computeAge
global function, you need to call the method of the p.computeAge
object, but the function still expects p
first argument.this
. If the function is called by itself ( f()
), then this variable points to a global object (in the browser it will be a window
). But if the function is called through a point, as a method of an object, ( pf()
), then it will be passed a pointer to this object p as this. Since we will still be forced to call methods through a call to the corresponding fields of the object ( p.computeAge
), this
will already exist in the methods and set to the correct value of p
. Rewrite the code using this knowledge. Also try copying it to the node
. function createPerson(first, last, born) { var computeAgeMethod = function(currentYear) { return currentYear - this.yearOfBirth; } var setLastNameMethod = function(newLastName) { this.lastName = newLastName; } var person = { firstName: first, lastName: last, yearOfBirth: born, computeAge: computeAgeMethod, setLastName: setLastNameMethod }; return person; } // Create a new person and get their age: var p = createPerson("Anne", "Hathaway", 1982); console.log(p.computeAge(2013));
createPerson
function has the following disadvantage: it does not work very fast and spends a lot of memory every time an object is created. Each time you call createPerson
JavaScript constructs two new functions, and assigns them as values to the “computeAge” and “setLastName” fields.setLastName
and setLastName
fields, but the person.computeAge()
and person.setLastName()
methods still work?node
: var obj1 = { "a": "aVar" }; var obj2 = { "b": "bVar" }; obj1 obj2 obj2.a obj2.b obj2.__proto__ = obj1; obj1 obj2 obj2.a obj2.b
obj2
is the prototype of the object obj1
, then obj2
“properties” of the object obj1
“appear”, such as the field “a” with the value “aVar”. At the same time, printing obj2
will not show the presence of the “a” attribute in the object.createPerson
transform so as to use this prototype: function createPerson(first, last, born) { var person = { firstName: first, lastName: last, yearOfBirth: born }; person.__proto__ = personPrototype; return person; } var personPrototype = { "computeAge": function(currentYear) { return currentYear - this.yearOfBirth; }, // "setLastName": function(newLastName) { this.lastName = newLastName; } } // Create a new person and get their age: var p = createPerson("Anne", "Hathaway", 1982); console.log(p); console.log(p.computeAge(2013));
node
. Notice which simple object, without its own methods, is shown via console.log(p)
. And that this simple object still has a computeAge
method.__proto__
very new, and may not be supported by browsers. The second drawback is that even if we no longer clutter up the namespace with the functions computeAge
and setLastName
we still bogged it down with the name personPrototype
.f()
, but through new f()
(compare with C ++ or Java!), Then two things happen:f()
accessible from inside function this
points simply to the global context; that is, wherever the window
shows in the browser, or global
from Node.JS. var f = function() { console.log(this); }; f() // , : console.log(window)
pf()
, then this function will already show this object p on this object. But if the function is called via new f()
, then a fresh empty object {}
will be created, and this
within the function will already be pointed to it. Try node: var f = function() { }; console.log({ "a": "this is an object", "f": f }.f()); console.log(new f());
.prototype
. The object on which the .prototype
attribute is .prototype
will automatically become the prototype of the newly created object from item 1.node
: var fooProto = { "foo": "prototype!" }; var f = function() { }; (new f()).foo // undefined f.prototype = fooProto; (new f()).foo // "prototype!"
__proto__
supernova attribute is equivalent to this more traditional code: function createPerson(first, last, born) { this.firstName = first; this.lastName = last; this.yearOfBirth = born; } createPerson.prototype = { "computeAge": function(currentYear) { return currentYear - this.yearOfBirth; }, // "setLastName": function(newLastName) { this.lastName = newLastName; } } // Create a new person and get their age: var p = new createPerson("Anne", "Hathaway", 1982); console.log(p); console.log(p.computeAge(2013));
createPerson.prototype
, but simply set the required fields separately. This idiom can also be found in industrial JavaScript code: createPerson.prototype.computeAge = function(currentYear) { return currentYear - this.yearOfBirth; } createPerson.prototype.setLastName = function(newLastName) { this.lastName = newLastName; }
createPerson
function instead of simple and clear function createPerson(first, last, born) { var person = { firstName: first, lastName: last, yearOfBirth: born }; return person; }
this
: function createPerson(first, last, born) { this.firstName = first; this.lastName = last; this.yearOfBirth = born; }
firstName
, lastName
) into argument values ( first
, last
) is suitable for variants with a very small number of arguments. But for large and spreading configurations, the manual listing of attributes becomes inconvenient and unnecessarily verbose. function createPerson(first, last, born) { var person = { firstName: first, lastName: last, yearOfBirth: born }); $.extend(this, person); }
function createPerson(person) { $.extend(this, person); } var p = new createPerson({ firstName: "Anne", lastName: "Hathaway", yearOfBirth: 1982 }); console.log(p);
jQuery
, this code is easiest to try in the browser, and not in the terminal with the node
.) function Person(person) { $.extend(this, person); } Person.prototype.computeAge = function(currentYear) { return currentYear - this.yearOfBirth; } Person.prototype.setLastName = function(newLastName) { this.lastName = newLastName; } var anne = new Person({ firstName: "Anne", lastName: "Wojcicki", yearOfBirth: 1973 }); var sergey = new Person({ firstName: "Sergey", lastName: "Brin", yearOfBirth: 1973 }); console.log(anne); console.log(sergey);
Person
function is sometimes called a class. For example, you can say: “Person has a method computeAge”.Source: https://habr.com/ru/post/171731/
All Articles