搜索
首页web前端js教程现代 JavaScript 开发编程风格Idiomatic.js指南中文版_javascript技巧

你为项目所择风格都应为最高准则。作为一个描述放置于你的项目中,并链接到这个文档作为代码风格一致性、可读性和可维护性的保证。

一、空白

1.永远都不要混用空格和Tab。
2.开始一个项目,在写代码之前,选择软缩进(空格)或者 Tab(作为缩进方式),并将其作为最高准则。
a).为了可读, 我总是推荐在你的编辑中设计2个字母宽度的缩进 — 这等同于两个空格或者两个空格替代一个 Tab。
3.如果你的编辑器支持,请总是打开 “显示不可见字符” 这个设置。好处是:
a).保证一致性
b).去掉行末的空格
c).去掉空行的空格
d).提交和对比更具可读性

二、美化语法

A. 小括号, 花括号, 换行

复制代码 代码如下:

// if/else/for/while/try 通常都有小括号、花括号和多行
// 这有助于可读

// 2.A.1.1
// 难辨语法(cramped syntax)的例子

if(condition) doSomething();

while(condition) iterating++;

for(var i=0;i

// 2.A.1.1
// 使用空格来提升可读性

if ( condition ) {
  // 语句
}

while ( condition ) {
  // 语句
}

for ( var i = 0; i   // 语句
}

// 更好的做法:

var i,
  length = 100;

for ( i = 0; i   // 语句
}

// 或者...

var i = 0,
  length = 100;

for ( ; i   // 语句
}

var prop;

for ( prop in object ) {
  // 语句
}

if ( true ) {
  // 语句
} else {
  // 语句
}


B. 赋值, 声明, 函数 ( 命名函数, 函数表达式, 构建函数 )
复制代码 代码如下:

// 2.B.1.1
// 变量
var foo = "bar",
  num = 1,
  undef;

// 字面量标识:
var array = [],
  object = {};

// 2.B.1.2
// 在一个作用域(函数)内只使用一个 `var` 有助于提升可读性
// 并且让你的声明列表变得有条不紊 (还帮你省了几次键盘敲击)

// 不好
var foo = "";
var bar = "";
var qux;

// 好
var foo = "",
  bar = "",
  quux;

// 或者..
var // 对这些变量的注释
foo = "",
bar = "",
quux;

// 2.B.1.3
// `var` 语句必须总是在各自作用域(函数)顶部
// 同样适应于来自 ECMAScript 6 的常量

// 不好
function foo() {

  // 在变量前有语句

  var bar = "",
    qux;
}

// 好
function foo() {
  var bar = "",
    qux;

  // 所有语句都在变量之后
}
// 2.B.2.1
// 命名函数声明
function foo( arg1, argN ) {

}

// 使用方法
foo( arg1, argN );

// 2.B.2.2
// 命名函数声明
function square( number ) {
  return number * number;
}

// 使用方法
square( 10 );

// 非常不自然的连带传参(continuation passing)风格
function square( number, callback ) {
  callback( number * number );
}

square( 10, function( square ) {
  // 回调内容
});

// 2.B.2.3
// 函数表达式
var square = function( number ) {
  // 返回有价值的、相关的内容
  return number * number;
};

// 带标识符的函数表达式
// 这种首选形式有附加的功能让其可以调用自身
// 并且在堆栈中有标识符
var factorial = function factorial( number ) {
  if ( number     return 1;
  }

  return number * factorial( number-1 );
};

// 2.B.2.4
// 构造函数声明
function FooBar( options ) {

  this.options = options;
}

// 使用方法
var fooBar = new FooBar({ a: "alpha" });

fooBar.options;
// { a: "alpha" }

C. 异常, 细节

复制代码 代码如下:

// 2.C.1.1
// 带回调的函数
foo(function() {
  // 注意:在第一函数调用的小括号和 `function` 处并没有空格
});

// 函数接受 `array` 作为参数,没有空格
foo([ "alpha", "beta" ]);

// 2.C.1.2
// 函数接受 `object` 作为参数,没有空格
foo({
  a: "alpha",
  b: "beta"
});

// 函数接受 `string` 字面量作为参数,没有空格
foo("bar");

// 分组用的小括号内部,没有空格
if ( !("foo" in obj) ) {

}


D. 一致性(统一)总是笑到最后的(Consistency Always Wins)

在 2.A-2.C 节,留白作为一个推荐方式被提出,基于单纯的、更高的目的:统一。值得注意的是格式化偏好,像“内部留白”必须是可选的,但在整个项目的源码中必须只存在着一种。

复制代码 代码如下:

// 2.D.1.1

if (condition) {
  // 语句
}

while (condition) {
  // 语句
}

for (var i = 0; i   // 语句
}

if (true) {
  // 语句
} else {
  // 语句
}


E. 引号

无论你选择单引号还是双引号都无所谓,在 JavaScript 中它们在解析上没有区别。而绝对需要强制的是一致性。 永远不要在同一个项目中混用两种引号,选择一种,并保持一致。

F. 行末和空行

留白会破坏区别并使用变更不可读。考虑包括一个预提交的 hook 自动删除行末和空行中的空格。

三、类型检测 (来源于 jQuery Core Style Guidelines)

A. 直接类型(实际类型,Actual Types)

String:

复制代码 代码如下:

typeof variable === "string"

Number:
复制代码 代码如下:

typeof variable === "number"

Boolean:
复制代码 代码如下:

typeof variable === "boolean"

Object:
复制代码 代码如下:

typeof variable === "object"

Array:
复制代码 代码如下:

Array.isArray( arrayLikeObject )
(如果可能的话)

Node:
复制代码 代码如下:

elem.nodeType === 1

null:
复制代码 代码如下:

variable === null

null or undefined:
复制代码 代码如下:

variable == null

undefined:

全局变量:

复制代码 代码如下:

typeof variable === "undefined"

局部变量:
复制代码 代码如下:

variable === undefined

属性:
复制代码 代码如下:

object.prop === undefined
object.hasOwnProperty( prop )
"prop" in object

B. 转换类型(强制类型,Coerced Types)

考虑下面这个的含义...

给定的 HTML:

复制代码 代码如下:

// 3.B.1.1

// `foo` 已经被赋予值 `0`,类型为 `number`
var foo = 0;

// typeof foo;
// "number"
...

// 在后续的代码中,你需要更新 `foo`,赋予在 input 元素中得到的新值

foo = document.getElementById("foo-input").value;

// 如果你现在测试 `typeof foo`, 结果将是 `string`
// 这意味着你在 if 语句检测 `foo` 有类似于此的逻辑:

if ( foo === 1 ) {

  importantTask();

}

// `importantTask()` 将永远不会被执行,即使 `foo` 有一个值 "1"

// 3.B.1.2

// 你可以巧妙地使用 + / - 一元运算符强制转换类型以解决问题:

foo = +document.getElementById("foo-input").value;
//    ^ + 一元运算符将它右边的运算对象转换为 `number`

// typeof foo;
// "number"

if ( foo === 1 ) {

  importantTask();

}

// `importantTask()` 将被调用


对于强制类型转换这里有几个例子:
复制代码 代码如下:

// 3.B.2.1

var number = 1,
  string = "1",
  bool = false;

number;
// 1

number + "";
// "1"

string;
// "1"

+string;
// 1

+string++;
// 1

string;
// 2

bool;
// false

+bool;
// 0

bool + "";
// "false"
// 3.B.2.2

var number = 1,
  string = "1",
  bool = true;

string === number;
// false

string === number + "";
// true

+string === number;
// true

bool === number;
// false

+bool === number;
// true

bool === string;
// false

bool === !!string;
// true
// 3.B.2.3

var array = [ "a", "b", "c" ];

!!~array.indexOf("a");
// true

!!~array.indexOf("b");
// true

!!~array.indexOf("c");
// true

!!~array.indexOf("d");
// false

// 值得注意的是上述都是 "不必要的聪明"
// 采用明确的方案来比较返回的值
// 如 indexOf:

if ( array.indexOf( "a" ) >= 0 ) {
  // ...
}
// 3.B.2.3

var num = 2.5;

parseInt( num, 10 );

// 等价于...

~~num;

num >> 0;

num >>> 0;

// 结果都是 2

// 时刻牢记心底, 负值将被区别对待...

var neg = -2.5;

parseInt( neg, 10 );

// 等价于...

~~neg;

neg >> 0;

// 结果都是 -2
// 但是...

neg >>> 0;

// 结果即是 4294967294

四、对比运算

复制代码 代码如下:

// 4.1.1
// 当只是判断一个 array 是否有长度,相对于使用这个:
if ( array.length > 0 ) ...

// ...判断真伪, 请使用这种:
if ( array.length ) ...

// 4.1.2
// 当只是判断一个 array 是否为空,相对于使用这个:
if ( array.length === 0 ) ...

// ...判断真伪, 请使用这种:
if ( !array.length ) ...

// 4.1.3
// 当只是判断一个 string 是否为空,相对于使用这个:
if ( string !== "" ) ...

// ...判断真伪, 请使用这种:
if ( string ) ...

// 4.1.4
// 当只是判断一个 string 是为空,相对于使用这个:
if ( string === "" ) ...

// ...判断真伪, 请使用这种:
if ( !string ) ...

// 4.1.5
// 当只是判断一个引用是为真,相对于使用这个:
if ( foo === true ) ...

// ...判断只需像你所想,享受内置功能的好处:
if ( foo ) ...

// 4.1.6
// 当只是判断一个引用是为假,相对于使用这个:
if ( foo === false ) ...

// ...使用叹号将其转换为真
if ( !foo ) ...

// ...需要注意的是:这个将会匹配 0, "", null, undefined, NaN
// 如果你 _必须_ 是布尔类型的 false,请这样用:
if ( foo === false ) ...

// 4.1.7
// 如果想计算一个引用可能是 null 或者 undefined,但并不是 false, "" 或者 0,
// 相对于使用这个:
if ( foo === null || foo === undefined ) ...

// ...享受 == 类型强制转换的好处,像这样:
if ( foo == null ) ...

// 谨记,使用 == 将会令 `null` 匹配 `null` 和 `undefined`
// 但不是 `false`,"" 或者 0
null == undefined

总是判断最好、最精确的值,上述是指南而非教条。

复制代码 代码如下:

// 4.2.1
// 类型转换和对比运算说明

// 首次 `===`,`==` 次之 (除非需要松散类型的对比)

// `===` 总不做类型转换,这意味着:

"1" === 1;
// false

// `==` 会转换类型,这意味着:

"1" == 1;
// true

// 4.2.2
// 布尔, 真 & 伪

// 布尔:
true, false

// 真:
"foo", 1

// 伪:
"", 0, null, undefined, NaN, void 0

五、实用风格

复制代码 代码如下:

// 5.1.1
// 一个实用的模块

(function( global ) {
  var Module = (function() {

    var data = "secret";

    return {
      // 这是一个布尔值
      bool: true,
      // 一个字符串
      string: "a string",
      // 一个数组
      array: [ 1, 2, 3, 4 ],
      // 一个对象
      object: {
        lang: "en-Us"
      },
      getData: function() {
        // 得到 `data` 的值
        return data;
      },
      setData: function( value ) {
        // 返回赋值过的 `data` 的值
        return ( data = value );
      }
    };
  })();

  // 其他一些将会出现在这里

  // 把你的模块变成全局对象
  global.Module = Module;

})( this );

// 5.2.1
// 一个实用的构建函数

(function( global ) {

  function Ctor( foo ) {

    this.foo = foo;

    return this;
  }

  Ctor.prototype.getFoo = function() {
    return this.foo;
  };

  Ctor.prototype.setFoo = function( val ) {
    return ( this.foo = val );
  };

  // 不使用 `new` 来调用构建函数,你可能会这样做:
  var ctor = function( foo ) {
    return new Ctor( foo );
  };

  // 把我们的构建函数变成全局对象
  global.ctor = ctor;

})( this );

六、命名

A. 你并不是一个人肉 编译器/压缩器,所以尝试去变身为其一。

下面的代码是一个极糟命名的典范:

复制代码 代码如下:

// 6.A.1.1
// 糟糕命名的示例代码

function q(s) {
  return document.querySelectorAll(s);
}
var i,a=[],els=q("#foo");
for(i=0;i
毫无疑问,你写过这样的代码 —— 希望从今天它不再出现。

这里有一份相同逻辑的代码,但拥有更健壮、贴切的命名(和一个可读的结构):

复制代码 代码如下:

// 6.A.2.1
// 改善过命名的示例代码

function query( selector ) {
  return document.querySelectorAll( selector );
}

var idx = 0,
  elements = [],
  matches = query("#foo"),
  length = matches.length;

for ( ; idx   elements.push( matches[ idx ] );
}


一些额外的命名提示:
复制代码 代码如下:

// 6.A.3.1
// 命名字符串

`dog` 是一个 string

// 6.A.3.2
// 命名 arrays

`['dogs']` 是一个包含 `dog 字符串的 array

// 6.A.3.3
// 命名函数、对象、实例,等

camlCase; function 和 var 声明

// 6.A.3.4
// 命名构建器、原型,等

PascalCase; 构建函数

// 6.A.3.5
// 命名正则表达式

rDesc = //;

// 6.A.3.6
// 来自 Google Closure Library Style Guide

functionNamesLikeThis;
variableNamesLikeThis;
ConstructorNamesLikeThis;
EnumNamesLikeThis;
methodNamesLikeThis;
SYMBOLIC_CONSTANTS_LIKE_THIS;


B. 面对 this

除使用众所周知的 call 和 apply 外,总是优先选择 .bind( this ) 或者一个功能上等价于它的。创建 BoundFunction 声明供后续调用,当没有更好的选择时才使用别名。

复制代码 代码如下:

// 6.B.1
function Device( opts ) {

  this.value = null;

  // 新建一个异步的 stream,这个将被持续调用
  stream.read( opts.path, function( data ) {

    // 使用 stream 返回 data 最新的值,更新实例的值
    this.value = data;

  }.bind(this) );

  // 控制事件触发的频率
  setInterval(function() {

    // 发出一个被控制的事件
    this.emit("event");

  }.bind(this), opts.freq || 100 );
}

// 假设我们已继承了事件发送器(EventEmitter) ;)

当不能运行时,等价于 .bind 的功能在多数现代 JavaScript 库中都有提供。

复制代码 代码如下:

// 6.B.2

// 示例:lodash/underscore,_.bind()
function Device( opts ) {

  this.value = null;

  stream.read( opts.path, _.bind(function( data ) {

    this.value = data;

  }, this) );

  setInterval(_.bind(function() {

    this.emit("event");

  }, this), opts.freq || 100 );
}

// 示例:jQuery.proxy
function Device( opts ) {

  this.value = null;

  stream.read( opts.path, jQuery.proxy(function( data ) {

    this.value = data;

  }, this) );

  setInterval( jQuery.proxy(function() {

    this.emit("event");

  }, this), opts.freq || 100 );
}

// 示例:dojo.hitch
function Device( opts ) {

  this.value = null;

  stream.read( opts.path, dojo.hitch( this, function( data ) {

    this.value = data;

  }) );

  setInterval( dojo.hitch( this, function() {

    this.emit("event");

  }), opts.freq || 100 );
}


提供一个候选,创建一个 this 的别名,以 self 作为标识符。这很有可能出 bug,应尽可能避免。
复制代码 代码如下:

// 6.B.3

function Device( opts ) {
  var self = this;

  this.value = null;

  stream.read( opts.path, function( data ) {

    self.value = data;

  });

  setInterval(function() {

    self.emit("event");

  }, opts.freq || 100 );
}

C. 使用 thisArg

好几个 ES 5.1 中的原型的方法都内置了一个特殊的 thisArg 标记,尽可能多地使用它

复制代码 代码如下:

// 6.C.1

var obj;

obj = { f: "foo", b: "bar", q: "qux" };

Object.keys( obj ).forEach(function( key ) {

  // |this| 现在是 `obj`

  console.log( this[ key ] );

}, obj ); //

// 打印出来...

// "foo"
// "bar"
// "qux"


thisArg 在 Array.prototype.every、 Array.prototype.forEach、 Array.prototype.some、 Array.prototype.map、 Array.prototype.filter 中都可以使用。

七、Misc

这个部分将要说明的想法和理念都并非教条。相反更鼓励对现存实践保持好奇,以尝试提供完成一般 JavaScript 编程任务的更好方案。

A. 避免使用 switch,现代方法跟踪(method tracing)将会把带有 switch 表达式的函数列为黑名单。

似乎在最新版本的 Firefox 和 Chrome 都对 switch 语句有重大改进。http://jsperf.com/switch-vs-object-literal-vs-module

值得注意的是,改进可以这里看到: https://github.com/rwldrn/idiomatic.js/issues/13

复制代码 代码如下:

// 7.A.1.1
// switch 语句示例

switch( foo ) {
  case "alpha":
    alpha();
    break;
  case "beta":
    beta();
    break;
  default:
    // 默认分支
    break;
}

// 7.A.1.2
// 一个可支持组合、重用的方法是使用一个对象来存储 “cases”,
// 使用一个 function 来做委派:

var cases, delegator;

// 返回值仅作说明用
cases = {
  alpha: function() {
    // 语句
    // 一个返回值
    return [ "Alpha", arguments.length ];
  },
  beta: function() {
    // 语句
    // 一个返回值
    return [ "Beta", arguments.length ];
  },
  _default: function() {
    // 语句
    // 一个返回值
    return [ "Default", arguments.length ];
  }
};

delegator = function() {
  var args, key, delegate;

  // 把 `argument` 转换成数组
  args = [].slice.call( arguments );

  // 从 `argument` 中抽出最前一个值
  key = args.shift();

  // 调用默认分支
  delegate = cases._default;

  // 从对象中对方法进行委派操作
  if ( cases.hasOwnProperty( key ) ) {
    delegate = cases[ key ];
  }

  // arg 的作用域可以设置成特定值,
  // 这种情况下,|null| 就可以了
  return delegate.apply( null, args );
};

// 7.A.1.3
// 使用 7.A.1.2 中的 API:

delegator( "alpha", 1, 2, 3, 4, 5 );
// [ "Alpha", 5 ]

// 当然 `case` key 的值可以轻松地换成任意值

var caseKey, someUserInput;

// 有没有可能是某种形式的输入?
someUserInput = 9;

if ( someUserInput > 10 ) {
  caseKey = "alpha";
} else {
  caseKey = "beta";
}

// 或者...

caseKey = someUserInput > 10 ? "alpha" : "beta";

// 然后...

delegator( caseKey, someUserInput );
// [ "Beta", 1 ]

// 当然还可以这样搞...

delegator();
// [ "Default", 0 ]

B. 提前返回值提升代码的可读性并且没有太多性能上的差别

复制代码 代码如下:

// 7.B.1.1
// 不好:
function returnLate( foo ) {
  var ret;

  if ( foo ) {
    ret = "foo";
  } else {
    ret = "quux";
  }
  return ret;
}

// 好:

function returnEarly( foo ) {

  if ( foo ) {
    return "foo";
  }
  return "quux";
}

八、原生 & 宿主对象(注:其实一直觉得 Host Objects 真不应该翻译过来,这是就按一般书的写法翻出来吧)

最基本的原则是:

不要干任何蠢事,事情总会变好的。

为了加强这个观念,请观看这个演示:

“一切都被允许: 原生扩展” by Andrew Dupont (JSConf2011, Portland, Oregon)

http://blip.tv/jsconf/jsconf2011-andrew-dupont-everything-is-permitted-extending-built-ins-5211542

九、注释

单行注释放于代码上方为首选
多行也可以
行末注释应被避免!
JSDoc 的方式也不错,但需要比较多的时间

十、单用一门语言

无论是什么语言程序维护者(或团队)规定使用何种语言,程序都应只用同一种语言书写。

 

附录

前置逗号(Comma First)

所有使用这个文档作为基本风格指南的项目都不允许前置逗号的代码格式,除非明确指定或者作者要求。

声明
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn
JavaScript引擎:比较实施JavaScript引擎:比较实施Apr 13, 2025 am 12:05 AM

不同JavaScript引擎在解析和执行JavaScript代码时,效果会有所不同,因为每个引擎的实现原理和优化策略各有差异。1.词法分析:将源码转换为词法单元。2.语法分析:生成抽象语法树。3.优化和编译:通过JIT编译器生成机器码。4.执行:运行机器码。V8引擎通过即时编译和隐藏类优化,SpiderMonkey使用类型推断系统,导致在相同代码上的性能表现不同。

超越浏览器:现实世界中的JavaScript超越浏览器:现实世界中的JavaScriptApr 12, 2025 am 12:06 AM

JavaScript在现实世界中的应用包括服务器端编程、移动应用开发和物联网控制:1.通过Node.js实现服务器端编程,适用于高并发请求处理。2.通过ReactNative进行移动应用开发,支持跨平台部署。3.通过Johnny-Five库用于物联网设备控制,适用于硬件交互。

使用Next.js(后端集成)构建多租户SaaS应用程序使用Next.js(后端集成)构建多租户SaaS应用程序Apr 11, 2025 am 08:23 AM

我使用您的日常技术工具构建了功能性的多租户SaaS应用程序(一个Edtech应用程序),您可以做同样的事情。 首先,什么是多租户SaaS应用程序? 多租户SaaS应用程序可让您从唱歌中为多个客户提供服务

如何使用Next.js(前端集成)构建多租户SaaS应用程序如何使用Next.js(前端集成)构建多租户SaaS应用程序Apr 11, 2025 am 08:22 AM

本文展示了与许可证确保的后端的前端集成,并使用Next.js构建功能性Edtech SaaS应用程序。 前端获取用户权限以控制UI的可见性并确保API要求遵守角色库

JavaScript:探索网络语言的多功能性JavaScript:探索网络语言的多功能性Apr 11, 2025 am 12:01 AM

JavaScript是现代Web开发的核心语言,因其多样性和灵活性而广泛应用。1)前端开发:通过DOM操作和现代框架(如React、Vue.js、Angular)构建动态网页和单页面应用。2)服务器端开发:Node.js利用非阻塞I/O模型处理高并发和实时应用。3)移动和桌面应用开发:通过ReactNative和Electron实现跨平台开发,提高开发效率。

JavaScript的演变:当前的趋势和未来前景JavaScript的演变:当前的趋势和未来前景Apr 10, 2025 am 09:33 AM

JavaScript的最新趋势包括TypeScript的崛起、现代框架和库的流行以及WebAssembly的应用。未来前景涵盖更强大的类型系统、服务器端JavaScript的发展、人工智能和机器学习的扩展以及物联网和边缘计算的潜力。

神秘的JavaScript:它的作用以及为什么重要神秘的JavaScript:它的作用以及为什么重要Apr 09, 2025 am 12:07 AM

JavaScript是现代Web开发的基石,它的主要功能包括事件驱动编程、动态内容生成和异步编程。1)事件驱动编程允许网页根据用户操作动态变化。2)动态内容生成使得页面内容可以根据条件调整。3)异步编程确保用户界面不被阻塞。JavaScript广泛应用于网页交互、单页面应用和服务器端开发,极大地提升了用户体验和跨平台开发的灵活性。

Python还是JavaScript更好?Python还是JavaScript更好?Apr 06, 2025 am 12:14 AM

Python更适合数据科学和机器学习,JavaScript更适合前端和全栈开发。 1.Python以简洁语法和丰富库生态着称,适用于数据分析和Web开发。 2.JavaScript是前端开发核心,Node.js支持服务器端编程,适用于全栈开发。

See all articles

热AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover

AI Clothes Remover

用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool

Undress AI Tool

免费脱衣服图片

Clothoff.io

Clothoff.io

AI脱衣机

AI Hentai Generator

AI Hentai Generator

免费生成ai无尽的。

热门文章

R.E.P.O.能量晶体解释及其做什么(黄色晶体)
3 周前By尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.最佳图形设置
3 周前By尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.如果您听不到任何人,如何修复音频
3 周前By尊渡假赌尊渡假赌尊渡假赌
WWE 2K25:如何解锁Myrise中的所有内容
4 周前By尊渡假赌尊渡假赌尊渡假赌

热工具

DVWA

DVWA

Damn Vulnerable Web App (DVWA) 是一个PHP/MySQL的Web应用程序,非常容易受到攻击。它的主要目标是成为安全专业人员在合法环境中测试自己的技能和工具的辅助工具,帮助Web开发人员更好地理解保护Web应用程序的过程,并帮助教师/学生在课堂环境中教授/学习Web应用程序安全。DVWA的目标是通过简单直接的界面练习一些最常见的Web漏洞,难度各不相同。请注意,该软件中

VSCode Windows 64位 下载

VSCode Windows 64位 下载

微软推出的免费、功能强大的一款IDE编辑器

MinGW - 适用于 Windows 的极简 GNU

MinGW - 适用于 Windows 的极简 GNU

这个项目正在迁移到osdn.net/projects/mingw的过程中,你可以继续在那里关注我们。MinGW:GNU编译器集合(GCC)的本地Windows移植版本,可自由分发的导入库和用于构建本地Windows应用程序的头文件;包括对MSVC运行时的扩展,以支持C99功能。MinGW的所有软件都可以在64位Windows平台上运行。

ZendStudio 13.5.1 Mac

ZendStudio 13.5.1 Mac

功能强大的PHP集成开发环境

WebStorm Mac版

WebStorm Mac版

好用的JavaScript开发工具