2017-04-26 35 views
9

Tôi vừa nhìn thấy một hành vi kỳ lạ của từ khóa this trong môi trường NodeJS. Tôi liệt kê chúng với mã. Tôi đã chạy mã này với NodeJS v6.x, với một tệp JavaScript duy nhất.Đối tượng 'toàn cục' trong NodeJS

Trong khi thử nghiệm với một dòng mã như sau, cho dù có hoặc không có câu lệnh 'use strict', điều này trỏ đến một đối tượng trống {}.

console.log(this) 

Tuy nhiên, khi tôi đang chạy báo cáo kết quả trong vòng một chức năng tự thực hiện như thế nào,

(function(){ 
    console.log(this); 
}()); 

Nó in một đối tượng thực sự lớn. Dường như đối tượng ngữ cảnh thực thi toàn cục được tạo bởi môi trường NodeJS.

Và trong khi thực hiện các chức năng trên với một tuyên bố 'use strict', dự kiến ​​nó in undefined

(function(){ 
    'use strict'; 

    console.log(this); 
}()); 

Nhưng, khi làm việc với trình duyệt (tôi đã thử nghiệm chỉ với Chrome), ba ví dụ đầu tiên mang lại đối tượng window và người cuối cùng đã cung cấp undefined như mong đợi.

Hành vi của trình duyệt khá dễ hiểu. Nhưng, trong trường hợp của NodeJS, nó không tạo ra bối cảnh thực thi, cho đến khi tôi gói trong một hàm?

Vì vậy, hầu hết mã trong NodeJS chạy với một ô trống toàn cầuobject?

+1

Hãy xem: http://stackoverflow.com/questions/22770299/meaning-of-this-in-node-js-modules-and-functions –

Trả lời

11

Trong khi trong trình duyệt phạm vi toàn cầu là đối tượng window, trong nodeJS phạm vi toàn cầu của mô-đun là chính mô-đun, vì vậy khi bạn xác định biến trong phạm vi toàn cầu của mô-đun nodeJS của bạn, nó sẽ là cục bộ cho mô-đun này .

Bạn có thể đọc thêm về nó trong NodeJS documentation nơi nó nói:

toàn cầu

<Object> The global namespace object.

Trong trình duyệt, phạm vi cấp cao nhất là phạm vi toàn cầu. Điều đó có nghĩa rằng trong các trình duyệt nếu bạn đang ở trong thế giới phạm vi var một cái gì đó sẽ xác định một biến toàn cầu . Trong Node.js, điều này khác. Phạm vi cấp cao nhất là không phải phạm vi toàn cầu; var một cái gì đó bên trong một mô-đun Node.js sẽ là địa phương cho mô-đun đó.

Và trong mã của bạn khi bạn viết:

  • console.log(this) trong một tập tin js rỗng (mô-đun) nó sẽ in một đối tượng rỗng {} đề cập đến mô-đun có sản phẩm nào của bạn.
  • console.log(this); bên trong một hàm tự cách gọi, this sẽ trỏ đến nodeJS toàn cầu đối tượng phạm vi, trong đó có tất cả NodeJS thuộc tính và các phương pháp thông thường như require(), module, exports, console ...
  • console.log(this) với strict mode bên trong một hàm tự cách gọi nó sẽ in undefined như một chức năng tự gọi không có đối tượng phạm vi cục bộ mặc định trong Strict mode.
2

Rất thú vị:

var JSON = require('circular-json'); 

console.log('1) ' + JSON.stringify(this, null, 2)); 

(function(){ 
    console.log('2) ' + JSON.stringify(this, null, 2)); 
}()); 

(function(){ 
    'use strict'; 
    console.log('3) ' + JSON.stringify(this, null, 2)); 
}()); 

sẽ sản xuất:

1) {} 


