2010-04-10 1 views
58

Tôi đã đọc tất cả các nơi mà global variables are bad và lựa chọn thay thế nên được sử dụng. Trong Javascript, tôi nên chọn giải pháp nào.Tôi đã nghe các Biến Toàn cầu Xấu, Tôi nên sử dụng giải pháp thay thế nào?

Tôi đang nghĩ đến việc một chức năng, mà khi ăn hai đối số (function globalVariables(Variable,Value)) trông nếu biến tồn tại trong một mảng địa phương và nếu nó không thiết lập giá trị của nó để Value, khác, VariableValue được nối. Nếu hàm được gọi mà không có đối số (function globalVariables()), nó sẽ trả về mảng. Có lẽ nếu hàm được kích hoạt chỉ với một đối số (function globalVariables(Variable)), hàm này trả về giá trị Variable trong mảng.

Bạn nghĩ sao? Tôi muốn nghe các giải pháp thay thế và các đối số của bạn để sử dụng các biến toàn cục.

Làm thế nào bạn sẽ sử dụng globalVariables();

function append(){ 
    globalVariables("variable1","value1"); //globalVariables() would append variable1 to it's local array. 
}; 

function retrieve(){ 
    var localVariable1 = globalVariables("variable1"); //globalVariables() would return "value1". 
}; 

function retrieveAll(){ 
    var localVariable1 = globalVariables(); //globalVariables() would return the globalVariable()'s entire, local [persistently stored between calls] array. 
}; 

function set(){ 
    globalVariables("variable1","value2"); //globalVariables() would set variable1 to "value2". 
}; 

Đây có phải là một Singleton Pattern BTW?

Trong trường hợp cụ thể này, hàm có thể đặt biến tại một thời điểm và sau đó một hàm khác, có thể khi người dùng gửi biểu mẫu, sẽ cần nhận biến đó. Do đó, hàm đầu tiên không thể truyền biến đó làm đối số cho hàm sau vì nó sẽ không bao giờ được gọi từ hàm đầu tiên.

Cảm ơn bạn, tôi đánh giá cao sự giúp đỡ của bạn!

+9

Tôi không nghĩ rằng bạn hoàn toàn hiểu tại sao họ xấu – Yacoby

+1

@ Yacoby: Tôi nghĩ tôi làm [câu trả lời của Lee giải thích rất nhiều] nhưng nếu bạn cảm thấy khác thì hãy xây dựng. Tôi nên sử dụng giải pháp nào trong kịch bản này? –

+0

Tôi phải đồng ý với @Yacoby tại đây. Bạn đang loại phát minh lại các biến toàn cầu trong ví dụ của bạn, do đó đưa bạn trở lại bước một của "biến toàn cầu là xấu". – Patrick

Trả lời

114

Lý do chính tại sao các biến toàn cục không được khuyến khích trong javascript là vì javascript, tất cả mã chia sẻ một không gian tên toàn cục, cũng javascript ngụ ý các biến toàn cầu. các biến không được khai báo rõ ràng trong phạm vi cục bộ sẽ tự động được thêm vào không gian tên chung. Dựa quá nhiều vào các biến toàn cầu có thể dẫn đến xung đột giữa các tập lệnh khác nhau trên cùng một trang (đọc douglas crockford's articles).

Một cách để giảm các biến toàn cục là sử dụng YUI module pattern. Ý tưởng cơ bản là bao bọc tất cả các mã của bạn trong một hàm trả về một đối tượng chứa các hàm cần được truy cập bên ngoài mô đun của bạn và gán giá trị trả về cho một biến toàn cục đơn lẻ.

var FOO = (function() { 
    var my_var = 10; //shared variable available only inside your module 

    function bar() { // this function not available outside your module 
     alert(my_var); // this function can access my_var 
    } 

    return { 
     a_func: function() { 
      alert(my_var); // this function can access my_var 
     }, 
     b_func: function() { 
      alert(my_var); // this function can also access my_var 
     } 
    }; 

})(); 

để sử dụng các chức năng trong mô-đun của bạn ở nơi khác, sử dụng FOO.a_func(). Bằng cách này để giải quyết xung đột không gian tên toàn cầu, bạn chỉ cần thay đổi tên của FOO.

+0

Điều này thật tuyệt, nó sẽ viết lại toàn bộ mã của tôi nhưng tôi đã hoàn thành nó, tuyệt vời, câu trả lời được chấp nhận. –

+0

Bài viết của crockford mô tả giải pháp của z33m http://www.yuiblog.com/blog/2006/06/01/global-domination/ – ychaouche

+4

heh heh - hai dấu ngoặc cuối cùng là một hình ảnh xác thực! nếu không có chúng, bạn cần phải tham chiếu đến 'FOO(). a_func()'. Ah nó bắt đầu có ý nghĩa bây giờ! – ErichBSchulz

2

Vấn đề với giải pháp của bạn là nó chỉ làm cho bạn mã khó hiểu hơn trong khi vẫn giữ tất cả những nhược điểm của các biến toàn cục. Trang bạn đã liên kết để đề cập đến các vấn đề. Vấn đề duy nhất mà giải pháp đề xuất của bạn thực sự giải quyết là ô nhiễm không gian tên nhưng với chi phí không thể xem các biến toàn cầu được khai báo dễ dàng như khai báo là một cuộc gọi hàm).

