前端干货之JS最佳实践

持续更新地址 https://wdd.js.org/js-best-pr...

1. 风格

一千个读者有一千个哈姆雷特,每个人都有自己的code style。我也曾为了要不要加分号给同事闹个脸红脖子粗,实际上有必要吗? 其实JavaScript已经有了比较流行的几个风格

  • JavaScript Standard Style
  • Google JavaScript Style Guide
  • Airbnb JavaScript Style Guide

我自己使用的是JavaScript Standard Style, 我之所以使用这个,是因为它有一些工具。可以让你写完代码后,一旦保存,就自动帮你把你的风格的代码修正成标准分割,而不是死记硬背应该怎么写。看完这个页面,你就应该立马爱上JavaScript Standard Style , 如果你用vscode, 恰好你有写vue, 你想在.vue文件中使用standard风格,那么你需要看看这篇文章

2. 可维护性

很多时候,我们不是从零开始,开发新代码。而是去维护别人的代码,以他人的工作成果为基础。确保自己的代码可维护,是赠人玫瑰,手留余香的好事。一方面让别人看的舒服,另一方面也防止自己长时间没看过自己的代码,自己都难以理解。

2.1. 什么是可维护代码

可维护的代码的一些特征

  • 可理解易于理解代码的用途
  • 可适应数据的变化,不需要完全重写代码
  • 可扩展要考虑未来对核心功能的扩展
  • 可调试给出足够的信息,让调试的时候,确定问题所在
  • 不可分割函数的功能要单一,功能粒度不可分割,可复用性增强

2.2. 代码约定

2.2.1. 可读性

  • 统一的缩进方式
  • 注释
  • 空白行

2.2.1.1. 缩进:

  • 一般使用4个空格
  • 不用制表符的原因是它在不同编辑器里显示效果不同

2.2.1.2. 注释:哪些地方需要注释?

  • 函数和方法
  • 大段代码
  • 复杂的算法
  • hack

2.2.1.3. 空白行:哪些地方需要空白行?

  • 方法之间
  • 方法里的局部变量和第一个语句之间
  • 单行或者多行注释
  • 方法内衣个逻辑单元之间
// Good
if (wl && wl.length) {for (i = 0, l = wl.length; i < l; ++i) {p = wl[i];type = Y.Lang.type(r[p]);if (s.hasOwnProperty(p)) {if (merge && type == 'object') {Y.mix(r[p], s[p]);} else if (ov || !(p in r)) {r[p] = s[p];}}}
}

2.2.2. 变量名和函数名

There are only two hard problem in Computer Science cache invalidation and naming things.---Phil Karlton
  • 驼峰式命名
  • 变量名以名词开头
  • 方法名以动词开头
  • 常量全部大写
  • 构造函数以大写字母开头
  • jQuery对象以"$"符号开头
  • 自定义事件处理函数以“on”开头
// Good
var count = 10;
var myName = "wdd";
var found = true;// Bad: Easily confused with functions
var getCount = 10;
var isFound = true;// Good
function getName() {return myName;
}// Bad: Easily confused with variable
function theName() {return myName;
}// Bad:
var btnOfSubmit = $('#submit');// Good:
var $btnOfSubmit = $('#submit');// Bad:给App添加一个处理聊天事件的函数,一般都是和websocket服务端推送消息相关
App.addMethod('createChat',function(res){App.log(res);
});
// Bad: 此处调用,这里很容易误以为这个函数是处理创建聊天的逻辑函数
App.createChat();// Good: 
App.addMethod('onCreateChat',function(res){App.log(res);
});
// Good:此处调用
App.onCreateChat();
变量命名不仅仅是一种科学,更是一种艺术。总之,要短小精悍,见名知意。有些名词可以反应出变量的类型。

2.2.2.1. 变量名

名词数据类型含义
count, length,size数值
name, title,message字符串
i, j, k用来循环
car,person,student,user对象
success,fail布尔值
payloadpost数据的请求体
method请求方式

2.2.2.2. 函数名

动词含义
canFunction returns a boolean
hasFunction returns a boolean
isFunction returns a boolean
getFunction returns a nonboolean
set Function is used to save a value

2.2.2.3. 一些与函数名搭配的常用动词