2) { 
    "global": "~", 
    "process": { 
    "title": "node", 
    "version": "v6.9.1", 
    "moduleLoadList": [ 
     "Binding contextify", 
     "Binding natives", 
     "NativeModule events", 
     "NativeModule util", 
     "Binding uv", 
     "NativeModule buffer", 
     "Binding buffer", 
     "Binding util", 
     "NativeModule internal/util", 
     "NativeModule timers", 
     "Binding timer_wrap", 
     "NativeModule internal/linkedlist", 
     "NativeModule assert", 
     "NativeModule internal/process", 
     "Binding config", 
     "NativeModule internal/process/warning", 
     "NativeModule internal/process/next_tick", 
     "NativeModule internal/process/promises",                            
     "NativeModule internal/process/stdio",                             
     "Binding constants",                                 
     "NativeModule path",                                 
     "NativeModule module",                                 
     "NativeModule internal/module",                               
     "NativeModule vm",                                  
     "NativeModule fs",                                  
     "Binding fs",                                   
     "NativeModule stream",                                 
     "NativeModule _stream_readable",                              
     "NativeModule internal/streams/BufferList",                            
     "NativeModule _stream_writable",                              
     "NativeModule _stream_duplex",                               
     "NativeModule _stream_transform",                              
     "NativeModule _stream_passthrough",                              
     "Binding fs_event_wrap",                                
     "NativeModule console",                                 
     "Binding tty_wrap",                                  
     "NativeModule tty",                                  
     "NativeModule net",                                  
     "NativeModule internal/net",                               
     "Binding cares_wrap",                                 
     "Binding tcp_wrap",                                  
     "Binding pipe_wrap",                                 
     "Binding stream_wrap",                                 
     "Binding signal_wrap"                                 
    ],                                      
    "versions": {                                    
     "http_parser": "2.7.0",                                 
     "node": "6.9.1",                                  
     "v8": "5.1.281.84",                                  
     "uv": "1.9.1",                                   
     "zlib": "1.2.8",                                  
     "ares": "1.10.1-DEV",                                 
     "icu": "57.1",                                   
     "modules": "48",                                  
     "openssl": "1.0.2j"                                  
    },                                      
    "arch": "x64",                                   
    "platform": "linux",                                  
    "release": {                                    
     "name": "node",                                   
     "lts": "Boron",                                   
     "sourceUrl": "https://nodejs.org/download/release/v6.9.1/node-v6.9.1.tar.gz", 
     "headersUrl": "https://nodejs.org/download/release/v6.9.1/node-v6.9.1-headers.tar.gz" 
    }, 
    "argv": [ 
     "/usr/local/bin/node", 
     "/home/froth/freelancer-projects/thistest.js" 
    ], 
    "execArgv": [], 
    "env": { 
     "NVM_DIR": "/home/froth/.nvm", 
     "LD_LIBRARY_PATH": "/opt/opencascade/lib", 
     "CSF_UnitsDefinition": "/opt/opencascade/src/UnitsAPI/Units.dat", 
     "CSF_GraphicShr": "/opt/opencascade/lib/libTKOpenGl.so", 
     "CSF_EXCEPTION_PROMPT": "1", 
     "LANG": "de_DE.UTF-8", 
     "PROFILEHOME": "", 
     "DISPLAY": ":0", 
     "SHELL_SESSION_ID": "09b6f0f3b1d94c5f8aba3f8022075677", 
     "NODE_PATH": "/usr/lib/node_modules", 
     "COLORTERM": "truecolor", 
     "NVM_CD_FLAGS": "", 
     "MOZ_PLUGIN_PATH": "/usr/lib/mozilla/plugins", 
     "CSF_IGESDefaults": "/opt/opencascade/src/XSTEPResource", 
     "CSF_XCAFDefaults": "/opt/opencascade/src/StdResource", 
     "XDG_VTNR": "1", 
     "PAM_KWALLET5_LOGIN": "/tmp/kwallet5_froth.socket", 
     "CSF_STEPDefaults": "/opt/opencascade/src/XSTEPResource", 
     "XDG_SESSION_ID": "c2", 
     "CSF_XSMessage": "/opt/opencascade/src/XSMessage", 
     "USER": "froth", 
     "DESKTOP_SESSION": "/usr/share/xsessions/awesome", 
     "GTK2_RC_FILES": "/home/froth/.gtkrc-2.0", 
     "PWD": "/home/froth/freelancer-projects", 
     "HOME": "/home/froth", 
     "XDG_SESSION_TYPE": "x11", 
     "CSF_PluginDefaults": "/opt/opencascade/src/StdResource", 
     "XDG_DATA_DIRS": "/usr/local/share/:/usr/share/:/var/lib/snapd/desktop", 
     "NVM_IOJS_ORG_MIRROR": "https://iojs.org/dist", 
     "KONSOLE_DBUS_SESSION": "/Sessions/1", 
     "XDG_SESSION_DESKTOP": "", 
     "CSF_StandardDefaults": "/opt/opencascade/src/StdResource", 
     "CSF_StandardLiteDefaults": "/opt/opencascade/src/StdResource", 
     "MMGT_CLEAR": "1", 
     "KONSOLE_DBUS_WINDOW": "/Windows/1", 
     "CSF_UnitsLexicon": "/opt/opencascade/src/UnitsAPI/Lexi_Expr.dat", 
     "GTK_MODULES": "canberra-gtk-module", 
     "MAIL": "/var/spool/mail/froth", 
     "NVM_RC_VERSION": "", 
     "CSF_XmlOcafResource": "/opt/opencascade/src/XmlOcafResource", 
     "TERM": "xterm-256color", 
     "SHELL": "/bin/bash", 
     "KONSOLE_DBUS_SERVICE": ":1.23", 
     "XDG_SESSION_CLASS": "user", 
     "XDG_SEAT_PATH": "/org/freedesktop/DisplayManager/Seat0", 
     "XDG_CURRENT_DESKTOP": "", 
     "QT_LINUX_ACCESSIBILITY_ALWAYS_ON": "1", 
     "KONSOLE_PROFILE_NAME": "Shell", 
     "CASROOT": "/opt/opencascade", 
     "NVM_NODEJS_ORG_MIRROR": "https://nodejs.org/dist", 
     "COLORFGBG": "15;0", 
     "XDG_SEAT": "seat0", 
     "SHLVL": "2", 
     "LANGUAGE": "", 
     "WINDOWID": "29360134", 
     "LOGNAME": "froth", 
     "DBUS_SESSION_BUS_ADDRESS": "unix:path=/run/user/1000/bus", 
     "XDG_RUNTIME_DIR": "/run/user/1000", 
     "CSF_MDTVTexturesDirectory": "/opt/opencascade/src/Textures", 
     "XAUTHORITY": "/home/froth/.Xauthority", 
     "XDG_SESSION_PATH": "/org/freedesktop/DisplayManager/Session1", 
     "PATH": "/home/froth/.gem/ruby/2.3.0/bin:/usr/local/sbin:/usr/local/bin:/usr/bin:/snap/bin:/usr/lib/jvm/default/bin:/opt/opencascade/bin:/usr/bin/site_perl:/usr/bin/vendor_perl:/usr/bin/core_perl", 
     "CSF_LANGUAGE": "us", 
     "CSF_SHMessage": "/opt/opencascade/src/SHMessage", 
     "OLDPWD": "/home/froth", 
     "_": "/usr/local/bin/node" 
    }, 
    "pid": 4658, 
    "features": { 
     "debug": false, 
     "uv": true, 
     "ipv6": true, 
     "tls_npn": true, 
     "tls_alpn": true, 
     "tls_sni": true, 
     "tls_ocsp": true, 
     "tls": true 
    }, 
    "_needImmediateCallback": false, 
    "execPath": "/usr/local/bin/node", 
    "debugPort": 5858, 
    "_events": { 
     "SIGWINCH": [ 
     null, 
     null 
     ] 
    }, 
    "_eventsCount": 4, 
    "domain": null, 
    "_exiting": false, 
    "config": { 
     "target_defaults": { 
     "cflags": [], 
     "default_configuration": "Release", 
     "defines": [], 
     "include_dirs": [], 
     "libraries": [] 
     }, 
     "variables": { 
     "asan": 0, 
     "debug_devtools": "node", 
     "force_dynamic_crt": 0, 
     "gas_version": "2.23", 
     "host_arch": "x64", 
     "icu_data_file": "icudt57l.dat", 
     "icu_data_in": "../../deps/icu-small/source/data/in/icudt57l.dat", 
     "icu_endianness": "l", 
     "icu_gyp_path": "tools/icu/icu-generic.gyp", 
     "icu_locales": "en,root", 
     "icu_path": "deps/icu-small", 
     "icu_small": true, 
     "icu_ver_major": "57", 
     "node_byteorder": "little", 
     "node_enable_d8": false, 
     "node_enable_v8_vtunejit": false, 
     "node_install_npm": true, 
     "node_module_version": 48, 
     "node_no_browser_globals": false, 
     "node_prefix": "/", 
     "node_release_urlbase": "https://nodejs.org/download/release/", 
     "node_shared": false, 
     "node_shared_cares": false, 
     "node_shared_http_parser": false, 
     "node_shared_libuv": false, 
     "node_shared_openssl": false, 
     "node_shared_zlib": false, 
     "node_tag": "", 
     "node_use_bundled_v8": true, 
     "node_use_dtrace": false, 
     "node_use_etw": false, 
     "node_use_lttng": false, 
     "node_use_openssl": true, 
     "node_use_perfctr": false, 
     "node_use_v8_platform": true, 
     "openssl_fips": "", 
     "openssl_no_asm": 0, 
     "shlib_suffix": "so.48", 
     "target_arch": "x64", 
     "uv_parent_path": "/deps/uv/", 
     "uv_use_dtrace": false, 
     "v8_enable_gdbjit": 0, 
     "v8_enable_i18n_support": 1, 
     "v8_inspector": true, 
     "v8_no_strict_aliasing": 1, 
     "v8_optimized_debug": 0, 
     "v8_random_seed": 0, 
     "v8_use_snapshot": true, 
     "want_separate_host_toolset": 0 
     } 
    }, 
    "stdout": { 
     "connecting": false, 
     "_hadError": false, 
     "_handle": { 
     "bytesRead": 0, 
     "_externalStream": {}, 
     "fd": 9, 
     "writeQueueSize": 0, 
     "owner": "~process~stdout" 
     }, 
     "_parent": null, 
     "_host": null, 
     "_readableState": { 
     "objectMode": false, 
     "highWaterMark": 16384, 
     "buffer": { 
      "head": null, 
      "tail": null, 
      "length": 0 
     }, 
     "length": 0, 
     "pipes": null, 
     "pipesCount": 0, 
     "flowing": null, 
     "ended": false, 
     "endEmitted": false, 
     "reading": false, 
     "sync": true, 
     "needReadable": false, 
     "emittedReadable": false, 
     "readableListening": false, 
     "resumeScheduled": false, 
     "defaultEncoding": "utf8", 
     "ranOut": false, 
     "awaitDrain": 0, 
     "readingMore": false, 
     "decoder": null, 
     "encoding": null 
     }, 
     "readable": false, 
     "domain": null, 
     "_events": {}, 
     "_eventsCount": 3, 
     "_writableState": { 
     "objectMode": false, 
     "highWaterMark": 16384, 
     "needDrain": false, 
     "ending": false, 
     "ended": false, 
     "finished": false, 
     "decodeStrings": false, 
     "defaultEncoding": "utf8", 
     "length": 0, 
     "writing": false, 
     "corked": 0, 
     "sync": false, 
     "bufferProcessing": false, 
     "writecb": null, 
     "writelen": 0, 
     "bufferedRequest": null, 
     "lastBufferedRequest": null, 
     "pendingcb": 1, 
     "prefinished": false, 
     "errorEmitted": false, 
     "bufferedRequestCount": 0, 
     "corkedRequestsFree": { 
      "next": null, 
      "entry": null 
     } 
     }, 
     "writable": true, 
     "allowHalfOpen": false, 
     "destroyed": false, 
     "_bytesDispatched": 6, 
     "_sockname": null, 
     "_writev": null, 
     "_pendingData": null, 
     "_pendingEncoding": "", 
     "server": null, 
     "_server": null, 
     "columns": 84, 
     "rows": 84, 
     "_type": "tty", 
     "fd": 1, 
     "_isStdio": true 
    }, 
    "stderr": { 
     "connecting": false, 
     "_hadError": false, 
     "_handle": { 
     "bytesRead": 0, 
     "_externalStream": {}, 
     "fd": 11, 
     "writeQueueSize": 0, 
     "owner": "~process~stderr" 
     }, 
     "_parent": null, 
     "_host": null, 
     "_readableState": { 
     "objectMode": false, 
     "highWaterMark": 16384, 
     "buffer": { 
      "head": null, 
      "tail": null, 
      "length": 0 
     }, 
     "length": 0, 
     "pipes": null, 
     "pipesCount": 0, 
     "flowing": null, 
     "ended": false, 
     "endEmitted": false, 
     "reading": false, 
     "sync": true, 
     "needReadable": false, 
     "emittedReadable": false, 
     "readableListening": false, 
     "resumeScheduled": false, 
     "defaultEncoding": "utf8", 
     "ranOut": false, 
     "awaitDrain": 0, 
     "readingMore": false, 
     "decoder": null, 
     "encoding": null 
     }, 
     "readable": false, 
     "domain": null, 
     "_events": {}, 
     "_eventsCount": 3, 
     "_writableState": { 
     "objectMode": false, 
     "highWaterMark": 16384, 
     "needDrain": false, 
     "ending": false, 
     "ended": false, 
     "finished": false, 
     "decodeStrings": false, 
     "defaultEncoding": "utf8", 
     "length": 0, 
     "writing": false, 
     "corked": 0, 
     "sync": true, 
     "bufferProcessing": false, 
     "writecb": null, 
     "writelen": 0, 
     "bufferedRequest": null, 
     "lastBufferedRequest": null, 
     "pendingcb": 0, 
     "prefinished": false, 
     "errorEmitted": false, 
     "bufferedRequestCount": 0, 
     "corkedRequestsFree": { 
      "next": null, 
      "entry": null 
     } 
     }, 
     "writable": true, 
     "allowHalfOpen": false, 
     "destroyed": false, 
     "_bytesDispatched": 0, 
     "_sockname": null, 
     "_writev": null, 
     "_pendingData": null, 
     "_pendingEncoding": "", 
     "server": null, 
     "_server": null, 
     "columns": 84, 
     "rows": 84, 
     "_type": "tty", 
     "fd": 2, 
     "_isStdio": true 
    }, 
    "stdin": { 
     "connecting": false, 
     "_hadError": false, 
     "_handle": { 
     "bytesRead": 0, 
     "_externalStream": {}, 
     "fd": 12, 
     "writeQueueSize": 0, 
     "owner": "~process~stdin", 
     "reading": false 
     }, 
     "_parent": null, 
     "_host": null, 
     "_readableState": { 
     "objectMode": false, 
     "highWaterMark": 0, 
     "buffer": { 
      "head": null, 
      "tail": null, 
      "length": 0 
     }, 
     "length": 0, 
     "pipes": null, 
     "pipesCount": 0, 
     "flowing": null, 
     "ended": false, 
     "endEmitted": false, 
     "reading": false, 
     "sync": false, 
     "needReadable": true, 
     "emittedReadable": false, 
     "readableListening": false, 
     "resumeScheduled": false, 
     "defaultEncoding": "utf8", 
     "ranOut": false, 
     "awaitDrain": 0, 
     "readingMore": false, 
     "decoder": null, 
     "encoding": null 
     }, 
     "readable": true, 
     "domain": null, 
     "_events": {}, 
     "_eventsCount": 4, 
     "_writableState": { 
     "objectMode": false, 
     "highWaterMark": 0, 
     "needDrain": false, 
     "ending": false, 
     "ended": false, 
     "finished": false, 
     "decodeStrings": false, 
     "defaultEncoding": "utf8", 
     "length": 0, 
     "writing": false, 
     "corked": 0, 
     "sync": true, 
     "bufferProcessing": false, 
     "writecb": null, 
     "writelen": 0, 
     "bufferedRequest": null, 
     "lastBufferedRequest": null, 
     "pendingcb": 0, 
     "prefinished": false, 
     "errorEmitted": false, 
     "bufferedRequestCount": 0, 
     "corkedRequestsFree": { 
      "next": null, 
      "entry": null 
     } 
     }, 
     "writable": false, 
     "allowHalfOpen": false, 
     "destroyed": false, 
     "_bytesDispatched": 0, 
     "_sockname": null, 
     "_writev": null, 
     "_pendingData": null, 
     "_pendingEncoding": "", 
     "server": null, 
     "_server": null, 
     "isRaw": false, 
     "isTTY": true, 
     "fd": 0 
    }, 
    "argv0": "node", 
    "mainModule": { 
     "id": ".", 
     "exports": {}, 
     "parent": null, 
     "filename": "/home/froth/freelancer-projects/thistest.js", 
     "loaded": false, 
     "children": [ 
     { 
      "id": "/home/froth/freelancer-projects/node_modules/circular-json/build/circular-json.node.js", 
      "exports": {}, 
      "parent": "~process~mainModule", 
      "filename": "/home/froth/freelancer-projects/node_modules/circular-json/build/circular-json.node.js", 
      "loaded": true, 
      "children": [], 
      "paths": [ 
      "/home/froth/freelancer-projects/node_modules/circular-json/build/node_modules", 
      "/home/froth/freelancer-projects/node_modules/circular-json/node_modules", 
      "/home/froth/freelancer-projects/node_modules", 
      "/home/froth/node_modules", 
      "/home/node_modules", 
      "/node_modules" 
      ] 
     } 
     ], 
     "paths": [ 
     "/home/froth/freelancer-projects/node_modules", 
     "/home/froth/node_modules", 
     "/home/node_modules", 
     "/node_modules" 
     ] 
    } 
    }, 
    "console": {} 
} 


