function Fubar (foo, bar) { this._foo = foo; this._bar = bar; } var snafu = new Fubar("Situation Normal", "All Fsked Up");
new
keyword, we get a new object, and the context of its constructor is set on the object itself. If we explicitly do not return anything from the constructor, then we get the object itself as a result. Thus, the body of the constructor function is used to initialize the newly created object, the prototype of which is the contents of the prototype
property of the constructor, so you can write as follows: Fubar.prototype.concatenated = function () { return this._foo + " " + this._bar; } snafu.concatenated() //=> 'Situation Normal All Fsked Up'
instanceof
operator, you can verify that the object was created using a specific constructor: snafu instanceof Fubar //=> true
instanceof
“wrong” possible in cases with more advanced idioms, or if you are a harmful troll collecting exception programming language and enjoying it, torturing job seekers with them. However, for our purposes, instanceof
works quite well.)new
keyword? var fubar = Fubar("Fsked Up", "Beyond All Recognition"); fubar //=> undefined
fubar
will be undefined. This is not what we need, even worse, because: _foo //=> 'Fsked Up'
function Fubar (foo, bar) { "use strict" this._foo = foo; this._bar = bar; } Fubar("Situation Normal", "All Fsked Up"); //=> TypeError: Cannot set property '_foo' of undefined
new
keyword are a potential problem.new
, the pseudo-variable this
points to a new instance of our so-called “class”. This can be used to determine whether the constructor was called with the code word new
. function Fubar (foo, bar) { "use strict" var obj, ret; if (this instanceof Fubar) { this._foo = foo; this._bar = bar; } else return new Fubar(foo, bar); } Fubar("Situation Normal", "All Fsked Up"); //=> { _foo: 'Situation Normal', _bar: 'All Fsked Up' }
new
? One of the problems that this approach solves is the impossibility of calling new Fubar(...)
. Consider an example: function logsArguments (fn) { return function () { console.log.apply(this, arguments); return fn.apply(this, arguments) } } function sum2 (a, b) { return a + b; } var logsSum = logsArguments(sum2); logsSum(2, 2) //=> 2 2 4
logsArguments
decorates the function that logs its arguments, returning the result of its call. Let's try to do the same with Fubar
: function Fubar (foo, bar) { this._foo = foo; this._bar = bar; } Fubar.prototype.concatenated = function () { return this._foo + " " + this._bar; } var LoggingFubar = logsArguments(Fubar); var snafu = new LoggingFubar("Situation Normal", "All Fsked Up"); //=> Situation Normal All Fsked Up snafu.concatenated() //=> TypeError: Object [object Object] has no method 'concatenated'
snafu
is an instance of LoggingFubar
, not Fubar
. But if you use auto-inheritance in Fubar
: function Fubar (foo, bar) { "use strict" var obj, ret; if (this instanceof Fubar) { this._foo = foo; this._bar = bar; } else { obj = new Fubar(); ret = Fubar.apply(obj, arguments); return ret === undefined ? obj : ret; } } Fubar.prototype.concatenated = function () { return this._foo + " " + this._bar; } var LoggingFubar = logsArguments(Fubar); var snafu = new LoggingFubar("Situation Normal", "All Fsked Up"); //=> Situation Normal All Fsked Up snafu.concatenated() //=> 'Situation Normal All Fsked Up'
snafu
is an instance of Fubar
, not LoggingFubar
. It is impossible to say for sure whether this is what we wanted. This method cannot be called a more than useful abstraction, not devoid of leaks, just as one cannot say that it “just works”, although thanks to it some things become possible which are much more difficult to implement with other approaches.instanceof
. function Fubar (foo, bar) { "use strict" if (this instanceof Fubar) { this._foo = foo; this._bar = bar; } else return arguments[0] instanceof Fubar; } var snafu = new Fubar("Situation Normal", "All Fsked Up"); snafu //=> { _foo: 'Situation Normal', _bar: 'All Fsked Up' } Fubar({}) //=> false Fubar(snafu) //=> true
var arrayOfSevereProblems = problems.filter(Fubar);
new
keyword. Let him"use strict"
helps, but this is not a panacea. In this mode, an error will not be generated if you do not try to write the value to the global scope, and if we try to do something before writing the same value, it will happen no matter what. function Fubar (foo, bar) { "use strict" if (!(this instanceof Fubar)) { throw new Error("Fubar needs to be called with the new keyword"); } this._foo = foo; this._bar = bar; } Fubar("Situation Normal", "All Fsked Up"); //=> Error: Fubar needs to be called with the new keyword
"use strict"
. If you need to make a check on your own instanceof
, you can wrap it in a constructor as a function method: Fubar.is = function (obj) { return obj instanceof Fubar; } var arrayOfSevereProblems = problems.filter(Fubar.is);
new
keyword can pose a potential threat. This can be avoided in three ways: by auto-inheritance, using overloaded functions and forcibly throwing an error in case of an incorrect call.Source: https://habr.com/ru/post/237959/
All Articles