JavaScript Class set itself - javascript

Its obvious that class properties can have it's own get and set functions.
But what about this?
As I tried so far, its legal to do something like this:
class Bind {
constructor(val) {
this.val = val;
}
set this(val) {
alert('not sure what happens here!');
}
get this() {
return this.val;
}
}
so these lines:
var b = new Bind(123);
b = 456;
should call the setter function, but the alert will never fire.
Any idea what that setter does?

b = 456;
Cause this does not change the previous value of b in any way, it just changes the previously stored reference into a value. A small example of what i mean:
let a = {it: "wont change" };
let b = a;
console.log(a, b);
b = 456;
console.log(a, b);
If rewriting b would change the referenced object in any way, a would change too.
Instead, You can reach the setter with:
b.this = 456;

class Person {
constructor(name) {
this._name = name;
}
get name() {
console.log("getter")
return this._name.toUpperCase();
}
set name(newName) {
console.log("setter")
this._name = newName;
}
}
let bob = new Person('Bob');
console.log(bob.name);// Outputs 'BOB'
bob.name = "new Bob"
console.log(bob.name); // Outputs 'NEW BOB'

Related

How to handle a variable assignment in JavaScript

Let's say I have a variable
let foo = {};
And I'm re-assigning it to something else.
foo = {}
The question is how do I know that the variable is re-assigned ?
Like I've heard about Proxy, but it doesn't work
// Creating a variable
let foo = {}
// Setting up a proxy
const fooProxy = new Proxy(foo, _ => {
get: function(...) { ... },
set: function(...) { ... }
}
// I just re-assigned the variable, and I want that `notify()` to tell me about it.
foo = {}
// I wanna call this function when the variable changes, but it doesn't work
function notify(){
console.log("Dude, your variable has changed!");
There's a few examples but I guess it comes down to purpose? If means are to secure variables from changing, that likely won't happen but you can get as close with call-backs and promises/etc.
class User {
constructor(name) {
this.name = name;
this.skill = "novice";
}
setSkill(newSkill) {
this.skill = newSkill;
this.alertChange()
}
alertChange(){
console.log(this.name+ " OH NO, My Skill!!!! No SECURITY HERE I GUESS?");
}
}
let Test = new User("Donny");
Test.setSkill("Egg Champion");
let test = undefined;
let test2 = undefined;
let watchvalue = 0;
function RepeatTillReady() {
clearTimeout(test);
clearTimeout(test2);
test = setTimeout(()=>{
if (watchvalue == 100) {
console.log("That took a while but we made it!");
} else {
RepeatTillReady();
}
}, 200);
test2 = setTimeout(()=>{
watchvalue++;
console.log("counting slowly now"+watchvalue);
}, 100);
}
RepeatTillReady();
Here's another fun example when trying to catch DOM load in browsers! :)

Is there any point to use getters/setters for an object?

It seems to me that using getters and setters for an object inside a class has no point to it. As I understand it, get/set is useful because it prevents someone outside the class changing something that shouldn't be changed or changing it to something it shouldn't be. However it seems pointless for objects. For example, I have a person with an address, I want to prevent editing the address, you can only view it:
class Person{
constructor(name, address){
this._name = name;
this._address = address;
}
get address(){
return this._address;
}
}
let bob = new Person("bob", {
street: "123 Main Street",
city: "Los Angelos",
state: "California"
});
But then you can still edit it like this:
let address = bob.address;
address.state = "New York";
To prevent this, I would think that you have to return a copy of the object instead of the reference. However, as far as i know, there is no standard way to deep clone an object. So you either have to shallow clone it, which seems not ideal if you have lots of nested references, or just return the reference to the object, which can be edited.
Am I missing something here?
Consider this class.
class Test {
constructor(val) {
this._foo = val;
}
set foo(val) {
throw new Error("It's not possible to change the foo property!")
}
set boo(val) {
console.log("setting _boo")
this._boo = val;
}
get foo() {
console.log("getting _foo");
return this._foo;
}
}
try {
let test = new Test('foooooo');
test.boo = "booooo";
console.log(`foo: ${test.foo}`);
test.foo = "bar";
} catch (e) {
console.log(e);
}
With "Setter" it's possible to control initializing properties.
You can see that it's possible to change the value of "boo" property but any attempt to change the value of the "foo" will throw an exception.
With "Getter" it's possible to control retrieving the value of properties.
You can see that it's possible to retrieve the value of "foo" property but not "boo" and its value is private.
PS:
Here are some examples to better understand JS behavior with objects and arrays:
//This works fine:
//Object
const obj = {};
obj.foo = 'bar';
console.log(obj); // {foo : 'bar'}
obj.foo = 'bar2';
console.log(obj); // {foo : 'bar2'}
//---------------------------------------
//Array:
const arr = [];
arr.push('foo');
console.log(arr); // ['foo']
arr.unshift("foo2");
console.log(arr); // ['foo2', 'foo']
arr.pop();
console.log(arr); // ['foo2']
//===========================================
//but these won't work:
const obj = {};
obj = {foo: 'bar'}; // error - re-assigning
const arr = ['foo'];
const arr = ['bar']; // error - re-declaring
const foo = 'bar';
foo = 'bar2'; // error - can not re-assign
var foo = 'bar3'; // error - already declared
function foo() {}; // error - already declared
New Example:
class A {
constructor(val) {
this._foo = val;
}
set foo(val) {
throw new Error("It's not possible to change the foo property!")
}
get foo() {
return this._foo;
}
}
class B {
constructor(val) {
this._obj = new A(val);
}
get Obj() {
return this._obj;
}
}
let b = new B('Test');
b.Obj.foo = 'new value';
console.log(b.Obj.foo);
In this manner, it's not possible to change the values ​​of the internal object.

create setter in Javascript

I want to create a setter in JS. But there is something wrong with my code, and this is my code:
class test {
constructor(str) {
this.name = str;
}
set name(str) {
this.sayHi();
}
sayHi() {
let temp = this.name;
console.log(`My name is ${temp}`)
}
}
let a = new test('bill') //My name is undefined
a.sayHi() //My name is undefined
why does it console undefined in this example?how to make it work?
Your setter needs to store the value somewhere; you'll also need a getter to get the value from that place.
Here's a simple example storing the value in another property:
class Test {
constructor(str) {
this._name = str; // ***
// (You might use `this.name = str` here, setters are sometimes
// considered an exception to the "don't call methods in the
// constructor" rule)
}
set name(str) {
this._name = str; // ***
}
get name() { // ***
return this._name; // ***
} // ***
sayHi() {
let temp = this.name;
console.log(`My name is ${temp}`)
}
}
let a = new Test('bill') //My name is undefined
a.sayHi() //My name is undefined
Of course, if you're going to do that, it doesn't make a lot of sense to have a setter, but that's getting a bit afield of the question...
Note: I changed the name of your class to Test (instead of test). The overwhelming convention in JavaScript is that class names (really constructor function names) are initially-capitalized.
Try this instead:
class test {
constructor(str) {
this.name = str;
}
set name(str) {
this._name = str
}
sayHi() {
let temp = this.name;
console.log(`My name is ${temp}`)
}
get name() {
return this._name
}
}

Dynamical inheritance TypeScript

JavaScript permit dynamical inheritance. I was wondering if TypeScript take it into account. The following code might illustrate the problem.
// inheritance.js
function fn1() {
this.a = "fn1";
}
function fn2() {
// ...
}
let f1 = new fn1(); // "instance" of fn1
let f2 = new fn2(); // "instance" of fn2
// inheritance
f2.__proto__ = f1;
// f2.a inherits from f1
console.log(f2.a); // output: "fn1"
As you can see we add an object f1, which is an instance of fn1, in the prototype chain of f2.
My question is therefore the following: can we reproduce this behave in TypeScript by using classes?
How would I change the following code to have the expected output?
// inheritance.ts
class class1 {
public a: string = "class1";
}
class class2 extends class1 {
// ...
}
let c1 = new class1();
let c2 = new class2();
console.log(c1.a); // output: "class1"
// this line would not work
c2.__proto__ = c1;
// change value c1.a
c1.a = "dynamical inheritance test";
console.log(c2.a); // should print value of c1.a (i.e "dynamical inheritance test")
I think what you are looking for is like an intersection mixing. There's a simple example found at the typescript docs. To do what you want, you, you can basically just assign the mixing's resulting class to the to inheriting class, then copy all properties of the class you want to be the extending to the result:
function extendDynamic<T, U>(first: T, second: U): T & U {
let result = <T & U>{};
(<any>result) = (<any>first);
for (let it in second) {
if (second.hasOwnProperty(it)) {
(<any>result)[it] = (<any>second[it]);
}
}
return result;
}
class Class1 {
public a: string;
constructor(n: string) {
this.a = n;
}
}
class Class2 {
b: string = 'bbb';
}
const a = new Class1("bar");
const b = extendDynamic(a, new Class2());
a.a = 'foo';
console.log(b.a, b.b); // foo, bbb

Multiple inheritance console output

I am using below code. I'm getting wrong output console with my code. Right now i am getting "this is aB" but i required constructor related output on my output console. Like "this is aA" for first, "this is aB" for second, "this is aC" for third console.
function A () {
this.name = "A";
}
A.prototype.a = function () {
console.log("this is a"+this.name);
}
function B () {
this.name = "B";
}
B.prototype.b = function () {
console.log("this is b"+this.name);
}
function C() {
this.name = "C";
A.call(this);
B.call(this);
}
C.prototype = Object.assign({}, A.prototype, B.prototype);
C.prototype.constructor = C;
C.prototype.c = function () {
console.log("this is c"+this.name);
}
var x = new C();
x.a(); //this is aB
x.b(); //this is bB
x.c(); //this is cB
this in all three constructors refers to the same object: The one created by the new operator. That one object can only have one name property. So whichever constructor you call last will "win" and the name will be assigned by that. Thus, you're seeing B all the time because even with new C, first C writes C, then A writes A (overwriting C), and finally B writes B (overwriting A).
If you want the code related to each level in the hierarchy to have its own name property, you cannot literally do that, but you can get close by having each one use its own property (e.g., nameA, nameB, and nameC). You can do this in a way that doesn't require you to remember which level you're writing the code at by using brackets notation and a variable shared by all the code for each level.
I'm not recommending that. Whatever the actual problem you're trying to solve is, there's probably a better solution.
But here's how you'd do it:
var A = (function() {
var name = "nameA"; // <== We declare a variable and put this level's property name in it
function A() {
this[name] = "A"; // <== Note we're using brackets notation here
}
A.prototype.a = function() {
console.log("this is a: " + this[name]); // <== Brackets again here
};
return A;
})();
var B = (function() {
var name = "nameB"; // <== Same again for B
function B () {
A.call(this);
this[name] = "B";
}
B.prototype = Object.create(A.prototype);
B.prototype.constructor = B;
B.prototype.b = function() {
console.log("this is b: " + this[name]);
};
return B;
})();
var C = (function() {
var name = "nameC";
function C() {
B.call(this);
this[name] = "C";
}
C.prototype = Object.create(B.prototype);
C.prototype.constructor = C;
C.prototype.c = function() {
console.log("this is c: " + this[name]);
};
return C;
})();
var x = new C();
x.a(); //this is aA
x.b(); //this is bB
x.c(); //this is cC
<!-- Script provides the `snippet` object, see http://meta.stackexchange.com/a/242144/134069 -->
<script src="//tjcrowder.github.io/simple-snippets-console/snippet.js"></script>
The one object all three constructors work with will end up with three properties: nameA, nameB, and nameC.
Again, I'm not recommending that, just pointing out that it's possible, and can suit some problems, although it's unclear whether it suits yours.
That was 2016. Here in 2020, you'd probably solve this with private fields. You can use them with a transpiler now and support is being actively added to JavaScript engines:
// NOTE: Only works in environments that support private fields (such as
// modern Chromium-based browsers)
class A {
#name; // <== Private field, only accessible to A's code
constructor() {
this.#name = "A";
}
a() {
console.log("this is a: " + this.#name);
}
}
class B extends A {
#name; // <=== Private field, only accessible to B's code
constructor() {
super();
this.#name = "B";
}
b() {
console.log("this is b: " + this.#name);
}
}
class C extends B {
#name; // <=== Private field, only accessible to C's code
constructor() {
super();
this.#name = "C";
}
c() {
console.log("this is c: " + this.#name);
}
}
const x = new C();
x.a(); // tthis is a: A
x.b(); // tthis is b: B
x.c(); // tthis is c: C
The one object created by new C will have a different private #name field for each class.

Categories

Resources