Giải pháp là viết mã không có biến toàn cục. Nếu một hàm cần một giá trị, hãy chuyển nó thành một đối số.

+2

... và nếu một đối tượng cần ngữ cảnh, hãy cung cấp nó làm đối số hàm tạo. –

+0

Cảm ơn nhưng trong trường hợp này, các giá trị truyền qua như các đối số sẽ không hoạt động. Tôi cần các biến khác nhau mà vẫn tồn tại lâu dài và có thể truy cập vào một số chức năng. –

2

Bạn thực sự không muốn làm điều này.
Về lý do, xem ví dụ: chức vụ cao nhất ở đây: What is the most EVIL code you have ever seen in a production enterprise environment?

Là một mặt lưu ý, người ta luôn luôn có thể thực hiện "toàn cầu" mã mà không xả rác nơi với globals:

(function() { 
    var notaglobal = 1; 
    alert(notaglobal); 
})(); 
//notaglobal is not defined in this scope   
7

trạng thái toàn cầu gây ra vấn đề trong một số lĩnh vực. Một là tái sử dụng mã. Khi bạn truy cập một số trạng thái toàn cầu có nghĩa là thành phần phải nhận thức được môi trường của nó (một cái gì đó bên ngoài chính nó). Bạn nên tránh điều này càng nhiều càng tốt, bởi vì nó làm cho thành phần không thể đoán trước được.

Giả sử tôi có một đối tượng truy cập chức năng globalVariables của bạn và tôi muốn sử dụng nó trong một trang khác. Làm thế nào để tôi biết để xác định các đối tượng globalVariables hoặc thậm chí làm thế nào để xác định nó? Tuy nhiên nếu bạn có thể chuyển thông tin vào một hàm tạo hoặc như một đối số cho một hàm thì tôi có thể dễ dàng xác định những gì được yêu cầu bởi đối tượng.

Ngoài ra khi bạn truy cập hoặc sửa đổi phạm vi toàn cầu thì bạn có nguy cơ ảnh hưởng đến các đối tượng khác. Đây là lý do tại sao các thư viện như jquery chỉ sử dụng một tên duy nhất trên phạm vi toàn cầu (ít nhất có thể). Nó làm giảm khả năng xung đột với các thư viện khác. Nói cách khác, phạm vi toàn cầu nằm ngoài tầm kiểm soát của bạn, vì vậy nó nguy hiểm.

34

Ngữ nghĩa học của con trai tôi. Ngữ nghĩa.

Bắt đầu với một toàn cầu: myApp = {}; Mọi thứ nên ở trong đó. Ngoại lệ duy nhất sẽ là thư viện AJAX của bạn (có một số ngoại lệ cực đoan như làm việc với các cuộc gọi lại JSONP).

Sẽ có rất ít thuộc tính trong myApp. Bạn sẽ muốn giữ các thuộc tính ứng dụng của mình trong các vùng chứa như cấu hình hoặc các thiết lập.

myApp = { 
    config:{ 
     prop:1 
    }, 
    settings:{ 
     prop:2 
    }, 
    widgets:{ 
     List: function(props){}, 
     Item: function(props){} 
    } 
} 

Sau đó, bạn có thể có nhiều thuộc tính hơn trong các mô-đun, thành phần, singletons và trình tạo lớp thấp hơn (tiện ích con).

Thiết lập này mang lại cho bạn lợi ích bổ sung khi có thể truy cập bất kỳ thuộc tính nào từ bất kỳ vị trí nào khác vì bạn có thể sử dụng nó với myApp toàn cầu. Tuy nhiên, bạn nên sử dụng "này" bất cứ khi nào có thể vì tra cứu nhanh hơn. Và chỉ cần thiết lập trực tiếp tài sản, đừng bận tâm với các công cụ getter/setter giả. Nếu bạn thực sự cần một getter/setter, mã nó cho việc sử dụng cụ thể đó.

Lý do ví dụ của bạn không hoạt động là quá chung chung và dường như bạn đang tìm kiếm lý do để làm việc trong không gian toàn cầu.

Và không thông minh với các biến riêng tư. Chúng cũng xấu: http://clubajax.org/javascript-private-variables-are-evil/

+0

