Why is using let resulting in undefined in a block of code? - ecmascript-6

When running code in a code block it results in 'undefined' then using the 'this' to reference a local variable in a block of code.
The strange thing is when removing the 'this' keyword in the same block, it prints fine.
let productId = 12;
if (true) {
let productId = 10
console.log(this.productId) // results in 'undefined'
console.log(this) //results in '{}'
console.log(productId) // results in '10'
}
Was under the impression that the 'this.productId' would refer directly to the productId in the true code block.

'this' to reference a local variable in a block of code.
That never happens. It just looks that way if "local" and "global" happen to be the same.
Here you can see how it behaves when you use var in a global scope.
var foo = "global";
function myFunction () {
var foo = "local";
console.log(this.foo);
}
myFunction();
And here in strict mode:
"use strict";
var foo = "global";
function myFunction () {
var foo = "local";
console.log(this.foo);
}
myFunction();
The side-effect of using var in the global scope creating a window property of the same name is weird and confusing.
When let was created it wasn't designed to use the same weird and confusing behaviour.
this being window by default is also weird and confusing, and isn't the case in Strict mode.

Related

ActionSctipt 3.0 Error:

I'm having real trouble trying to access the symbol dynamically, I have 9 buttons that all call this method, and they pass in their location (tl, t, tr, etc.) I've tried this method before on another program and it works without a problem, but in this program it fails.
I am attempting to access a symbol call s_tl (example location), but all I'm getting is undefined (see results).
function turn(btn : String):Function {
return function(e:MouseEvent) {
var players_turn : int;
var chosen : String = "s_" + btn;
trace(this);
trace(this[chosen]);
trace(chosen);
trace(this[chosen]);
// if crosses turn 0 else 1
if (s_c.currentFrame == 1) {
players_turn = 0;
} else {
players_turn = 1;
}
// check who's turn it is if it's been pressed before
if (players_turn == 0 && this[chosen].visible == false) {
this[chosen].gotoAndStop(1);
this[chosen].visible = true;
} else {
this[chosen].gotoAndStop(2);
this[chosen].visible = true;
}
};
}
Results:
[object global]
undefined
s_br
undefined
TypeError: Error #1010: A term is undefined and has no properties.
at MethodInfo-6()
Your problem is the bad code style. You define unnamed unbind function inside function turn() and that's where the root of your problem is. Unbind function exist, as your trace shows, in global addressing context and, unlike function turn(), is not bind to any specific display object. Your buttons probably exist on the same addressing context with turn(). Argument btn is available inside unnamed function because ECMA standard instructs so (if function A creates function B then local variables, including arguments, of A are available as local variables in B), but it is a very very very bad practice that makes code messy and induce headaches.
Please explain what you tried to achieve with that code so we could untangle it and rewrite in not-so-twisted way.
Okey, I basically figured you're doing Tic Tac Toe. Now, guideline. A cell must contain 3 frames: 1st frame for the button graphics, 2nd and 3rd for X and O. Name them your way: s_1, s_2, etc.
for (var i:int = 1; i < 10; i++)
{
var aCell:MovieClip = getChildByName("s_" + i) as MovieClip;
aCell.addEventListener(MouseEvent.CLICK, onTic);
}
function onTic(e:MouseEvent):void
{
var playersTurn:int = s_c.currentFrame;
var aCell:MovieClip = e.currentTarget as MovieClip;
trace(aCell.name);
// Now, the magic.
aCell.gotoAndStop(playersTurn + 1);
aCell.removeEventListener(MouseEvent.CLICK, onTic);
}

What does this conf do?

