Giter Site home page Giter Site logo

Comments (43)

seansd-zz avatar seansd-zz commented on July 30, 2024

I suppose you could think of a private field definition of a 'class' as being hooked up to the prototype but not accessible to anything other than the methods of a 'class', and so in turn doing a this.#someProp instance level (own) property overwriting said defined private prototype value. That could work, although would that mean that not using keyword 'this' would set the value for all instances (on it's prototype)? And that still doesn't really solve the issue in example 1 where the 'this' pointer is not actually defined or not an instance of the object in question.

from proposal-class-fields.

loganfsmyth avatar loganfsmyth commented on July 30, 2024

These are existing problems, I don't know that this syntax makes the problem any worse.

The first example is bad news imho, b/c there is no way to know the true value of this

Calling functions with the proper context has always been the responsibility of the user. Agents could certainly make this a clear error message at least, like "method called with improper 'this' value" or something.

I don't think there's really a fix for this. The function call is just a normal function call, there are no other channels of data that would tell you which instance of the class was being used.

The 2nd example is a bit non-sensical, but it is still important

This also already happens now if you extend any type that requires internal slots, like Map or Set. You cannot extend an ES6 class with an ES5-style form without calling the constructor with Reflect.construct and returning that, otherwise you're just not constructing the class correctly.

such as what if a class method itself is a constructor

ES6 method cannot be called as constructors.

from proposal-class-fields.

bakkot avatar bakkot commented on July 30, 2024

I assume that example would just return the empty string value?

Also, attempting to access a private field on a receiver which lacks it will throw an error at runtime.

from proposal-class-fields.

wilmarques avatar wilmarques commented on July 30, 2024

It's a private field, not protected. If you try to access it from another class, it must throw an error.

Also, if this isn't the class, it must throw an error.

from proposal-class-fields.

littledan avatar littledan commented on July 30, 2024

@seansd You can do subclassing here like this to set up the private fields as desired:

function Point3D(x, y, z)
{
     var self = Reflect.construct(Point2D, [x, y], new.target);
     self.z = z;
     return self;
}

Point3D.prototype = Object.create(Point2D.prototype);

from proposal-class-fields.

seansd-zz avatar seansd-zz commented on July 30, 2024

I concur that the fact that this is not necessarily what you'd expect is already a problem, however adding this functionality i feel would exacerbate that problem further, hence the discussion.

You cannot extend an ES6 class with an ES5-style form without calling the constructor with Reflect.construct and returning that, otherwise you're just not constructing the class correctly.

I'm not sure what the spec says, but try it in Chrome right now, it absolutely works, there is nothing forcing an plain old function with prototype that has an ES6 class from being called as a constructor and thereby not calling super. . .

And the options are not ideal:

  • You do nothing, and 'this' is undefined, an pretty cryptic hard to debug error is thrown
  • You do nothing, and 'this' is some other object which does not have a '#str' property
  • You do nothing, and 'this' is some other object which just so happens to have a property called '#str'
  • You do a check in every function to ensure 'this' is what you expect, but that still could be a problem

Another example:

 class Point2D {
         #x  = 0;
         #y = 0;
         #str = '';

         constructor(x, y) {
              this.#x = (typeof x === 'number' && !isNaN(x)) ? x : (Number(x) || 0);
              this.#y = (typeof y === 'number' && !isNaN(y)) ? y : (Number(y) || 0);

              this.#str = this.#x + ', ' + this.#y;
         }

         toString() { 
             let me = this, ret = '';
             if (me && (me instanceof Point2D)) {
                 ret = me.#str;  /* would this work by the way since 'this' is aliased? */
             }
             return ret; //   return this.#str; 
    }

}

function Point3D(x, y, z)
{
       var me = this;
       me.x = x;
       me.y = y;
       me.z = z;
       Object.defineProperty(me, '#str', { configurable: false, enumerable: false, writable:false, value: 'ha ha'});
      return me;
}

Point3D.prototype = Object.create(Point2D.prototype);

var oPoint3D = new Point3D(10, 20, 30);

console.log(oPoint3D);

the this checks in the Point2D.toString method will pass b/c Point3D inherits the prototype, but everything will be wrong.

from proposal-class-fields.

seansd-zz avatar seansd-zz commented on July 30, 2024