Nhận xét rất tốt và có giá trị. Cảm ơn. – ychaouche

+2

nhận xét tuyệt vời mwilcox. Tôi đã sử dụng bài đăng này để thuyết phục những người khác ở đây tại nơi làm việc này. – Chris

+0

Đây là cách thực hiện. Một toàn cầu duy nhất với tất cả các vars của bạn hoàn toàn phải có thể truy cập trên toàn cầu. +1 – welbornio

2

Sử dụng các biến toàn cục thường là một thực tiễn không tốt, bất kể ngôn ngữ bạn chọn. Họ thậm chí không được phép (dễ dàng) được phép sử dụng khi ở số strict mode, mà tôi thực sự khuyên bạn nên sử dụng.

Hãy xem xét đoạn mã này tôi thấy:

if (typeof session != 'undefined' && !data.cart.request_status) 
    data.input_definitions.passengers = 
    inflate_passenger(session, data.input_definitions.passengers); 

tôi cần phải quay lại và hỏi một lập trình viên felow nơi đã làm biến session này đến từ đâu, vì không tìm kiếm mã xuất hiện nơi được thành lập.

Tôi đã bật một gói khác từ công ty đặt biến toàn cục. Mã nó giống như một trò đùa: nếu bạn cần giải thích nó có lẽ không tốt.

Giải pháp sử dụng ES6:

Nếu tại Node, sử dụng import hoặc require để mang lại những thứ mong muốn vào phạm vi từ vựng, đừng để mọi người chạm vào môi trường toàn cầu của bạn mà bạn không biết nó.

import {Sesssion} from 'api-core'; 
const Session = require('api-core').session; 

Nếu bạn đang ở frontend cung cấp mã cho trình duyệt mà bạn không thể sử dụng import trừ khi bạn transpile đang ES6 bạn sử dụng Babel.

Ví dụ transpiling sử dụng Gulp.js:

// $ npm install --save-dev gulp-babel babel-preset-es2015 

// gulpfile.js 
const gulp = require('gulp'); 
const babel = require('gulp-babel'); 

gulp.task('transpile',() => { 
    return gulp.src('src/app.js') 
    .pipe(babel({presets: ['es2015']})) 
    .pipe(gulp.dest('dist')); 
}); 

// $ gulp transpile 

Legacy workaround:

Khi sử dụng ES6 tính năng không phải là một lựa chọn các cách giải quyết duy nhất để sử dụng một loạt các biến toàn cầu, đang sử dụng chỉ có một và có hy vọng:

// scripts/app.js 
var MyApp = { 
    globals: { 
    foo: "bar", 
    fizz: "buzz" 
    } 
}; 
1

Câu trả lời khác giải thích rõ nhất với chức năng ẩn danh là this article mention,

Chức năng ẩn danh khó gỡ lỗi, duy trì, kiểm tra hoặc sử dụng lại.

Dưới đây là ví dụ về chức năng bình thường. Đọc và hiểu dễ dàng hơn.

/* global variable example */ 
 

 
    var a= 3, b= 6; 
 
    
 
    function fwithglobal(){ 
 
    console.log(a, b); // 3 6 expected 
 
    } 
 
    
 
    fwithglobal(); // first call 
 
    
 
    function swithglobal(){ 
 
    var a=9; 
 
    console.log(a, b); // not 3 6 but 9 6 
 
    } 
 
    
 
    swithglobal(); // second call 
 
    
 

 
/* global variable alternative(function parameter) */ 
 

 
    function altern(){ 
 
    var a= 3, b= 6; // var keyword needed 
 
     f_func(a,b); 
 
     s_func(a,b); 
 
    } 
 
    
 
    function f_func(n, m){ 
 
    console.log(n, m); // 3 6 expected 
 
    } 
 
    
 
    function s_func(n, m){ 
 
    var a=9; 
 
    console.log(n, m); // 3 6 expected 
 
    } 
 
    
 
    altern(); // only once

0

biến toàn cầu đang xấu ... nếu không được quản lý!

Rủi ro tiềm năng của các biến toàn cầu cao tới mức thú vị và năng suất của việc sử dụng các đối tượng thường xuyên sẵn sàng để sử dụng.

Tôi không tin một người nên tìm kiếm một giải pháp thay thế duy nhất. Thay vào đó, tôi ủng hộ một đối tượng chịu trách nhiệm quản lý những hình cầu đó và khi cơ sở mã/thành phần đáo hạn, hãy cấu trúc lại chúng ra

Một điều không được đề cập trong câu trả lời hiện tại. Các địa chỉ này giải quyết được nhiều vấn đề mà mọi người cố gắng giải quyết với các biến toàn cục, nhưng bao gồm những mối quan tâm liên quan đến các hình cầu đơn giản không thể, giống như các vòng đời đối tượng.