搜尋
首頁web前端js教程js物件實例詳解(JavaScript物件深度剖析,深度理解js物件)

下面小編就為大家帶來一篇js物件實例詳解(JavaScript物件深度剖析,深度理解js物件)。小編覺得蠻不錯的,現在就分享給大家,也給大家做個參考。對js有興趣一起跟著小編過來看看吧

這算是醞釀很久的一篇文章了。

JavaScript作為一個基於物件(沒有類別的概念)的語言,從入門到精通到放棄一直會被物件這個問題圍繞。

平常發的文章基本上都是開發中遇到的問題和對最佳解決方案的探討,終於忍不住要寫一篇基礎概念類的文章了。

本文探討以下問題,在座的朋友各取所需,歡迎批評指正:

1、建立物件
2、proto與prototype
3、繼承與原型鏈
4、物件的深度複製
5、一些Object的方法與需要注意的點
6、ES6新增特性

下面反覆提到實例物件和原型對象,透過建構函式new 出來的本文稱作實例對象,建構函數的原型屬性本文稱為原型對象。

建立物件

字面上量的方式:

var myHonda = {color: "red", wheels: 4, engine: {cylinders: 4, size: 2.2}}

就是new Object()的文法糖,一樣一樣的。

工廠模式:

function createCar(){ 
 var oTemp = new Object(); 
 oTemp.name = arguments[0];
 //直接给对象添加属性,每个对象都有直接的属性 
 oTemp.age = arguments[1]; 
 oTemp.showName = function () {  
 alert(this.name); 
 };//每个对象都有一个 showName 方法版本 
 return oTemp;
};
var myHonda = createCar('honda', 5)

只是給new Object()包了層皮,方便量產,並沒有本質區別,姑且算作創建對象的一種方式。

建構子:

function Person(name, age, sex) {
 this.name = name;
 this.age = age;
 this.sex = sex;
 this.getName = function() {
return this.name;
 };
}
var rand = new Person("Rand McKinnon", 33, "M");

上面建構子的getName 方法,每次實例化都會新建該函數對象,也形成了在目前情況下並沒有卵用的閉包,所以建構函式加入方法用下面方式處理,工廠模式給物件加入方法的時候也應該用下面的方式避免重複建構函式物件

function Person(name, age, sex) {
 this.name = name;
 this.age = age;
 this.sex = sex;
 this.getName = getName
}
function getName() {
 return this.name;
};

建構子建立物件的過程和工廠模式又是半斤八兩,相當於隱藏了創建新對象和返回該對象這兩步,構造函數內this 指向新建對象,沒什麼不同。

最大不同點: 建構函數創造出來的物件 constructor 屬性指向該建構函數,工廠模式指向 function Object(){...}。

建構函式相當於在原型鏈上加了一環,建構函式有自己的 prototype,工廠模式就是個普通函式。說到這裡我上一句話出現了漏洞,工廠模式的 constructor 指向哪得看第一句話 new 的是什麼。

建構子直接呼叫而不new 的話,就看呼叫時候this 指向誰了,直接呼叫就把屬性綁到window 上了,透過call 或apply 綁定到其他物件作用域就把屬性加到該對象了。

原型模式:

建構子雖然在原型鏈上加了一環,但顯然這一環啥都沒有啊,這樣一來和工廠模式又有什麼區別?加了一環又有什麼意義?原型模式浮出水面。

function Car(){} 
//用空构造函数设置类名
Car.prototype.color = "blue";//每个对象都共享相同属性
Car.prototype.doors = 3;
Car.prototype.drivers = new Array("Mike","John");
Car.prototype.showColor = function(){  
 alert(this.color);
};//每个对象共享一个方法版本,省内存。
//构造函数的原型属性可以通过字面量来设置,别忘了通过 Object.defineProperty()设置 constructor 为该构造函数
function Car(){} 
Car.prototype = {
 color:"blue",
 doors:3,
 showColor:function(){  
alert(this.color);
 }
}
Object.defineProperty(Car.prototype, "constructor", { enumerable:false, value:Car })
//(不设置 constructor 会导致 constructor 不指向构造函数,直接设置 constructor 会导致 constructor 可枚举)

使用原型模式註意動態性,透過建構函式實例化出的對象,他的原型對像是建構函式的prototype ,如果在他的原型對像上增加或刪除一些方法,該對象會繼承這些修改。例如,先透過建構子 A 實例化出物件 a ,然後再給 A.prototype 增加一個方法,a 是可以繼承這個方法的。但是給 A.prototype 設定一個新的對象,a 是不會繼承這個新物件的屬性和方法的。聽起來有點繞,修改A.prototype 相當於直接修改a 的原型對象,a 很自然的會繼承這些修改,但是重新給A.prototype 賦值的話,修改的是構造函數的原型,並沒有影響a 的原型對象! a 被創建出來以後原型物件就已經確定了,除非直接修改這個原型物件(或這個原型物件的原型物件),否則 a 是不會繼承這些修改的!