动词用法
send发送
resend重发
validate验证
query查询
create创建
add添加
delete删除
remove移除
insert插入
update更新,编辑
copy复制
render渲染
close关闭
open开启
clear清除
edit编辑
query查询
on当事件发生
list渲染一个列表,如用户列表renderUsersList()
content渲染内容,如用户详情的页面 renderUserContent()

2.2.2.4. 接口常用的动词

对于http请求的最常用的四种方法,get,post,put,delete,有一些常用的名词与其对应

含义请求方法词语栗子
增加postcreatecreateUser,createCall
删除deletedeletedeleteUser
修改putupdateupdateUser,updateProfile
查询getget,querygetUser,queryUser(无条件查询使用get,有条件查询使用query)

2.2.2.5. 学会使用单复数命名函数

函数名含义
getUser()获取一个用户,一般是通过唯一的id来获取
getUsers()获取一组用户,一般是通过一些条件来获取
createUser()创建一个用户
createUsers()创建一组用户

2.2.2.6. 常量

var MAX_COUNT = 10;
var URL = "http://www.nczonline.net/";

2.2.2.7. 构造函数

// Good
function Person(name) {this.name = name;
}
Person.prototype.sayName = function() {alert(this.name);
};
var me = new Person("wdd");

2.2.2.8. 底层http请求接口函数

  • 建议使用“_”开头,例如App._getUsers();而对于接口函数的封装,例如App.getUsers(),内部逻辑调用App._getUsers();

2.2.3. 文件名

  • 全部使用小写字母
  • 单词之间的间隔使用“-”

eg:

app-main.js
app-event.js
app-user-manger.js

2.2.4. 文件归类

自己写的js文件最好和引用的一些第三方js分别放置在不同的文件夹下。

2.2.5. 千万别用alert

alert的缺点

  • 如果你用alert来显示提醒消息,那么用户除了点击alert上的的确定按钮外,就只能点击上面的关闭,或者选择禁止再选择对话框,除此以外什么都不能操作。
  • 有些浏览器如果禁止了alert的选项,那么你的alert是不会显示的
  • 如果你在try catch语句里使用alert,那么console里将不会输出错误信息,你都没办法查看错误的详细原因,以及储出错的位置。

更优雅的提醒方式

  • console.log() 普通提示消息
  • console.error() 错误提示消息
  • console.info() 信息提示消息
  • console.warn() 警告提示消息

2.3. 松散耦合

  • html文件中尽可能避免写js语句
  • 尽量避免在js更改某个css类的属性,而使用更改类的方法
  • 不要在css中写js的表达式
  • 解耦应用逻辑和事件处理程序

2.3.1. 将应用逻辑和事件处理程序的解耦

//一般事件订阅的写法,以jQuery的写法为栗子
$(document).on('click','#btn-get-users',function(event){event.stopPropagation();//下面的省略号表示执行获取所有用于并显示在页面上的逻辑// Bad.........//
});

如果增加了需求,当点击另外一个按钮的时候,也要执行获取所有用户并显示在页面上,那么上面省略的代码又要复制一份。如果接口有改动,那么需要在两个不同的地方都要修改。
所以,应该这样。

$(document).on('click','#btn-get-users',function(event){event.stopPropagation();//将应用逻辑分离在其他个函数中// GoodApp.getUsers();App.renderUsers();
});

2.3.2. 松散解耦规则

  • 不要将event对象传给其他方法,只传递来自event对象中的某些数据
  • 任何事件处理程序都应该只处理事件,然后把处理转交给应用逻辑。

2.3.3. 将异步请求和数据处理解耦

// Bad
ReqApi.tenant.queryUsers({},function(res){if(!res.success){console.error(res);return;}//对数据的处理.........
});    

上面代码对数据的处理直接写死在异步请求里面,如果换了一个请求,但是数据处理方式是一样的,那么又要复制一遍数据处理的代码。最好的方式是将数据处理模块化成为一个函数。

// Good
ReqApi.tenant.queryUsers({},function(res){if(!res.success){console.error(res);return;}//对数据的处理App.renderUsers(res.data);
}); 

异步请求只处理请求,不处理数据。函数的功能要专一,功能粒度不可分割。