3) undefined 

Trong 3) đây là không xác định vì nó không được autoboxed đến một đối tượng trong chế độ nghiêm ngặt. Điều đó có nghĩa là không có đối tượng gốc trong ngữ cảnh này. Nếu bạn không sử dụng chế độ nghiêm ngặt thì mã của bạn được đóng bởi một phạm vi cha mẹ. Bạn có thể thấy trong đầu ra, bên trong nodejs có rất nhiều thông tin về nội dung của nút.

Trong 1) đầu ra là một đối tượng rỗng vì trong mã cấp cao nhất trong mô-đun nút, điều này tương đương với mô-đun.exports và mô-đun.exports trống trong ví dụ này.

1

Để bắt đầu với documentation trên bối cảnh toàn cầu trong môi trường nút

Trong trình duyệt, phạm vi cấp cao nhất là phạm vi toàn cầu. Điều đó có nghĩa rằng trong các trình duyệt nếu bạn đang ở trong phạm vi toàn cầu, var sẽ định nghĩa một biến toàn cầu. Trong Node.js, điều này khác. Phạm vi cấp cao nhất không phải là phạm vi toàn cầu; var một cái gì đó bên trong một mô-đun Node.js sẽ được địa phương để mô-đun đó.

Mỗi tệp JS được coi là một mô-đun. Nút tự động kết thúc mã của một tệp JS trong một IIFE tự với exports, require, module, __filename, __dirname làm tham số cho hàm.