Object.create()

傳入要建立物件實例的原型對象,和原型模式幾乎是一個意思也是相當於在原型鏈上加了一環,差別在於這種方式創建的物件沒有建構子。這種方式相當於:

function object(o){
function F(){}
F.prototype = o;
return new F()
}

相當於建構子只短暫的存在了一會,創建出來的物件的 constructor 指向 原型物件 o 的 constructor !

混合模式:

使用原型模式時,當給實例物件設定自己專屬的屬性的時候,該實例物件會忽略原型鏈中的該屬性。但當原型鏈中的屬性是引用類型值的時候,操作不當有可能會直接修改原型物件的屬性!這會影響到所有使用該原型物件的實例物件!

大部分情況下,實例物件的多數方法是共有的,多數屬性是私有的,所以屬性在建構函式中設置,方法在原型中設定是合適的,建構函式與原型結合使用是通常的做法。

还有一些方法,无非是工厂模式与构造函数与原型模式的互相结合,在生成过程和 this 指向上做一些小变化。

class 方式:

见下面 ES6 class 部分,只是一个语法糖,本质上和构造函数并没有什么区别,但是继承的方式有一些区别。

proto与prototype

这两个到底是什么关系?搞清楚 实例对象 构造函数 原型对象 的js物件實例詳解(JavaScript物件深度剖析,深度理解js物件),这两个属性的用法就自然清晰了,顺便说下 constructor。

构造函数创建的实例对象的 constructor 指向该构造函数(但实际上 constructor 是对应的原型对象上的一个属性!所以实例对象的 constructor 是继承来的,这一点要注意,如果利用原型链继承,constructor 将有可能指向原型对象的构造函数甚至更上层的构造函数,其他重写构造函数 prototype 的行为也会造成 constructor 指向问题,都需要重设 constructor),构造函数的 prototype 指向对应的原型对象,实例对象的 proto 指对应的原型对象,proto是浏览器的实现,并没有出现在标准中,可以用 constructor.prototype 代替。考虑到 Object.create() 创建的对象,更安全的方法是 Object.getPrototpyeOf() 传入需要获取原型对象的实例对象。

我自己都感觉说的有点乱,但是他们就是这样的,上一张图,看看能不能帮你更深刻理解这三者关系。


js物件實例詳解(JavaScript物件深度剖析,深度理解js物件)

继承与原型链

当访问一个对象的属性时,如果在对象本身找不到,就会去搜索对象的原型,原型的原型,知道原型链的尽头 null,那原型链是怎么链起来的?

把 实例对象 构造函数 原型对象 视为一个小组,上面说了三者互相之间的关系,构造函数是函数,可实例对象和原型对象可都是普通对象啊,这就出现了这样的情况:

这个小组的原型对象,等于另一个小组实例对象,而此小组的原型对象又可能是其他小组的实例对象,这样一个个的小组不就连接起来了么。举个例子:

function Super(){
 this.val = 1;
 this.arr = [1];
}
function Sub(){
 // ...
}
Sub.prototype = new Super();

Sub 是一个小组 Super 是一个小组,Sub 的原型对象链接到了 Super 的实例对象。

基本上所有对象顺着原型链爬到头都是 Object.prototype , 而 Object.prototype 就没有原型对象,原型链就走到头了。

判断构造函数和原型对象是否存在于实例对象的原型链中:

实例对象 instanceof 构造函数,返回一个布尔值,原型对象.isPrototypeOf(实例对象),返回一个布尔值。

上面是最简单的继承方式了,但是有两个致命缺点:

所有 Sub 的实例对象都继承自同一个 Super 的实例对象,我想传参数到 Super 怎么办?

如果 Super 里有引用类型的值,比如上面例子中我给 Sub 的实例对象中的 arr 属性 push 一个值,岂不是牵一发动全身?

下面说一种最常用的组合继承模式,先举个例子:


function Super(value){
 // 只在此处声明基本属性和引用属性
 this.val = value;
 this.arr = [1];
}
// 在此处声明函数
Super.prototype.fun1 = function(){};
Super.prototype.fun2 = function(){};
//Super.prototype.fun3...
function Sub(value){
 Super.call(this,value); // 核心
 // ...
}
Sub.prototype = new Super(); // 核心