So I was looking at a tutorial online and came across this:
function generateRobot(conf:Object = null):Robot {
var conf:Object = conf || {};
var defaults:Object = {
laserColor:red,
personality: "evil"
}
for (var key:String in defaults){
conf[key] = conf[key] || defaults[key];
}
Can someone help explain what line 2 and line 8 mean? Thanks for helping a new coder!
I have added some comments and renamed the param to make it clearer:
//param is a parameter of the type object with a default value of null that is passed
//into the function, if nothing is passed in it will be null
function generateRobot(param:Object = null):Robot {
//declare a local variable called conf and populate
//it with the parameter if it exists, otherwise create a new object {}
var conf:Object = param || {};
//create a default settings object
var defaults:Object = {
laserColor:red,
personality: "evil"
}
//loop through the default settings
for (var key:String in defaults){
//conf setting becomes param if exists otherwise use the defaults value
conf[key] = conf[key] || defaults[key];
}
The questions seems specific to the || construct in the variable assignment. As #Thilo mentioned, it is simply a way to specify a default, should the field be missing in the parameter.
For example:
function read_file(file, delete_after) {
delete_after = delete_after || "False";
//rest of code
}
would be such that, if variable delete_after is not passed when function read_file is called, then it will assume value "False", or anything after the || sign.
Some prefer an explicit check against undefined.
Other pointers to look at:
Set a default parameter value for a JavaScript function
http://www.codereadability.com/javascript-default-parameters-with-or-operator/

setName vs setId in Google App Script

In 'google script', on trigger of an event (button click), I am trying to change the name as well as Id of a textbox. Following is simplified code:
function addRow(e){
var app = UiApp.getActiveApplication();
app.getElementById('tbox')
.setId('txt1')
.setName('txt1');
}
Now, setId is working but setName is throwing me an error. Is there something that I am obviously missing?
From a quick test I did it seems that, although it does not throw an error if used alone, it is not possible to change an element's id, as shown in this little test:
function doGet() {
var app = UiApp.createApplication().setTitle('Button Test');
return app.add(app.createTextBox().setId('tbox').setName('tbox').setText('tbox')
.addKeyPressHandler(app.createServerHandler('inspectBox'))).add(
app.createButton('Change').addClickHandler(app.createServerHandler('btnClick')));
}
function inspectBox(e) {
var p = e.parameter;
var app = UiApp.getActiveApplication();
return app.add(app.createLabel('id: '+p.source)).add(
app.createLabel('name: '+(p.tbox ? 'tbox' : p.txt1 ? 'txt1' : 'not found')));
}
function btnClick() {
var app = UiApp.getActiveApplication();
app.getElementById('tbox').setId('txt1');
//app.getElementById('tbox').setName('txt1');
return app;
}
Later, if you comment the setId line and uncomment the setName one, then type a char in the textbox, you'll see that the name changes. And the setName call works fine if you continue working on the element using, for example, setText. Which is not true for setId, that fails if you try anything on the element.
Anyway, as commented by others, it's indeed odd that you have such a requirement. I guess you should find another way (possibly a better one) to do what you want (which you have not described).

flash get function's argument name

I want to get all arguments names of a function inside the function
example:
function fct(var1:string,var2:string){
var names:Array=...
trace(names);
}
must trace : var1,var2
Thanks!
Simply put, this is not possible. The closest you can get is the argument number and value. See below:
function fct( ... args ):void {
for ( var v:Object in args ) {
trace( v + ": " + args[v] );
}
}
var str1:String = "this is a test";
var str2:String = "this is another test";
fct( str1, str2 );
//output
//0: this is a test
//1: this is another test
For future reference, you can use ... + a variable name to allow for as many arguments as you need. Regardless, you should just need to access args[ INDEX ] rather than the actual variable name, which you wouldn't be able to access anyway because there would be no way to apply scope (such as variableName[ "propertyName" ])
It is impossible like native method, but you can use metadata tag to set arguments names. I create simple example. But i don't understand how it can help you in real projects:
[Arguments(param1="arg1",param2="arg2")]
public function test(arg1:Number, arg2:Number):void {
var desc_xml:XML = describeType(Object(this).constructor);
var metas_xml:XMLList = desc_xml.factory.method.(#name == "test");
var args_xml:XMLList = metas_xml.metadata.(#name == "Arguments");
for each (var argx:XML in args_xml.arg)
{
trace(argx.#value.toXMLString());
}
};
I use flex 4.6. Don't forget add each existing Metadata tags to the compiler argument with “-keep-as3-metadata+=Arguments”. It need for compile release versions.

JSLint writing constructors that reference static variables

I'm writing a display class in Javascript (using jQuery) which may be instantiated before a web page has loaded. If the page isn't ready when the constructor is called, the instance is added to a static instances field for the class, which is iterated over when the page has loaded:
function MemDisplay(ready_callback) {
this.readyCallback = ready_callback;
if (MemDisplay.ready) {
this.linkToPage();
} else {
MemDislay.instances.push(this);
}
}
//this makes sure that the ready callback can be sent when the page has loaded
MemDisplay.ready = false;
MemDisplay.instances = [];
$(document).ready(function () {
var i;
MemDisplay.ready = true;
for (i = 0; i < MemDisplay.instances.length; i += 1) {
MemDisplay.instances[i].linkToPage();
} });
//example truncated for brevity
When I run this through JSLint, I get this error:
Problem at line 25 character 9:
'MemDislay' is not defined.
MemDislay.instances.push(this);
I need to reference MemDisplay.instances in the constructor, but the constructor is where MemDisplay is defined, so I'm puzzled about how to make this work while fitting within JSLint's guidelines. Is there a better way to do this? Should I just ignore JSLint in this instance?
JSLint here is actually highlighting a broader issue with the code without saying so.
You are referencing a class (MemDisplay) but never instantiating it as an object. I.e. you are treating the class like an already-instantiated object.
I've created a very simple equivalent to what you are trying to achieve (also at this JSFiddle)
function MyClass(p1, p2){
this.param1 = p1; //class member/property - use this to access internally.
if (this.param1 === 1){ //you might want to consider doing this as part of some setter method
alert("test");
}
this.MyMethod = function(){ //class method/function
alert("MyMethod Called");
};
}
var myObj = new MyClass(1,2); //instantiate
alert(myObj.param1); //get value of object member (you can set as well)
myObj.MyMethod(); //call a method
It'll take a bit of reorgansiation, but by declaring the values up front, you can get make JSLint happy.
My brain must have figured this out while I slept: the trick is to attach the field to the prototype, which seems pretty obvious now that I've thought of it, since that's what you have to do to define class methods.
The following checks out in JSLint, and demonstrates the sharing of a field between all instances of MyClass (or see this code on jsfiddle):
/*global alert */
function MyClass(name) {
this.name = name;
MyClass.prototype.field += 1;
}
MyClass.prototype.field = 0;
MyClass.prototype.myMethod = function () {
alert(this.name + "'s class's field is " + MyClass.prototype.field);
};
var myObj = new MyClass("first");
myObj.myMethod();
var myOtherObj = new MyClass("second");
myObj.myMethod();
myOtherObj.myMethod();
I'm not sure if there's a prettier way to do it, as having 'prototype' all over the place feels a bit excessive, on the other hand it could be a good thing because it makes it clear that prototype.field does not belong to the instance.