2.3.4. 不要将某个变量写死在函数中,尽量使用参数传递进来

如果你需要一个函数去验证输入框是否是空,如下。这种方式就会绑定死了这个只能验证id为test的输入框,换成其他的就不行

// bad
function checkInputIsEmpty(){var value = $('#test').val();if(value){return true;}else{return false;}
}// good 
function isEmptyInput(id){var value = $('#'+id).val();if(value){return true;}else{return false;}
}

2.4. 编程实践

2.4.1. 尊总对象所有权

javascript动态性质是的几乎任何东西在任何时间都能更改,这样就很容易覆写了一些默认的方法。导致一些灾难性的后果。如果你不负责或者维护某个对象,那么你就不能对它进行修改。

  • 不要为实例或原型添加属性
  • 不要为实例或者原型添加方法
  • 不要重定义存已存在的方法

2.4.2. 避免全局变量

// Bad 两个全局变量
var name = "wdd";
funtion getName(){console.log(name);
}// Good 一个全局变量
var App = {name:"wdd",sayName:funtion(){console.log(this.name);//如果这个函数当做回调数使用,这个this可能指向window,}
};

单一的全局变量便是命名空间的概念,例如雅虎的YUI,jQuery的$等。

2.4.3. 避免与null进行比较

funtion sortArray(values){// 避免if(values != null){values.sort(comparator);}
}
function sortArray(values){// 推荐if(values instanceof Array){values.sort(compartor);}
}

2.4.3.1. 与null进行比较的代码,可以用以下技术进行替换

  • 如果值是一个应用类型,使用instanceof操作符,检查其构造函数
  • 如果值是基本类型,使用typeof检查其类型
  • 如果是希望对象包含某个特定的方法名,则只用typeof操作符确保指定名字的方法存在于对象上。

代码中与null比较越少,就越容易确定代码的目的,消除不必要的错误。

2.4.4. 从代码中分离配置文件

配置数据是一些硬代码(hardcoded),看下面的栗子

function validate(value){if(!value){alert('Invalid value');location.href = '/errors/invalid.php';}
}

上面代码里有两个配置数据,一个是UI字符串('Invalid value'),另一个是一个Url('/error/invalid.php')。如果你把他们写死在代码里,那么如果当你需要修改这些地方的时候,那么你必须一处一处的检查并修改,而且还可能会遗漏。

2.4.4.1. 所以第一步是要区分,哪些代码应该写成配置文件的形式?

  • 显示在UI元素中的字符串
  • URL
  • 一些重复的唯一值
  • 一些设置变量
  • 任何可能改变的值

2.4.4.2. 一些例子

var Config = {"MSG_INVALID_VALUE":"Invalid value","URL_INVALID":"/errors/invalid.php"
}

2.4.5. 调试信息开关

在开发过程中,可能随处留下几个console.log,或者alert语句,这些语句在开发过程中是很有价值的。但是项目一旦进入生产环境,过多的console.log可能影响到浏览器的运行效率,过多的alert会降低程序的用户体验。而我们最好不要在进入生产环境前,一处一处像扫雷一样删除或者注释掉这些调试语句。

最好的方式是设置一个开关。

//全局命令空间
var App = {debug:true,log:function(msg){if(debug){console.log(msg);}},alert:function(msg){if(debug){alert(msg);}}
};//使用
App.log('获取用户信息成功');
App.alert('密码不匹配');//关闭日志输出与alert
App.debug = false;

2.4.6. 使用jQuery Promise

没使用promise之前的回调函数写法

// bad:没使用promise之前的回调函数写法
function sendRequest(req,successCallback,errorCallback){var inputData = req.data || {};inputData = JSON.stringify(inputData);$.ajax({url:req.base+req.destination,type:req.type || "get",headers:{sessionId:session.id},data:inputData,dataType:"json",contentType : 'application/json; charset=UTF-8',success:function(data){successCallback(data);},error:function(data){console.error(data);errorCallback(data);}});
}//调用
sendRequest(req,function(res){...
},function(res){...
});

使用promise之后

function sendRequest(req){var dfd = $.Deferred();var inputData = req.data || {};inputData = JSON.stringify(inputData);$.ajax({url:req.base+req.destination,type:req.type || "get",headers:{sessionId:session.id},data:inputData,dataType:"json",contentType : 'application/json; charset=UTF-8',success:function(data){dfd.resolve(data);},error:function(data){dfd.reject(data);}});return dfd.promise();
}//调用
sendRequest(req)
.done(function(){//请求成功...
})
.fail(function(){//请求失败...
});

2.4.7. 显示错误提醒,不要给后端接口背锅

假如前端要去接口获取用户信息并显示出来,如果你的请求格式是正确的,但是接口返回400以上的错误,你必须通过提醒来告知测试,这个错误是接口的返回错误,而不是前端的逻辑错误。

2.4.8. REST化接口请求

对资源的操作包括获取、创建、修改和删除资源,这些操作正好对应HTTP协议提供的GET、POST、PUT和DELETE方法。

对应方式

请求类型接口前缀
GET.get,
POST.create 或者 .get
PUT.update
DELETE.delete

说明

  • 有些接口虽然是获取某一个资源,但是它使用的却是POST请求,所以建议使用.get比较好

示例:

// 与用户相关的接口
App.api.user = {};// 获取一个用户: 一般来说是一个指定的Id,例如userId
App.api.user.getUser = function(){...
};// 获取一组用户: 一般来说是一些条件,获取条件下的用户,筛选符合条件的用户
App.api.user.getUsers = function(){...
};// 创建一个用户
App.api.user.createUser = function(){};// 创建一组用户
App.api.user.createUsers = function(){};// 更新一个用户
App.api.user.updateUser = function(){};// 更新一组用户
App.api.user.updateUsers = function(){};// 更新一个用户
App.api.user.updateUser = function(){};// 更新一组用户
App.api.user.updateUsers = function(){};// 删除一个用户
App.api.user.deleteUser = function(){};// 删除一组用户
App.api.user.deleteUsers = function(){};

3. 性能

3.1. 注意作用域

  • 避免全局查找
  • 避免with语句

3.2. 选择正确的方法

  • 优化循环

    • 减值迭代:从最大值开始,在循环中不断减值的迭代器更加高效
    • 简化终止条件:由于每次循环过程都会计算终止条件,所以必须保证它尽可能快。也就是避免其他属性查找
    • 简化循环体:由于循环体是执行最多的,所以要确保其最大限度地优化。
  • 展开循环
  • 避免双重解释:
// **Bad** 某些代码求值
eval("alert('hello')");// **Bad** 创建新函数
var sayHi = new Function("alert('hello')");// **Bad** 设置超时
setTimeout("alert('hello')");
  • 性能的其他注意事项

    • 原生方法较快
    • switch语句较快:可以适当的替换ifelse语句case 的分支不要超过128条
    • 位运算符较快

3.3. 最小化语句数

3.3.1. 多个变量声明(废弃)

// 方式1:Bad
var count = 5;
var name = 'wdd';
var sex = 'male';
var age = 10;// 方式2:Good
var count = 5,name = 'wdd',sex = 'male',age = 10;

2017-03-07 理论上方式2可能要比方式1性能高一点。但是我在实际使用中,这个快一点几乎是没什么感受的。就像你无法感受到小草的生长一样。反而可读性更为重要。所以,每行最好只定义一个变量,并且每行都有一个var,并用分号结尾。

3.3.2. 插入迭代值

// Good
var name = values[i++];

3.3.3. 使用数组和对象字面量

// Good
var values = ['a','b','c'];var person = {name:'wdd',age:10
};

只要有可能,尽量使用数组和对象字面量的表达式来消除不必要的语句

3.4. 优化DOM交互

在JavaScript各个方面中,DOM无疑是最慢的一部分。DOM操作与交互要消耗大量的时间。因为他们往往需要重新渲染整个页面或者某一部分。进一步说,看似细微的操作也可能花很久来执行。因为DOM要处理非常多的信息。理解如何优化与DOM的交互可以极大的提高脚本完成的速度。
  • 使用dom缓存技术
  • 最小化现场更新
  • 使用innerHTML插入大段html
  • 使用事件代理

3.4.1. Dom缓存技术

调用频率非常高的dom查找,可以将DOM缓存在于一个变量中

// 最简单的dom缓存var domCache = {};function myGetElement(tag){return domCache[tag] = domCache[tag] || $(tag);
}