过程是这样的,在简单的原型链继承的基础上, Sub 的构造函数里运行 Super ,从而给 Sub 的每一个实例对象一份单独的属性,解决了上面两个问题,可以给 Super 传参数了,而且因为是独立的属性,不会因为误操作引用类型值而影响其他实例了。不过还有个小缺点: Sub 中调用的 Super 给每个 Sub 的实例对象一套新的属性,覆盖了继承的 Super 实例对象的属性,那被覆盖的的那套属性不就浪费了?岂不是白继承了?最严重的问题是 Super 被执行了两次,这不能忍(其实也没多大问题)。下面进行一下优化,把上面例子最后一行替换为:


Sub.prototype = Object.create(Super.prototype);
// Object.create() 给原型链上添加一环,否则 Sub 和 Super 的原型就重叠了。
Sub.prototype.constructor = Sub;


到此为止,继承非常完美。

其他还有各路继承方式无非是在 简单原型链继承 --> 优化的组合继承 路程之间的一些思路或者封装。

通过 class 继承的方式:

通过 class 实现继承的过程与 ES5 完全相反,详细见下面 ES6 class的继承 部分。

对象的深度克隆

JavaScript的基础类型是值传递,而对象是引用传递,这导致一个问题:

克隆一个基础类型的变量的时候,克隆出来的的变量是和旧的变量完全独立的,只是值相同而已。

而克隆对象的时候就要分两种情况了,简单的赋值会让两个变量指向同一块内存,两者代表同一个对象,甚至算不上克隆克隆。但我们常常需要的是两个属性和方法完全相同但却完全独立的对象,称为深度克隆。我们接下来讨论几种深度克隆的方法。

说几句题外的话,业界有一个非常知名的库 immutable ,个人认为很大程度上解决了深度克隆的痛点,我们修改一个对象的时候,很多时候希望得到一个全新的对象(比如Redux每次都要用一个全新的对象修改状态),由此我们就需要进行深度克隆。而 immutable 相当于产生了一种新的对象类型,每一次修改属性都会返回一个全新的 immutable 对象,免去了我们深度克隆的工作是小事,关键性能特别好。

历遍属性


function clone(obj){
 var newobj = obj.constructor === Array ? [] : {}; // 用 instanceof 判断也可
 if(typeof obj !== 'object' || obj === null ){
return obj
 } else {
for(var i in obj){
 newobj[i] = typeof obj[i] === 'object' ? cloneObj(obj[i]) : obj[i]; 
 // 只考虑 对象和数组, 函数虽然也是引用类型,但直接赋值并不会产生什么副作用,所以函数类型无需深度克隆。
}
 }
 return newobj;
};


原型式克隆


function clone(obj){
 function F() {};
 F.prototype = obj;
 var f = new F();
 for(var key in obj)
 {
 if(typeof obj[key] =="object")
 {
  f[key] = clone(obj[key])
 }
 }
 return f ;
}

这种方式不能算严格意义上的深度克隆,并没有切断新对象与被克隆对象的联系,被克隆对象作为新对象的原型存在,虽然新对象的改变不会影响旧对象,但反之则不然!而且给新对象属性重新赋值的时候只是覆盖了原型中的属性,在历遍新对象的时候也会出现问题。这种方式问题重重,除了实现特殊目的可以酌情使用,通常情况应避免使用。
json序列化

var newObj = JSON.parse(JSON.stringify(obj));

这是我最喜欢的方式了!简短粗暴直接!但是最大的问题是,毕竟JSON只是一种数据格式所以这种方式只能克隆属性,不能克隆方法,方法在序列化以后就消失了。。。

一些Object的方法与需要注意的点

Object 自身的方法:

设置属性,Object.defineProperty(obj, prop, descriptor) 根据 descriptor 定义 obj 的 prop 属性(值,是否可写可枚举可删除等)。

Object.getOwnPropertyDescriptor(obj, prop) 返回 obj 的 prop 属性的描述。

使对象不可拓展,Object.preventExtensions(obj),obj 将不能添加新的属性。

判断对像是否可拓展,Object.isExtensible(obj)。

密封一个对象,Object.seal(obj),obj 将不可拓展且不能删除已有属性。

判断对象是否密封,Object.isSealed(obj)。

冻结对象,Object.freeze(obj) obj 将被密封且不可修改。

判断对象是否冻结,Object.isFrozen(obj)。

获取对象自身属性(包括不可枚举的),Object.getOwnPropertyNames(obj),返回 obj 所有自身属性组成的数组。

获取对象自身属性(不包括不可枚举的),Object.keys(obj),返回 obj 所有自身可枚举属性组成的数组。

