Function declaration style and variable scope problem

เป็นปัญหาที่ยังไม่สามารถทำให้เกิดขึ้นอีกในโค้ดแบบอื่นได้ แต่เอามาเขียนไว้ก่อนเพราะมันสร้างความปวดหัวให้กับคนเขียน Javascript มาก่อนมากมาย และไม่รู้จะเจอมันอีกทีเหมื่อไหร่ แต่ไม่สามารถเอาโค้ดต้นฉบับทั้งก้อนมาใส่ในนี้ได้ เลยขอแค่เล่าแล้วเอา stacktrace มาแปะใส่ไว้ละกัน

เหตุการณ์เริ่มต้นเกิดจาก @pitiphong_p เจอบั๊กหนึ่งที่ไม่รู็จะแก้อย่างไรเข้าเพราะใน Flash Builder Debugger บอกว่าตัวแปรต่างๆ มีค่าครบสมบุรณ์หมด แต่ error บอกไม่สามารถหาตัวแปรนั้นได้

[Fault] exception, information=TypeError: Error #1010: A term is undefined and has no properties.
Fault, CheckboxListRenderer.as:21
 21            data.selected = checkbox.selected
(fdb) bt
#0   this = [Object 32588233, class='global'].<anonymous>(event=[Object 659079665, class='flash.events::Event']) at CheckboxListRenderer.as:21
#1   EventDispatcher/dispatchEventFunction() at <null>:0
#2   this = [Object 655130785, class='mx.controls::CheckBox'].EventDispatcher/dispatchEvent(_arg1=[Object 659079665, class='flash.events::Event']) at <null>:0
#3   this = [Object 655130785, class='mx.controls::CheckBox'].UIComponent/dispatchEvent(event=[Object 659079665, class='flash.events::Event']) at UIComponent.as:9440
#4   this = [Object 655130785, class='mx.controls::CheckBox'].Button/http://www.adobe.com/2006/flex/mx/internal::setSelected(value=true, isProgrammatic=false) at Button.as:1204
#5   this = [Object 655130785, class='mx.controls::CheckBox'].Button/clickHandler(event=[Object 591642521, class='flash.events::MouseEvent']) at Button.as:2798

ตอนแรกก็พยายามคาดเดาปัญหาไปต่าง ๆ อาจเกิดจากการ bind ตัวแปรผิดที่ หรือตอนกำหนดค่าผิด แต่ถ้าอย่างนั้น ทำไมตอน debug ถึงสามารถเอาค่าออกมาดูได้หละ ลองดูโค้ดเจ้าปัญหาซักนิดก่อนละกัน

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
package sample
{
  import mx.binding.utils.BindingUtils
  import mx.containers.HBox
  import mx.controls.Alert
  import mx.controls.CheckBox
  import mx.core.IFactory
 
  import flash.events.Event
 
  public class CheckboxListRenderer extends HBox {
 
    [Bindable]
    public var listRenderer:IFactory
 
    public var checkbox:CheckBox = new CheckBox()
 
    private var instance:*
 
    private var checkboxChange = function(event:Event):void {
      if (data.hasOwnProperty('selected')) {
        data.selected = checkbox.selected
      }
    }
 
    public override function set data(item:Object):void {
      super.data = item
      if (item && item.hasOwnProperty('selected')) {
        checkbox.selected = item.selected
      }
    }
 
    protected override function createChildren():void {
      super.createChildren()
      addChild(checkbox)
 
      if (listRenderer != null) {
        instance = listRenderer.newInstance()
        addChild(instance)
      }
      trace("Checkbox list renderer created children")
    }
 
    protected override function commitProperties():void {
      super.commitProperties()
      horizontalScrollPolicy = "off"
      verticalScrollPolicy = "off"
 
      // Handle change in targeting phase for changing data selected flag.
      checkbox.addEventListener(Event.CHANGE, checkboxChange)
 
      BindingUtils.bindProperty(instance, "data", this, "data")
    }
 
  }
}

รับรองได้เลยว่าถ้าใครเอาโค้ดด้านบนไปลองเล่นดูเองจะไม่เจอปัญหาแน่นอน ซึ่งถึงวันนี้ยังไม่เข้าใจเหมือนกันว่าทำยังไงถึงจะเกิดปัญหาได้ แต่วิธีแก้นั้นง่ายมากคือ เปลี่ยนวิธีประกาศฟังก์ชั่นจาก

20
21
22
23
24
    private var checkboxChange = function(event:Event):void {
      if (data.hasOwnProperty('selected')) {
        data.selected = checkbox.selected
      }
    }

เป็น

20
21
22
23
24
    private function checkboxChange(event:Event):void {
      if (data.hasOwnProperty('selected')) {
        data.selected = checkbox.selected
      }
    }

ปัญหาทุกอย่างก็หายไปอย่างปริศนา ทิ้งไว้แต่เครื่องหมายคำถามว่าทำไมขอบเขตของฟังก์ชั่นถึงต่างกันเพียงแค่เปลี่ยนรูปแบบการประกาศฟังก์ชั่นเท่านั้น และไม่สามารถทดลองซ้ำกับการเขียนโค้ดแบบง่าย ๆ ได้ แต่หลังจากนี้รู้แล้วว่า จะไม่ประกาศฟังก์ชั่นในรูปแบบตัวแปรอีก เพราะไม่อยากเจอปัญหาแปลกๆ แบบนี้ให้นั่งปวดหัวหาวิธีแก้อีกแล้ว

Tags: , ,

Post Author

This post was written by llun who has written 512 posts on แนท (/næt/).

I'm programmer at Throughwave

3 Responses to “Function declaration style and variable scope problem”

  1. IIUV March 6, 2010 at 10:27 pm #

    เอ๊ะ หรือมันจะเป็น bug ของ Flash builder beta 4???

  2. teerapap.c March 8, 2010 at 2:00 am #

    ผมสงสัยว่า แล้ว checkboxChange แบบที่บอกใช้ไม่ได้อะครับ ถ้าเรียกตรงๆ ไม่ได้เรียกผ่าน eventListener เรียกทำงานได้รึเปล่าครับ?

    • llun March 9, 2010 at 10:08 pm #

      ได้เพราะ scope ตอนเรียกอยู่ในคลาสแล้ว

Leave a Reply