In the above example, i suppose that could still work since the toString method would first look at a private value it has access to, and therefore, the Point3D evil property override won't work (that's good), but it still would have only an uninitialized / default value. . . so again I say that we need to find a solution somehow. .. and forcing a user to always validate the 'this' pointer is not great, especially when it's not really easy to validate

from proposal-class-fields.

seansd-zz avatar seansd-zz commented on July 30, 2024

i suppose at the very least you'd have the option of adding another private member to ensure the construtor was called (given my comment above would be correct).

from proposal-class-fields.

bakkot avatar bakkot commented on July 30, 2024

the this checks in the Point2D.toString method will pass b/c Point3D inherits the prototype, but everything will be wrong.

No, they would not. this.#foo attempts to access a private field; it is not equivalent to this['#foo'] (see the FAQ for private fields). And since oPoint3D doesn't have the private field in question, the access in toString would throw an error, presumably with a message like oPoint3D lacks private field #foo.

Edit:

/* would this work by the way since 'this' is aliased? */

Yes, it would; this proposal does not give any new semantics to the this keyword. See FAQ.

from proposal-class-fields.

loganfsmyth avatar loganfsmyth commented on July 30, 2024

I'm not sure what the spec says, but try it in Chrome right now, it absolutely works, there is nothing forcing an plain old function with prototype that has an ES6 class from being called as a constructor and thereby not calling super. . .

I should clarify that with "successfully" I guess :P You can use ES5-style inheritance to inherit the prototype of an ES6 class you want in the prototype chain of an object, but there is no guarantee that it will work. The same is already true in ES5 with Array and any other builtin type.

function Point() { }
Point.prototype = Object.create(Array.prototype);

var a = new Point(1, 2, 3);

a instanceof Array // true
Array.isArray(a); // false

because the object you created isn't actually an array, it's just an object that kind of looks like an array. The same is true for ES6 classes when extended using the ES5 approach. If you want to correctly extend an ES6 class from an ES5 constructor, you need to use Reflect.construct like was mentioned above.

from proposal-class-fields.

seansd-zz avatar seansd-zz commented on July 30, 2024

Right yes I get that (in terms of ES5/ES6 construction), and hence that's my point, b/c that could be done, checking the 'this' pointer to make sure it's an 'instanceof' is not particularly helpful.

If (given my example), an improper inherited object called said method and as a result an error was thrown like you suggest, then (assuming we write that in the spec), I think that would be ok, since developers would not need to constantly do said checks (unless they wanted to silence the error and just default). I want to make sure said messaging is clear though. . .

With that said, I wonder if we could also add something to do said check more easily. . .what does this.hasOwnProperty('#foo') or Object.getOwnPropertyDescriptor(this, '#foo') do inside class methods? Always return false? What about the 'in' operator?

Might be nice to allow developers to check and instead of throwing do something else. . .
if (this && '#foo' in this) { } else { /*return default value, throw custom error, whatever */ } ? Maybe you could ONLY do that with the 'in' operator?

from proposal-class-fields.

bakkot avatar bakkot commented on July 30, 2024

The behavior I described is already what's specified.

In this proposal there's no way to check for a private field except a try - but that works fine. We might want to make it easier eventually, in theory, but I don't think it's necessary to include in the initial thing.

from proposal-class-fields.

loganfsmyth avatar loganfsmyth commented on July 30, 2024

what does this.hasOwnProperty('#foo') or Object.getOwnPropertyDescriptor(this, '#foo')

Those are unchanged. You can already have a property named #foo on an object. This proposal is adding syntax, but there is no visible property added to the object, otherwise they wouldn't be private. e.g.

var obj = {
  "#foo"(){}
};

creates an object with that property name. Because of the usage of quotes, the # is just a character in the property name.

It could potentially work to allow if (#foo in this) as a way for developers to check if a private exists on the given object.

from proposal-class-fields.

seansd-zz avatar seansd-zz commented on July 30, 2024

right, only inside a class method of course :), another question are you required to always access private members via '.' (dot) notation? Or would this['#foo'] still work so long as it's inside a given class method and said field was declared in that class?

from proposal-class-fields.

bakkot avatar bakkot commented on July 30, 2024

You are required to use dot notation - see the faq I linked above.