当使用for in循环遍历对象的属性时,原型链上的所有可枚举属性都将被访问。

只关心对象本身时用Object.keys(obj)代替 for in,避免历遍原型链上的属性。

获取某对象的原型对象,Object.getPrototypeOf(object),返回 object 的原型对象。

设置某对象的原型对象,Object.setPrototypeOf(obj, prototype),ES6 新方法,设置 obj 的原型对象为 prototype ,该语句比较耗时。

Object.prototype 上的方法:

检查对象上某个属性是否存在时(存在于本身而不是原型链中),obj.hasOwnProperty() 是唯一可用的方法,他不会向上查找原型链,只在 obj 自身查找,返回布尔值。

检测某对象是否存在于参数对象的原型链中,obj.isPrototypeOf(obj2),obj 是否在 obj2 的原型链中,返回布尔值。

检测某属性是否是对象自身的可枚举属性,obj.propertyIsEnumerable(prop),返回布尔值。

对象类型,obj.toString(),返回 "[object type]" type 可以是 Date,Array,Math 等对象类型。

obj.valueOf(),修改对象返回值时的行为,使用如下:

function myNumberType(n) {
this.number = n;
}
myNumberType.prototype.valueOf = function() {
return this.number;
};
myObj = new myNumberType(4);
myObj + 3; // 7

ES6新增特性

判断两个值是否完全相等,Object.is(value1, value2),类似于 === 但是可以用来判断 NaN。

属性和方法简写:

// 属性简写
var foo = 'bar';
var baz = {foo};
baz // {foo: "bar"}
// 等同于
var baz = {foo: foo};
// 方法简写
function f(x, y) {
 return {x, y};
}
// 等同于
function f(x, y) {
 return {x: x, y: y};
}
f(1, 2) // Object {x: 1, y: 2}

合并对象:

Object.assign(target, [...source]);

将 source 中所有和枚举的属性复制到 target。

多个 source 对象有同名属性,后面的覆盖前面的。

var target = { a: 1 };
var source1 = { b: 2 };
var source2 = { c: 3 };
Object.assign(target, source1, source2);
target // {a:1, b:2, c:3}

注意一点,该命令执行的是浅克隆,如果 source 中有属性是对象,target 中会复制该对象的引用。

常用于给对象添加属性和方法(如给构造函数的原型添加方法),克隆、合并对象等。

获取对象自身的值或键值对(做为Object.keys(obj)的补充不包括不可枚举的):

Object.keys(obj)返回 obj 自身所有可枚举属性的值组成的数组。

Object.entries(obj)返回 obj 自身所有可枚举键值对数组组成的数组,例如:

var obj = { foo: 'bar', baz: 42 };
Object.entries(obj)
// [ ["foo", "bar"], ["baz", 42] ]
// 可用于将对象转为 Map 结构
var obj = { foo: 'bar', baz: 42 };
var map = new Map(Object.entries(obj));
map // Map { foo: "bar", baz: 42 }

拓展运算符:

取出对象所有可历遍属性,举例:

let z = { a: 3, b: 4 };
let n = { ...z };
n // { a: 3, b: 4 }
// 可代替 Object.assign()
let ab = { ...a, ...b };
// 等同于
let ab = Object.assign({}, a, b);

可用于解构赋值中最后一个参数:

let { x, y, ...z } = { x: 1, y: 2, a: 3, b: 4 };
x // 1
y // 2
z // { a: 3, b: 4 }
// 可以这样理解,把 z 拆开以后就等于后面对象未被分配出去的键值对。

Null 传导运算符:

const firstName = message?.body?.user?.firstName || 'default';
// 代替
const firstName = (message
 && message.body
 && message.body.user
 && message.body.user.firstName) || 'default';

class:

ES6 引入了 class 关键字,但并没有改变对象基于原型继承的原理,只是一个语法糖,让他长得像传统面向对象语言而已。

以下两个写法完全等价:

function Point(x, y) {
 this.x = x;
 this.y = y;
}
Point.prototype.toString = function () {
 return '(' + this.x + ', ' + this.y + ')';
};
//定义类
class Point {
 constructor(x, y) {
this.x = x;
this.y = y;
 }
 toString() {
return '(' + this.x + ', ' + this.y + ')';
 }
}
// 类中定义的方法就是在原型上

有两点区别, class 中定义的方法是不可枚举的,class 必须通过 new 调用不能直接运行。

class 不存在变量提升,使用要在定义之后。

class 中的方法前加 static 关键字定义静态方法,只能通过 class 直接调用不能被实例继承。