Dưới đây là ảnh chụp màn hình của bối cảnh thực hiện sử dụng node-debug

node-debug

Nếu bạn chạy vào mã bên dưới, bản in true có nghĩa this đề cập đến exports trong node.js. Giải thích tốt nhất trong số answer này.

console.log(this === exports); 

Có nghĩa là lúc thực thi mã được bọc một cái gì đó tương tự như dưới đây trong Node.js tách mã của bạn từ bối cảnh toàn cầu bằng cách sử dụng chức năng wrapper bối cảnh.

var context = (function (exports, require, module, __filename, __dirname) { 
     console.log(this) //This is my code 
    }); 

    var module = {exports:{}}; 
    context.apply(module.exports, [module.exports, require, module, "FILE_NAME", "DIR_NAME"]); 

trả lời đến điểm tiếp theo tham khảo documentation này hoàn toàn:

của một chức năng từ khóa này cư xử một chút khác nhau trong JavaScript so với các ngôn ngữ khác. Nó cũng có một số khác biệt giữa chế độ nghiêm ngặt và chế độ không nghiêm ngặt.

vì vậy khi bạn thực thi mã này

(function(){ 
    console.log(this); 
}()); 

in các global đối tượng và trong use strict chế độ in undefined


Hãy nhớ rằng:

Trong trình duyệt chức năng không phải là bọc bởi ngữ cảnh hàm IIFE/wrapper như trong nút, được thực thi trực tiếp trên đối tượng window. Do đó ngữ cảnh gọi thay đổi cho Node.js và Trình duyệt.

Đồng thời đọc this.

Các vấn đề liên quan