from proposal-class-fields.

loganfsmyth avatar loganfsmyth commented on July 30, 2024

I also realize my example is tough because #foo would already evaluate to a value, so take

class Example {
  #foo = "prop";
  prop = 4;
  method() {
    if (#foo in this) {}
  }
}

It would actually check that this has a property named prop because #foo evaluates to prop before in runs so my example would not work :P

from proposal-class-fields.

bakkot avatar bakkot commented on July 30, 2024

@loganfsmyth, that's kind of an argument against the shorthand syntax, actually. Albeit a quite weak one.

from proposal-class-fields.

seansd-zz avatar seansd-zz commented on July 30, 2024

Actually your example is still ok, b/c in that case the 'this' pointer still MUST be a constructed instance of Example (and actually an object), it was just defaulted with a value. And as a developer you could just do:

   class Example {
        #foo;
         prop = 4;
         constructor() {
             this.#foo = 'whatever';
         }
         method() {
             if (#foo in this) { } /* false if not constructed, true if constructed, false even if there is a prop called '#foo' unless it was constructed */
        }
}

Would that not work?

I'm not so sure i like requiring DOT notation though, could lead to big code. . .

from proposal-class-fields.

seansd-zz avatar seansd-zz commented on July 30, 2024

In your case if you provided a default value statically for all instances, then it would still return true, but that's ok b/c the developer would have the option. . .(assuming this is actually a proper instance of example)

from proposal-class-fields.

seansd-zz avatar seansd-zz commented on July 30, 2024

and just back to requiring DOT notation, I have worked on 2 separate apps, where we have a ton of code, and we have a job that converts long property names to using [] syntax for size savings which ends up saving over 15% in size without requiring gzip and with basically no discernable run-time penalty. . . so that's a nice thing. . granted it's only useful in very large codebases. . .

from proposal-class-fields.

bakkot avatar bakkot commented on July 30, 2024

The FAQ entry linked above explains our rational for that decision. We are not, in general, particularly concerned with file size, especially uncompressed - but note that this feature allows minifiers to rename private fields safely (because they cannot be accessed from outside the class and because it is possible to statically determine which field is being accessed), which is not possible for public properties.

from proposal-class-fields.

loganfsmyth avatar loganfsmyth commented on July 30, 2024

Actually your example is still ok, b/c in that case the 'this' pointer still MUST be a constructed instance of Example

The issue with my example is that #foo is short for this.#foo meaning that in is executed with the value of the #foo property, so it isn't checking if #foo exists, it is checking if the prop key exists since that is the value of this.#foo.

from proposal-class-fields.

seansd-zz avatar seansd-zz commented on July 30, 2024

The issue with my example is that #foo is short for this.#foo meaning that in is executed with the value of the #foo property, so it isn't checking if #foo exists, it is checking if the prop key exists since that is the value of this.#foo.

Right i get that is the case now, but what i'm saying is that could still be ok if you modify what the 'in' operator does. ..

if statement is (#name in this) , modify the in operator parsing to accept an identifer that is a symbol and not a string that must begin with # on the left side, and on the right side 'this' must be a given object. check if said object on the right side is an object, and a prototype of the given class/function, and check if #name has a defined value in that instance, (which can only happen inside class methods). If #name has a default value that's OK, so long as the object on the right hand side is a prototype of the given object (regardless of whether construction happened, or it was set in some other method, b/c you provided a default value). But if #name had an initial value of undefined, then the in operator would also require that private symbol on the object to have SOME value, and in either case (in the context of a class method) (#name in this) WOULD NEVER look at any properties on the object that are trying to mask (in other words some one doing Object.defineProperty(this '#name', {value:'x'}) doesn't matter b/c in the context of a class method the statement of using (#name in this) always means 'validate the object/private slot`. Would that not work? In short the 'in' operator in a class method WOULD not look at the 'value' of the #foo property beyond checking that there is indeed a value.

Again I'm pointing out that the modified 'in' operator behavior would only apply inside a class method, and therefore would not evaluate a #foo into a string property. . .

from proposal-class-fields.

seansd-zz avatar seansd-zz commented on July 30, 2024

The FAQ entry linked above explains our rational for that decision. We are not, in general, particularly concerned with file size, especially uncompressed - but note that this feature allows minifiers to rename private fields safely (because they cannot be accessed from outside the class and because it is possible to statically determine which field is being accessed), which is not possible for public properties.

Ah good call, a minifier would always be free to change the private property name to something very short since it can only be used inside the given class. . . yeah ok that means this.#myStupidLongPrivatePropName could always become this.#f which would be shorter than ```this[a] /* assuming a = '#f' */. . . Nice

from proposal-class-fields.

seansd-zz avatar seansd-zz commented on July 30, 2024

Also curious would private properties/fields be accessible via arrow functions similar to how super is. . . ?

     class MyObject {
          method() {
               console.log('echo MyObject');
          }
    }

    class MySubObject extends MyObject {
         constructor() {
               super();
               this.foo = () => {
                   super.method(); /* works echo MyObject */
               }
         }
         method() {
             console.log('echo MySubObject');
      }
}

/* as opposed too */

     class MyObject {
          method() {
               console.log('echo MyObject');
          }
    }

    class MySubObject extends MyObject {
         constructor() {
               super();
               this.foo = function() { 
                   super.method(); /* fails, no super  */
               }
         }
         method() {
             console.log('echo MySubObject');
      }
}

So would the same rule apply to privates?

  class MyObject {
          method() {
               console.log('echo MyObject');
          }
    }

    class MySubObject extends MyObject {
         #foo;
          #bar = 100;
         constructor() {
               super();
               this.#foo = () => {
                   console.log(this.#bar); /* works?  echo 10 */
               }
         }
         method() {
             console.log('echo MySubObject');
      }
}

/* as opposed too */

     class MyObject {
          method() {
               console.log('echo MyObject');
          }
    }

    class MySubObject extends MyObject {
         #foo;
         #bar = 10;
         constructor() {
               super();
               this.#foo = function() { 
                   console.log(this.#bar); /* fails? or maybe works b/c it was created inside a class method / constructor? */
               }
         }
         method() {
             console.log('echo MySubObject');
      }
}

from proposal-class-fields.

loganfsmyth avatar loganfsmyth commented on July 30, 2024

modify the in operator parsing to accept an identifer that is a symbol and not a string

The issue is that the in operator already accepts general expressions, so people expect that to be consistent, e.g.

var this_obj = this;
var prop_name = "prop";

(prop_name in this_obj);
("prop" in this);

Those last two behave identically, vs

var this_obj = this;
var prop_name = #foo;

(prop_name in this_obj);
(#foo in this);

which under your proposal would evaluate to two different checks, which would be against general expectations for JS as a language. Alternatively that would mean #foo would behave differently from this.#foo in that one extremely specific case, which seems super confusing.

would private properties/fields be accessible via arrow functions

Yes they are usable from arrows. Someone else can chime in, but I believe they work in any nested scope in the class, as if they were like variables.

from proposal-class-fields.

seansd-zz avatar seansd-zz commented on July 30, 2024

Yeah I get your concern although I also don't think it's that problematic since we are talking about fields inside a class method. . .I suppose you could just do:

     class Example {
          static const #VALID_INSTANCE = Symbol('Example'),
          #foo                = 10,
          #validInstance = false;

          constructor(f) {
                  this.#foo = f;
                  this.#validInstance = Example.#VALID_INSTANCE;
         }

         toString() {
             if (this && this.#validInstance === Example.#VALID_INSTANCE) {
                  return this.#foo;
             }
             return '';
       }
}

It's just a shame that we can't make such handling simpler. . .I suppose you could have a new operator, like if JavaScript had a kindOf operator, similar to instanceof but required the given object is only a prototype of the parent or that it's prototypes are all ES6 class instances. . .

from proposal-class-fields.

seansd-zz avatar seansd-zz commented on July 30, 2024

Another question. . .is there a way to lock a private field / make it read-only later? I think I'm right that you can have them be defined as constants initially (yes/no?), but given the above could I force this.#validInstance to be write-once? (just curious, not sure that there's really a true valid use case).

from proposal-class-fields.

loganfsmyth avatar loganfsmyth commented on July 30, 2024

I think a piece you are missing here is that the prototype is not the important part for this feature. The object must actually be created by running the class constructor. You don't need your check because accessing this.#validInstance on an object that wasn't created by calling the constructor will throw an exception. e.g.

class Example {
  #foo = "value";
  readFoo() {
    return #foo;
  }
}

// returns "value"
(new Example()).readFoo();

// Exception thrown because object does not have a `#foo` field,
// because that field is created when the constructor is executed.
Object.create(Example.prototype).readFoo();

is there a way to lock a private field / make it read-only later

There is not.

from proposal-class-fields.

seansd-zz avatar seansd-zz commented on July 30, 2024

Hmmmm OK that would make sense but if you wanted to handle the given error case of a bad this pointer yourself you'd have to do something like:

   class Example {
          #foo = "value";
          readFoo() {
                   let prvFoo;
                   try {
                         prvFoo = this.#foo;
                   } catch (e) {
                         /*could only be an invalid instance so return a default */
                        return '';
                   }
                   return prvFoo;
          }
}

Again it's just a shame there's no way to make it so that classes that wanted to fail gracefully without throwing could have to implement something like the above in each method. . . but again as long as the error messaging is decent i suppose it solves the bulk problem of folks calling class methods improperly and thereby breaking a function unexpectedly.

Does that also mean that you cannot change a private value for all instances?
For example with a public field you could do:

       class Example {
               foo = "value";
                change() {
                     Example.prototype.foo = "value_" + Math.random();
                 }
        }                         

Could you do Example.prototype.#foo? (Sounds like no since the private field only gets added via construction).

from proposal-class-fields.

loganfsmyth avatar loganfsmyth commented on July 30, 2024

Yeah, the catch would work well as an approach.

Does that also mean that you cannot change a private value for all instances?

There is no scope where a private is common across all instances. Each instance has their own copy of all private fields.

For example with a public field you could do:

For public fields, setting it on the prototype would modify the prototype, but the field set with the class property is unaffected. foo = "value"; is an expression that is attached to the class declaration, it is not stored on the prototype anywhere. In that example, it's the same as

class Example {
  constructor(){
    this.foo = "value";
  }
  change() {
    Example.prototype.foo = "value_" + Math.random();
  }
}

so even through it is on the prototype, references to this.foo will always get the value on "this" because it is at the top of the prototype chain.

Could you do Example.prototype.#foo?

That would throw because Example.prototype does not have that field, the same way my earlier example throws.

from proposal-class-fields.

seansd-zz avatar seansd-zz commented on July 30, 2024

Ok got it, so does a public property definition of the same name as a public field, happening later then just override the given field (assuming the correct this pointer)?

        class Example() {
              foo = 100;
              constructor() {
                  Object.defineProperty(this, 'foo', {value:200 });
              }
             method() {
                  return this.foo; //assuming construction it's 200, otherwise it's 100 unless a sub did somthing
             }

And also I'm guessing that means field definitions can't be getters/setters ie.

       class Example {
                 get #foo() {
                      return 100;
                 }
                 /* well now this is not really a field if it's public, b/c it's just a prototype getter class method */
                 get bar() {
                      return 200;
                }
     }

Or could they?

from proposal-class-fields.

loganfsmyth avatar loganfsmyth commented on July 30, 2024

Ok got it, so does a public property definition of happening later then just override the given field (assuming the correct this pointer)?

Sorry, I don't follow what you're asking there.

And also I'm guessing that means field definitions can't be getters/setters

Correct, they are only values.

from proposal-class-fields.

seansd-zz avatar seansd-zz commented on July 30, 2024

What I'm asking is does a public field automatically become a property (and thereby be configurable, enumerable, etc)?

          class Example {
                foo = 0;
                constructor() {
                      this.foo = 100; // is this also already a property as well as a field? 
                      //can i remove it/redefine it here into a property
                }
                method() {
                    console.log(this.foo);
              }
        }

        class SubExample extends Example {
               foo = 0;
                constructor() {
                     super();
                      this.foo = 200;
                 }
                 method() {
                       console.log(this.foo); //200
                       console.log(super.foo); //100? 200? error? Ideally should be 100
                       super.method(); //console log 100, 200, error? Ideally should be 100 as well i think
                       Object.defineProperty(this, 'foo', { configurable: true, enumerable: true, writable: true, value: 150 }); //allowed? Overwrites field?
                      console.log(this.foo); //150
                      super.method(); //console.log 150 i assume, could one get back to the field value in the super?
                       console.log(super.foo); //200? or would it use the redefined prop, meaning 150?
               }
     }
```

from proposal-class-fields.

bakkot avatar bakkot commented on July 30, 2024

Public fields are properties on the instance, yes. (And not on the prototype.) As you can see in the spec, they're currently writable and enumerable, but not configurable. I'm not sure how set we are on that last part.

In your example:

console.log(super.foo); // undefined, since there is no `foo` on Example.prototype
super.method(); // 200; there is only one property `foo`, and it's redefined to be 200 by `SubExample`'s constructor
Object.defineProperty(...); // fails; the property is not configurable.

In other words, a public field definition class A { f = 0; } is very similar to

class A {
  constructor() {
    Object.defineProperty(this, 'f', {configurable: false, writable: true, enumerable: true, value: 0});
  }
}

This has gotten somewhat off topic, however.

from proposal-class-fields.

loganfsmyth avatar loganfsmyth commented on July 30, 2024

Class fields are normal properties on the class instance, that are set on the instance when the given classes's constructor initializes the instance. super.foo would never return anything in your example because nothing is stored on the prototype. In your example it is, desugarred to ES6

class Example {
  constructor() {
    // foo = 0;
    Object.defineProperty(this, "foo", {
      configurable: false,
      enumerable: true,
      writable: true,
      value: 0,
    });

    this.foo = 100;
  }
  method() {
    console.log(this.foo);
  }
}

class SubExample extends Example {
  constructor() {
    super();
    // foo = 0;
    Object.defineProperty(this, "foo", {
      configurable: false,
      enumerable: true,
      writable: true,
      value: 0,
    });

    this.foo = 200;
  }
  method() {
    console.log(this.foo); // 200

    console.log(super.foo); // undefined

    super.method(); // 200

    // Throws because the property is "configurable: false" already
    // If you changed this to configurable: false it'd work fine
    Object.defineProperty(this, 'foo', {
      configurable: true, // false here would make it work fine
      enumerable: true,
      writable: true,
      value: 150
    });

    console.log(this.foo); // 150, if previous doesn't throw
    super.method(); // 150 again
  }
}

from proposal-class-fields.

seansd-zz avatar seansd-zz commented on July 30, 2024

Yeah it's somewhat off topic but I was just trying to understand if fields are unique to a class. So basically a public field definition on a parent class is forced down to all sub classes as an 'own' prop. (and could even be non-writable).

Anyway I think we can close, so long as we can clearly document then error messaging (eventhough i'd still like a better way to handle a bad 'this' pointer more gracefully, but at least it's better)

from proposal-class-fields.

littledan avatar littledan commented on July 30, 2024

Sorry, what's the error you're concerned about?

from proposal-class-fields.

loganfsmyth avatar loganfsmyth commented on July 30, 2024

The error would be the TypeError in PrivateFieldGet and PrivateFieldSet so if you forget to .bind(this) in an event handler or something, it is clear that an incorrect this is the issue.

I'm assuming the error would be like the current behavior for something like

Object.create(Set.prototype).add("foo")

which on Chrome throws

Uncaught TypeError: Method Set.prototype.add called on incompatible receiver #<Set>

but since missing private fields aren't something people are used to, having a good error message for it could easily be helpful. No-one just starting out will know what "incompatible receiver" means. Does JS really specify much in the way of error text for issues at the moment? I don't think I've seen any of that in the spec currently.

from proposal-class-fields.

littledan avatar littledan commented on July 30, 2024

@loganfsmyth Yes, that's the current behavior--it throws a TypeError, but the spec doesn't say exactly what the message is. Descriptive messages are up to the implementations, many of which are actively working on improving things.

Would the error be less unexpected if you had to access private fields through this.#x rather than #x?

from proposal-class-fields.

seansd-zz avatar seansd-zz commented on July 30, 2024

actually what would #x do right now? is that just mean an implied 'this'?

from proposal-class-fields.

littledan avatar littledan commented on July 30, 2024

@seansd Yes.

from proposal-class-fields.

littledan avatar littledan commented on July 30, 2024

OK, it seems like there isn't anything to do about this issue; hopefully the discussion here will be useful for other people trying to understand the proposal. Closing for now.

from proposal-class-fields.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.