如果静态方法包含 this 关键字,这个 this 指的是 class,而不是实例。注意下面代码:

class Foo {
 static bar () {
 this.baz();
 }
 static baz () {
 console.log('hello');
 }
 baz () {
 console.log('world');
 }
}
Foo.bar() // hello

父类的静态方法,可以被子类继承,目前 class 内部无法定义静态属性。

设置静态属性与实例属性新提案:

class 的实例属性可以用等式,写入类的定义之中。

静态属性直接前面加 static 即可。

class MyClass {
 myProp = 42;
 static myStaticProp = 42;
}

class 的继承:

class 通过 extends 实现继承,注意 super 关键字

class ColorPoint extends Point {
 constructor(x, y, color) {
super(x, y); // 调用父类的constructor(x, y)
this.color = color;
 }
 toString() {
return this.color + ' ' + super.toString(); // 调用父类的toString()
 }
}

extends 可以继承其他类或任何有 prototype 属性的函数。

super 会从父类获取各路信息绑定到子类的 this。

子类自己没有 this 对象,要先继承父类的实例对象然后再进行加工,所以要在 constructor 里调用 super 继承 this 对象后才能使用 this。

ES5 的继承,实质是先创造子类的实例对象 this,然后再将父类的方法添加到 this 上面(Parent.apply(this))。ES6 的继承机制完全不同,实质是先创造父类的实例对象 this(所以必须先调用 super 方法创建和继承这个 this,并绑定到子类的 this),然后再用子类的构造函数修改this。

这条理由也是造成了 ES6 之前无法继承原生的构造函数(Array Function Date 等)的原型对象,而使用 class 可以。因为 ES5 中的方法是先实例化子类,再把父类的属性添加上去,但是父类有很多不能直接访问的属性或方法,这就糟了,而通过 class 继承反其道而行之先实例化父类,这就自然把所有属性和方法都继承了。

super 作为对象时,在普通方法中,指向父类的原型对象;在静态方法中,指向父类。

通过 super 调用父类的方法时,super 会绑定子类的 this。

constructor 方法会被默认添加:

class ColorPoint extends Point {
}
// 等同于
class ColorPoint extends Point {
 constructor(...args) {
super(...args);
 }
}

Object.getPrototypeOf(object),获取某对象的原型对象,也可以获取某类的原型类。

class 的 proto与prototype

子类的proto属性,表示构造函数的继承,总是指向父类。

子类prototype属性的proto属性,表示方法的继承,总是指向父类的 prototype 属性。

相当于子类本身继承父类,子类的原型对象继承自父类的原型对象。

new.target:

用在构造函数或者 class 内部,指向调用时 new 的构造函数或者 class。

相关推荐:

怎样用正则表达式让JavaScript的代码高亮

javascript匹配js中注释的正则表达式代码

Javascript中从学习bind到实现bind的过程详解

JavaScript门面模式实例详解

以上是js物件實例詳解(JavaScript物件深度剖析,深度理解js物件)的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn
超越瀏覽器:現實世界中的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支持服务器端编程,适用于全栈开发。

如何安裝JavaScript?如何安裝JavaScript?Apr 05, 2025 am 12:16 AM

JavaScript不需要安裝,因為它已內置於現代瀏覽器中。你只需文本編輯器和瀏覽器即可開始使用。 1)在瀏覽器環境中,通過標籤嵌入HTML文件中運行。 2)在Node.js環境中,下載並安裝Node.js後,通過命令行運行JavaScript文件。

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中的所有內容
3 週前By尊渡假赌尊渡假赌尊渡假赌

熱工具

ZendStudio 13.5.1 Mac

ZendStudio 13.5.1 Mac

強大的PHP整合開發環境

Atom編輯器mac版下載

Atom編輯器mac版下載

最受歡迎的的開源編輯器

Dreamweaver CS6

Dreamweaver CS6

視覺化網頁開發工具

MinGW - Minimalist GNU for Windows

MinGW - Minimalist GNU for Windows

這個專案正在遷移到osdn.net/projects/mingw的過程中,你可以繼續在那裡關注我們。 MinGW:GNU編譯器集合(GCC)的本機Windows移植版本,可自由分發的導入函式庫和用於建置本機Windows應用程式的頭檔;包括對MSVC執行時間的擴展,以支援C99功能。 MinGW的所有軟體都可以在64位元Windows平台上運作。

MantisBT

MantisBT

Mantis是一個易於部署的基於Web的缺陷追蹤工具,用於幫助產品缺陷追蹤。它需要PHP、MySQL和一個Web伺服器。請查看我們的演示和託管服務。