3.5. 避免过长的属性查找,设置一个快捷方式

// 先看下面的极端情况
app.user.mother.parent.home.name = 'wdd'
app.user.mother.parent.home.adderess = '上海'
app.user.mother.parent.home.weather = '晴天'// 更优雅的方式
var home = app.user.mother.parent.home;
home.name = 'wdd';
home.address = '上海',
home.weather = '晴天'

注意
使用上面的方式是有前提的,必须保证app.user.mather.parent.home是一个对象,因为对象是传递的引用。如果他的类型是一个基本类型,例如:number,string,boolean,那么复制操作仅仅是值传递,新定义的home的改变,并不会影响到app.user.mather.parent.home的改变。

4. 快捷方式

4.1. 字符串转数字

+'4.1' === 4.1

4.2. 数字转字符

4.1+'' === '4.1'

4.3. 字符串取整

'4.99' | 0 === 4

5. 通用编码原则

建议读者自行扩展

  • DRY(dont't repeat yoursele: 不要重复你自己)
  • 高内聚低耦合
  • 开放闭合
  • 最小意外
  • 单一职责(single responsibility)

6. 高级技巧

6.1. 安全类型检测

  • javascript内置类型检测并不可靠
  • safari某些版本(<4)typeof正则表达式返回为function

建议使用Object.prototype.toString.call()方法检测数据类型

function isArray(value){return Object.prototype.toString.call(value) === "[object Array]";
}function isFunction(value){return Object.prototype.toString.call(value) === "[object Function]";
}function isRegExp(value){return Object.prototype.toString.call(value) === "[object RegExp]";
}function isNativeJSON(){return window.JSON && Object.prototype.toString.call(JSON) === "[object JSON]";
}

对于ie中一COM对象形式实现的任何函数,isFunction都返回false,因为他们并非原生的javascript函数。

在web开发中,能够区分原生与非原生的对象非常重要。只有这样才能确切知道某个对象是否有哪些功能

以上所有的正确性的前提是:Object.prototype.toString没有被修改过

6.2. 作用域安全的构造函数

function Person(name){this.name = name;
}//使用new来创建一个对象
var one = new Person('wdd');//直接调用构造函数
Person();

由于this是运行时分配的,如果你使用new来操作,this指向的就是one。如果直接调用构造函数,那么this会指向全局对象window,然后你的代码就会覆盖window的原生name。如果有其他地方使用过window.name, 那么你的函数将会埋下一个深藏的bug。

那么,如何才能创建一个作用域安全的构造函数?

function Person(name){if(this instanceof Person){this.name = name;}else{return new Person(name);}
}

6.3. 惰性载入函数

假设有一个方法X,在A类浏览器里叫A,在b类浏览器里叫B,有些浏览器并没有这个方法,你想实现一个跨浏览器的方法。

惰性载入函数的思想是:在函数内部改变函数自身的执行逻辑

function X(){if(A){return new A();}else{if(B){return new B();}else{throw new Error('no A or B');}}
}

换一种写法

function X(){if(A){X = function(){return new A();};}else{if(B){X = function(){return new B();};}else{throw new Error('no A or B');}}return new X();
}

6.4. 防篡改对象

6.4.1. 不可扩展对象 Object.preventExtensions

// 下面代码在谷歌浏览器中执行
> var person = {name: 'wdd'};
undefined
> Object.preventExtensions(person);
Object {name: "wdd"}
> person.age = 10
10
> person
Object {name: "wdd"}
> Object.isExtensible(person)
false

6.4.2. 密封对象Object.seal

密封对象不可扩展,并且不能删除对象的属性或者方法。但是属性值可以修改。

> var one = {name: 'hihi'}
undefined
> Object.seal(one)
Object {name: "hihi"}
> one.age = 12
12
> one
Object {name: "hihi"}
> delete one.name
false
> one
Object {name: "hihi"}

6.4.3. 冻结对象 Object.freeze

最严格的防篡改就是冻结对象。对象不可扩展,而且密封,不能修改。只能访问。

6.5. 高级定时器

6.5.1. 函数节流

函数节流的思想是:某些代码不可以没有间断的连续重复执行

var processor = {timeoutId: null,// 实际进行处理的方法performProcessing: function(){...},// 初始化调用方法process: function(){clearTimeout(this.timeoutId);var that = this;this.timeoutId = setTimeout(function(){that.performProcessing();}, 100);}
}// 尝试开始执行
processor.process();

6.5.2. 中央定时器

页面如果有十个区域要动态显示当前时间,一般来说,可以用10个定时来实现。其实一个中央定时器就可以搞定。

中央定时器动画 demo地址:http://wangduanduan.coding.me...

var timers = {timerId: 0,timers: [],add: function(fn){this.timers.push(fn);},start: function(){if(this.timerId){return;}(function runNext(){if(timers.timers.length > 0){for(var i=0; i < timers.timers.length ; i++){if(timers.timers[i]() === false){timers.timers.splice(i, 1);i--;}}timers.timerId = setTimeout(runNext, 16);}})();},stop: function(){clearTimeout(timers.timerId);this.timerId = 0;}};

7. 函数式编程

推荐阅读:JS函数式编程中文版

8. HTML的告诫

  • 使用input的时候,一定要加上maxlength属性。(你以为只需要输入一个名字的地方,用户可能复制一篇文章放进去。)
  • 从input取值的时候,最好去除一下首尾空格

9. ajax的告诫

ajax在使用的时候,例如点击按钮,获取某个列表。需要注意以下方面

  1. ajax请求还没有结束时,按钮一定要disabled,防止多次点击。请求结束时,才去掉按钮的disabled属性。
  2. 请求没结束的时候,一定要显示一个gif的动画,告诉用户请求还在loading。不要让用户以为这垃圾程序又卡死了。
  3. 请求的结果如果是空的,一定要告诉用户: 很抱歉,暂时没有查询到相关记录之类的话语。不要给一个空白页面给用户。
  4. 最好考虑到请求报错的情况,给出友好的错误提醒。

10. 代码整洁之道

10.1. 函数整洁

  • 尽量将所有代码封装在函数中,不要暴露全局变量
  • 每个函数的函数体中,代码行越少越好,最好一个函数中就一句代码

11. 工程化与模块化

11.1. 前端构建工具必不可少

11.1.1. webpack

11.1.2. rollup

11.1.3. parcel

12. 协议 TCP IP HTTP

如果你认为前端不需要关于协议的知识,那么你就是大错特错了。其实不仅仅是前端,所有的开发者都应该学习底层的协议。因为他们是互联网通信的基石。

推荐三本必读的书籍
  • HTTP权威指南
  • 图解TCP/IP : 第5版
  • 图解HTTP

或者你一也可以看看关于协议方面的一些问题,以及如果你遇到过,你是否知道如何解决:

  • 可能被遗漏的https与http的知识点
  • 哑代理 - TCP链接高Recv-Q,内存泄露的罪魁祸首

13. 推荐深度阅读

13.1. 推荐阅读技术书籍

  • 编写可读代码的艺术
  • 编写可维护的JavaScript
  • JavaScript忍者秘籍(第2版)
  • JavaScript语言精粹
  • HTTP权威指南
  • 图解TCP/IP : 第5版
  • 图解HTTP
  • 代码整洁之道

13.2. 推荐阅读在线文章

  • Writing Fast, Memory-Efficient JavaScript
  • JavaScript 秘密花园
  • You-Dont-Know-JS
  • 关于缓存,你应该链接的一切
  • JS函数式编程中文版

13.3. 技术之外

  • 筑巢引凤-高黏度社会化网站设计秘诀
  • 黑客与画家

14. 参考文献

  • JavaScript高级程序设计(第3版) 【美】尼古拉斯·泽卡斯
  • Maintainable JavaScript (英文版) Nicholas C. Zakas(其实和上边那本书应该是同一个人)
  • JavaScript忍者秘籍 John Resig / Bear Bibeault (John Resig 大名鼎鼎jQuery的创造者)
  • 百度前端研发部 文档与源码编写风格
  • js函数式编程指南
  • JavaScript SDK Design Guide: JavaScript-sdk设计指南

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/542476.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

运用多种设计模式的综合案例_SpreadJS 纯前端表格控件应用案例:表格数据管理平台...

由某科技公司研发的表格数据管理平台&#xff0c;是一款面向业务和企业管理系统定制开发的应用平台&#xff0c;包括类 Excel 设计器、PC应用端和移动应用端等应用模块。该平台具备强大的业务配置和集成开发能力&#xff0c;对于企业客户的信息系统在管理模式、业务流程、表单界…

VS中C++ 项目重命名

应该都有过这样的经历&#xff0c;在Visual studio中创建解决方案&#xff0c;添加几个项目进去&#xff0c;然后开始愉快的敲代码...。写代码正欢的时候&#xff0c;却总是感觉那里有些不舒服&#xff0c;一细看&#xff0c;这项目名称取的真心挫&#xff0c;修改个吧。直接右…

axure9数据统计插件_WMDA:大数据技术栈的综合实践

一、概述WMDA是58自主开发的用户行为分析产品&#xff0c;同时也是一款支持无埋点的数据采集产品&#xff0c;只需要在第一次使用的时候加载一段SDK代码&#xff0c;即可采集全量、实时的PC、M、APP三端以及小程序的用户行为数据。同时&#xff0c;为了满足用户个性化的数据采集…

openfoam安装中出现allmake error_如何更新OpenFOAM的版本?

这是协作翻译的第四章&#xff0c;翻译完感觉挺有意思的&#xff0c;分享给大家一起看看。4.更新OpenFOAM版本4.1 版本管理OpenFOAM以两种不同的方式分发。一种方式是使用Git仓库下载的仓库版本。仓库版本的版本号由附加的x标记&#xff0c;例如 OpenFOAM2.1.x。该版本会经常更…

相同布局在不同手机上显示不同_不懂响应式,不同尺寸屏幕下的页面很难达到最佳效果...

让用户在不同设备和尺寸的屏幕下看的页面显示效果更佳&#xff0c;屏幕空间利用更高&#xff0c;操作体验更统一&#xff0c;交互方式更符合习惯。本文主要围绕什么是响应式&#xff0c;如何搭建响应系统&#xff0c;响应式网站解析 三个部分进行阐述&#xff0c;在项目中提前定…

markdown 流程图_测试了12款Markdown编辑器,推荐一个最好用的!

有很多喜欢写博客的小伙伴问我&#xff0c;这个代码笔记的格式怎么弄的简洁又好看&#xff0c;虽然csdn里面有Markdown的书写模式&#xff0c;但是我还是想推荐一款比较好用的写笔记的编辑器 - Typora。相信很多小伙伴都在使用吧&#xff0c;这个一直是我最喜欢的 markdown 编辑…

mysql多行合并成一行_数据文件合并与拆分

在数据处理业务中&#xff0c;经常要把文件结构相同或近似相同的数据文件合并成一个文件&#xff0c;或者将一个比较大的数据文件拆分成小的数据文件。本文将介绍文本文件和 Excel 文件合并及拆分会遇到的几种情况&#xff0c;并提供用 esProc SPL 编写的代码示例。esProc 是专…

suse linux增加新磁盘分区,Virtualbox中Linux添加新磁盘并创建分区

引言&#xff1a;我们常常在使用系统的时候突然发现&#xff0c;哎呦~~~我们的磁盘空间不够用啦&#xff01;我遇到常见的就是数据库数据暴增&#xff0c;预留的空间没有啦&#xff0c;只好新添加磁盘&#xff0c;在VB虚拟机上就可以实现&#xff0c;往往苦于没有图文并茂的好资…

arcgis字段计算器无法赋值_Arcgis空间连接工具的妙用

​Arcgis功能真的无比强大&#xff0c;读书时一般只会用到一些常见的&#xff0c;工作后挖掘了很多新功能&#xff0c;数据处理效率大幅提升&#xff0c;个人觉得arcgis是最强大最好用的gis软件&#xff01;本节给大家分享下空间连接功能的两个妙用。空间连接功能很多giser应该…

SpringMVC Mybatis Shiro RestTemplate的实现客户端无状态验证及访问控制【转】

2019独角兽企业重金招聘Python工程师标准>>> A.首先需要搭建SpringMVCShiro环境 a1.pom.xml配置 spring: <dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId><version>4.1.0.RELEAS…

sql服务器默认密码_搭建一个DNS服务器,轻松实现域名解析内容分发,访问速度提高N倍...

DNS服务器&#xff0c;Domain Name Server&#xff0c;域名解析服务器&#xff0c;互联网上相互通信使用的是IP&#xff0c;但是IP是又长又臭又难记&#xff0c;所以创造了域名来解决IP难写难记的问题&#xff0c;记一个g.cn比203.208.50.127强过不知多少倍了。有了域名&#x…

linux .net 控制台应用程序,VisualStudioCode创建的asp.net core控制台程序部署到linux

1、asp.net core控制台程序static void Main(string[] args){int times10;while(times>0){Console.WriteLine("Hello World!");times--;Thread.Sleep(1000);}}2、发布发布前&#xff0c;修改test2.csproj文件(项目名称为test2)Exenetcoreapp2.1centos.7-x64主要添…

linux系统怎样写单片机程序,单片机知识是Linux驱动开发的基础之一以及如何学单片机...

这是arm裸机1期加强版第1课第2、3节课程的wiki文字版。为什么没前途也要学习单片机&#xff1f;因为它是个很好的入口。学习单片机可以让我们抛开复杂的软件结构&#xff0c;先掌握硬件操作&#xff0c;如&#xff1a;看原理图、芯片手册、写程序操作寄存器等。在上一节视频里&…

bat 批处理 常用命令和乱码问题

为什么80%的码农都做不了架构师&#xff1f;>>> rem echo off ECHO OFF XCOPY E:\test.bat D:\ IF ERRORLEVEL 1 ECHO 文件拷贝Failure IF ERRORLEVEL 0 ECHO 文件拷贝Success :start set /p first"1记事本,2远程:" if %first% LEQ 2 (IF %first% …

SuperMap iServer发布的ArcGIS REST 地图服务如何通过ArcGIS API加载

作者&#xff1a;yx 文章目录 一、发布服务二、代码加载三、结果展示 一、发布服务 SuperMap iServer支持将地图发布为ArcGIS REST地图服务&#xff0c;您可以在发布服务时直接勾选ArcGIS REST地图服务&#xff0c;如下图所示&#xff1a; 也可以在已发布的地图服务中&#x…

new file会创建文件吗_Rust 文件系统处理之文件读写 Rust 实践指南

Rust 中&#xff0c;文件读写处理简单而高效。代码也很紧凑&#xff0c;容易阅读。我们从读取文件的字符串行、避免读取写入同一文件、使用内存映射随机访问文件这三个文件处理中的典型案例来了解一下。文件处理场景大家都很熟悉&#xff0c;因此闲言少叙&#xff0c;直接看代码…

【Maven学习笔记(二)】Maven的安装与配置

为什么80%的码农都做不了架构师&#xff1f;>>> 1、默认本地仓库路径 C:\Users\97449\.m2\repository 2、修改本地仓库路径 打开D:\apache-maven\conf\settings.xml <?xml version"1.0" encoding"UTF-8"?><!-- Licensed to the Apa…

npm 全局安装vuecli报错_cnn explainer本地使用--被npm坑惨

最近在知乎上面看到&#xff0c;看到一个cnn解释器&#xff0c;把每个步揍都很清楚的展示了出来&#xff0c;我想自己搞来玩玩。第一次使用npm&#xff0c;很多地方不会&#xff0c;第一步&#xff1a;先在网页上下载下来cnn_explainer&#xff0c;然后解压在没有中文路径的文件…

Python程序从给定的N个数字中找到最大倍数

Here, we will be framing code for finding the maximum multiple of a number x from a given set of a number (set of 5 numbers in this program). 在这里&#xff0c;我们将使用成帧代码&#xff0c; 从给定的一组数字(此程序中的5个数字组成的集合)中找到x的最大倍数 。…

openmpi安装_Intel Parallel Studio XE 2019安装设置

1.Intel Parallel Studio XE 2019简介Intel Parallel Studio XE 是Intel在单独一款软件开发套件中整合了英特尔公司业界领先的 C/C 和 Fortran 编译器、性能和MPI并行库、错误检查、代码健壮和性能分析的工具&#xff0c;有助于大幅提升应用程序性能&#xff0c;同时提高代码质…