首页 文章 精选 留言 我的

精选列表

搜索[JavaScript],共9118篇文章
优秀的个人博客,低调大师

Python全栈 Web(JavaScript 数组、string、正则、Math、Date)

数组: 常用的API: toString() 将数组转换为字符串 默认是将数组的元素 使用逗号隔开 链接成字符串在进行返回 join(seperator) 将数组的元素使用seperator字符串作为分隔符 链接成字符串再进行返回 reverse() 将数组进行反转 该函数会改变现有数组的结构 不需要接受返回值 sort() 对数组的元素进行排序 默认按照Unicode码进行排序 对数字不准确 会改变原有数组的内容 特点: 允许自定义的排序规则(排序函数)用来指定数组的排序方式 语法: arr.sort(排序函数); 排序函数: 升序的排序函数: function sortAsc(a, b){ return a - b; } arr.sort(sortAsc); 匿名函数实现: arr.sort(function(a, b){ return a - b; }) 降序排序: 排序后

优秀的个人博客,低调大师

JavaScript函数式编程之pointfree与声明式编程

更多相关内容见博客 github.com/zhuanyongxi… 函数式编程中的pointfree的意思就是“无参”或“无值”,pointfree style是一种编程范式,也作tacit programming,就是“无参编程”的意思了。什么是“无参编程”? // 这就是有参的,因为有word var snakeCase = word => word.toLowerCase().replace(/\s+/ig, '_'); // 这是pointfree var snakeCase = compose(replace(/\s+/ig, '_'), toLowerCase); 从另一个角度看,有参的函数的目的是得到一个数据,而pointfree的函数的目的是得到另一个函数。 所以,如下的方程,虽然也有参,也可以认为是pointfree的。 const titlesForYear = year => pipe( filter(publishedInYear(year)), map(book => book.title) ) 那这pointfree有什么用? 它可以让我们把注意力集中在函数上,参数命名的麻烦肯定是省了,代码也更简洁优雅。 需要注意的是,一个pointfree的函数可能是由众多非pointfree的函数组成的,也就是说底层的基础函数大都是有参的,pointfree体现在用基础函数组合而成的高级函数上。如果我们使用函数式编程的工具,如ramda,这些基础函数大都已经被写好了,这样我们去写pointfree的代码就很容易了。 什么是声明式编程?它区别于命令式编程 // 命令式 var words = []; for (i = 0; i < otherWords.length; i++) { words.push(otherWords[i].word); } // 声明式 var words = otherWords.map(function(ele){ return ele.word; }); 容易看出,命令式的代码,我们不但要去遍历,还要关注如何遍历。而声明式的就容易很多,可以节省我们的注意力,代码也更加简洁。 其他的命令式的写法有:使用ifelse进行的条件判断,使用算数运算符进行的算数运算,使用比较运算符进行的比较运算和使用逻辑运算符进行的逻辑运算。 至于那些说“虽然如此,但使用命令式循环速度要快很多”的人,我建议你们先去学学 JIT 优化代码的相关知识。这里有一个非常棒的视频,可能会对你有帮助。 需要注意的是,要实现这种声明式的编程,首先我们要有这个map方法,这一点与pointfree相同,都是需要我们先对常用的操作做一次封装,而这些常用的操作本身还是命令式的。 pointfree的声明式代码是函数式编程应该有的样子。 最后用一个来自Scott Sauyet的文章《Favoring Curry》中的例子,使用的函数式工具是ramda。下面的代码不需要一句一句的看,大概体会一下就可以了。 一组JSON数据 var data = { result: "SUCCESS", interfaceVersion: "1.0.3", requested: "10/17/2013 15:31:20", lastUpdated: "10/16/2013 10:52:39", tasks: [ {id: 104, complete: false, priority: "high", dueDate: "2013-11-29", username: "Scott", title: "Do something", created: "9/22/2013"}, {id: 105, complete: false, priority: "medium", dueDate: "2013-11-22", username: "Lena", title: "Do something else", created: "9/22/2013"}, {id: 107, complete: true, priority: "high", dueDate: "2013-11-22", username: "Mike", title: "Fix the foo", created: "9/22/2013"}, {id: 108, complete: false, priority: "low", dueDate: "2013-11-15", username: "Punam", title: "Adjust the bar", created: "9/25/2013"}, {id: 110, complete: false, priority: "medium", dueDate: "2013-11-15", username: "Scott", title: "Rename everything", created: "10/2/2013"}, {id: 112, complete: true, priority: "high", dueDate: "2013-11-27", username: "Lena", title: "Alter all quuxes", created: "10/5/2013"} // , ... ] }; 需求是找到Scott所有未完成的任务,并按照到期日期升序排列。 正确的结果是 [ {id: 110, title: "Rename everything", dueDate: "2013-11-15", priority: "medium"}, {id: 104, title: "Do something", dueDate: "2013-11-29", priority: "high"} ] 命令式的代码如下 getIncompleteTaskSummaries = function(membername) { return fetchData() .then(function(data) { return data.tasks; }) .then(function(tasks) { var results = []; for (var i = 0, len = tasks.length; i < len; i++) { if (tasks[i].username == membername) { results.push(tasks[i]); } } return results; }) .then(function(tasks) { var results = []; for (var i = 0, len = tasks.length; i < len; i++) { if (!tasks[i].complete) { results.push(tasks[i]); } } return results; }) .then(function(tasks) { var results = [], task; for (var i = 0, len = tasks.length; i < len; i++) { task = tasks[i]; results.push({ id: task.id, dueDate: task.dueDate, title: task.title, priority: task.priority }) } return results; }) .then(function(tasks) { tasks.sort(function(first, second) { var a = first.dueDate, b = second.dueDate; return a < b ? -1 : a > b ? 1 : 0; }); return tasks; }); }; pointfree的代码 var getIncompleteTaskSummaries = function(membername) { return fetchData() .then(R.prop('tasks')) .then(R.filter(R.propEq('username', membername))) .then(R.reject(R.propEq('complete', true))) .then(R.map(R.pick(['id', 'dueDate', 'title', 'priority']))) .then(R.sortBy(R.prop('dueDate'))); }; pointfree的声明式的代码 // 提取 tasks 属性 var SelectTasks = R.prop('tasks'); // 过滤出指定的用户 var filterMember = member => R.filter( R.propEq('username', member) ); // 排除已经完成的任务 var excludeCompletedTasks = R.reject(R.propEq('complete', true)); // 选取指定属性 var selectFields = R.map( R.pick(['id', 'dueDate', 'title', 'priority']) ); // 按照到期日期排序 var sortByDueDate = R.sortBy(R.prop('dueDate')); // 合成函数 var getIncompleteTaskSummaries = function(membername) { return fetchData().then( R.pipe( SelectTasks, filterMember(membername), excludeCompletedTasks, selectFields, sortByDueDate, ) ); }; 参考文章 Pointfree编程风格指南 Favoring Curry JS函数式编程指南 Tacit programming Thinking in Ramda: Pointfree Style Thinking in Ramda: Declarative Programming 原文发布时间为:2018年06月17日 原文作者:砖用冰西瓜 本文来源:掘金如需转载请联系原作者

优秀的个人博客,低调大师

【JavaScript框架封装】数据类型检测模块功能封装

版权声明:本文为博主原创文章,未经博主允许不得转载。更多学习资料请访问我爱科技论坛:www.52tech.tech https://blog.csdn.net/m0_37981569/article/details/80984381 数据类型检测封装后的最终模块代码如下: /*数据类型检验*/ xframe.extend(xframe, { // 鸭子类型(duck typing)如果它走起路来像鸭子,叫起来也是鸭子,那么它就是鸭子。 // 只关注对象的行为,不关注对象本身面向接口编型 ,而不是面向实现编程,是设计模式中最重要的思想。 // 【理解】:一个对象有效的语义,不是由集成自特定的类或实现特定的接口, 而是由当前方法和属性的集合决定的!!! isNumber: function (val) { // 如果这个数字是有限的话, 而且是数字类型 return (typeof val === 'number' && isFinite(val)) && (Object.prototype.toString.call(val) === '[object Number]'); }, /*** * 判断一个变量是不是Boolean类型 * @param val * @returns {boolean} */ isBoolean: function (val) { return (typeof val === 'boolean') && (Object.prototype.toString.call(val) === '[object Boolean]'); }, /** * 判断一个变量是不是字符串类型 * @param val * @returns {boolean} */ isString: function (val) { return (typeof val === 'string') && (Object.prototype.toString.call(val) === '[object String]'); }, /** * 判断一个变量是不是undefined * @param val * @returns {boolean} */ isUndefined: function (val) { // oid 0 is a correct and standard way to produce undefined. return (val === void 0) || (typeof val === 'undefined') && (Object.prototype.toString.call(val) === '[object Undefined]'); }, /** * 判断一个变量是不是为空 * @param val * @returns {boolean} */ isNull: function (val) { return (val === null) && (Object.prototype.toString.call(val) === '[object Null]'); }, /** * 检测 * @param obj * @returns {*} */ isNaN: function (val) { // 只要这个数字通过判断是不是和他自身相同或者使用typef的方式去检测 return val !== val; }, /** * 判断一个变量是不是一个对象类型 * @param val * @returns {boolean} */ isObject: function (val) { if (val !== null && val !== undefined) { if ((typeof val === 'object') && (Object.prototype.toString.call(val))) { return true; } } return false; }, /** * 判断一个对象是不是数组对象 * @param val * @returns {boolean|void|string} */ isArray: function (val) { // 判断上不是一个数组的先判断这个数组对象是不是为空, 因为如果val为空的话,就是val.constructor这个属性实际上是没有的,error if (val !== null || typeof val !== "undefined") { // 注意在使用constructor判断数据类型的时候比较的实际上是他的原型对象的constructor属性, 这个属性指向的实际上是这个变量的原型对象 return (val.constructor === Array) && (Object.prototype.toString.call(val)); } return false; } }); 知识要点总结: 1.判断一个对象的数据类型通常可以使用 Object.prototype.toString.call(val) 这种方式判断数据类型一般对于String,Boolean.Object,Array,NUll都是通用的一种检测方法,首先调用Object的原型对象里面的toString()方法,并使用call方法修改toString()函数中this的指向为val /* * 这是因为toString为Object的原型方法, * 而Array ,function等类型作为Object的实例,都重写了toString方法。 * 不同的对象类型调用toString方法时, * 根据原型链的知识,调用的是对应的重写之后的toString方法(function类型返回内容为函数体的字符串,Array类型返回元素组成的字符串.....), * 而不会去调用Object上原型toString方法(返回对象的具体类型), * 所以采用obj.toString()不能得到其对象类型,只能将obj转换为字符串类型;因此,在想要得到对象的具体类型时,应该调用Object上原型toString方法。 * * */ // 每一个原型都有自己的prototype都有自己的constructor和toString()方法 console.log(Object.prototype.toString.call("jerry"));//[object String] console.log(Object.prototype.toString.call(12));//[object Number] console.log(Object.prototype.toString.call(true));//[object Boolean] console.log(Object.prototype.toString.call(undefined));//[object Undefined] console.log(Object.prototype.toString.call(null));//[object Null] console.log(Object.prototype.toString.call({name: "jerry"}));//[object Object] console.log(Object.prototype.toString.call(function () { }));//[object Function] console.log(Object.prototype.toString.call([]));//[object Array] console.log(Object.prototype.toString.call(new Date));//[object Date] console.log(Object.prototype.toString.call(/\d/));//[object RegExp] 2.call,apply,bind的使用方法总结 // call和apply的使用方法总结----------------------------------------------------------------- window.color = 'red'; document.color = 'yellow'; var s1 = {color: 'blue' }; function changeColor(){ console.log(this.color); } // 注意call()里面传递的参数,就会把这个参数传给调用的函数,此时调用函数的内部里面的this实际上指向了传递过来的这个参数对象 changeColor.call(); //red (默认传递参数) changeColor.call(window); //red changeColor.call(document); //yellow changeColor.call(this); //red changeColor.call(s1); //blue window.firstName = "Cynthia"; window.lastName = "_xie"; var myObject = {firstName:'my', lastName:'Object'}; function getName(){ // 这个函数内部的this默认指向的是window,通过call和apply可以间接修改这个this的指向 console.log(this.firstName + this.lastName); } function getMessage(sex,age){ console.log(this.firstName + this.lastName + " 性别: " + sex + " age: " + age ); } getName.call(window); // Cynthia_xie getName.call(myObject); // myObject getName.apply(window); // Cynthia_xie getName.apply(myObject);// myObject getMessage.call(window,"女",21); //Cynthia_xie 性别: 女 age: 21 getMessage.apply(window,["女",21]); // Cynthia_xie 性别: 女 age: 21 getMessage.call(myObject,"未知",22); //myObject 性别: 未知 age: 22 getMessage.apply(myObject,["未知",22]); // myObject 性别: 未知 age: 22 总结: /* 1. apply()方法 接收两个参数,一个是函数运行的作用域(this),另一个是参数数组。 语法:apply([thisObj [,argArray] ]);,调用一个对象的一个方法,2另一个对象替换当前对象。 说明:如果argArray不是一个有效数组或不是arguments对象,那么将导致一个 TypeError,如果没有提供argArray和thisObj任何一个参数,那么Global对象将用作thisObj。 2. call()方法 第一个参数和apply()方法的一样,但是传递给函数的参数必须列举出来。 语法:call([thisObject[,arg1 [,arg2 [,...,argn]]]]);,应用某一对象的一个方法,用另一个对象替换当前对象。 说明: call方法可以用来代替另一个对象调用一个方法,call方法可以将一个函数的对象上下文从初始的上下文改变为thisObj指定的新对象,如果没有提供thisObj参数,那么Global对象被用于thisObj。 3. bind()方法通常用于修改一个函数内部this的指向,返回的是一个函数,但是不会立即调用,如果需要调用传递参数的话还需要自己手动调用这个函数 * * * */

优秀的个人博客,低调大师

使用JavaScript实现一个俄罗斯方块

清明假期期间,闲的无聊,就做了一个小游戏玩玩,目前游戏逻辑上暂未发现bug,只不过样子稍微丑了一些-.-项目地址:https://github.com/Jiasm/tetris在线Demo:http://blog.jiasm.org/tetris/?width=16&height=40(修改URL参数可以调整难度) 整体分成三块进行开发,使用面向对象式编程进行开发(其实我更喜欢用函数式编程,但苦于游戏的一些状态用对象来存储会更直观一些): Game: 负责生成新的方块 负责方块移动的处理 方块触底的判断 移除满足清除条件的行 Render: 负责用Game的数据来渲染整个游戏界面 Controller: 负责接受用户输入(上下左右各种操作)并处理 向用户反馈当前游戏的状态 这样分层带来了一个好处,我们游戏的逻辑Game模块并不依赖于当前程序运行的环境,而Render可以是Canvas、DOM,甚至是控制台输出。我们要移植到其他平台,只需要修改Render即可。 项目结构 忽略了一些与游戏没有直接关系的结构 . ├── model │ ├── Brick.js │ ├── Game.js │ └── index.js ├── utils │ ├── buildEnum.js │ ├── deepCopy.js │ ├── getShape.js │ ├── index.js │ ├── lineIndex.js │ ├── matrixString.js │ └── rotateArray.js ├── enum │ ├── gameType.js │ ├── index.js │ └── pointType.js ├── data │ └── shapes.js ├── controller │ └── index.js └── view ├── RenderCanvas.js └── index.js 各目录下的index.js是为了方便同时引用多个文件,大致长这个样子: export { default as model1 } from './model1' export { default as model2 } from './model2' 然后我们就可以在用到的地方写: import { model1, model2 } from './XXX' model 这里是游戏的核心逻辑所在位置。 像俄罗斯方块这种的矩阵类游戏,存储数据最合适的方法就是一个二维数组了。为了更直观一些,我们选择了游戏的高度作为第一层数组的长度: matrix = new Array(height).fill(new Array(width)) // width: 2 height: 4 [ [ 1, 1], [ 1, 1], [ 1, 1], [ 1, 1] ] 而且这样选择在一些逻辑处理上也会更方便一些: 下移操作时,我们只需改变元素的第一层下标 判断是否触底时,我们只需将当前下标 + 1 判断是否有元素即可 我们对数组中的元素进行了定义: 0: 空,表示当前坐标为空白 1: 新的方块,表示当前活动的方块 2: 老的方块,已经触底固定的方块 接下来,我们就遇到了一个问题,如何处理方块的放置。我们知道,游戏会不停的向棋盘中加载新的方块。如果我们每次处理下移的时候,都将当前二维数组中对应的方块元素移除,然后在塞入到新的位置,未免太过繁琐了。 所以我们在初始化数据时,初始化两个二维数组。当我们加载一个新的方块后,将方块对应的元素塞入其中的一个二维数组。然后等到我们有进行其他的操作时,比如左右移动,向下之类的。我们直接使用第二个二维数组覆盖到当前的数组中去,然后再将更改下标后的方块塞入数组。这样在数据上,我们就完成了方块的移动。 class Game { init () { // 初始化两个矩阵 this.matrix = [[], []] this.oldMatrix = [[], []] } move () { // 重置当前矩阵数据 this.matrix = deepCopy(this.oldMatrix) // 解除引用 // 加载方块数据 this.matrix[y][x1] = 1 this.matrix[y][x2] = 1 } } 左右移动的处理 左右的移动不能像向下移动一样,单纯的下标+1。我们需要判断当前的操作是否有效。比如右侧如果遇到了障碍物或者到达边缘,我们肯定是不能够再进行移动的。 // blend 为活动砖块的形状描述 [[1, 1, 1], [0, 1, 0]] 类似这样的结构 if ( x >= width - brickWidth || blend.some((row, rowIndex) => { let _pos = oldMatrix[y + rowIndex] return row && row[brickWidth - 1] && _pos && _pos[x + brickWidth] }) ) return // 右侧有障碍物,无法移动 使用类似这样的逻辑进行判断,保证当前方块向右移动后不会覆盖之前的方块。 快速向下的处理 我看有些游戏实现的,貌似下降触发只是加速下降而已(这种情况只需要改变定时下降的速度即可)-.-这里的实现是,直接触底 所以就会遇到一个问题,当前砖块最多可以下降到什么位置? [1, 1, 1] [0, 0, 0] [0, 2, 0] [2, 2, 2] 就像这样的一个数据,0|2这两列都可以向下移动两列,但是这样就会导致中间一列的重叠。我们一定要取出下降幅度最小的那个值。所以我们就要算出最后一行1的下标以及第一行2的下标,将这两个下标进行相减,最小值即为我们当前方块可下降的距离。 旋转方块的处理 旋转方块应该是游戏中比较复杂的一块逻辑了。绝不是仅仅简单的将方块的二维数组由行改为列,在有些时候,我们还需要判断方块是否可以进行旋转。就像这样的,中间的绿色长条是不能够进行旋转的。所以我们要先拿到旋转后的数据,来与当前游戏中的数据进行比较,检验是否会出现重叠的情况,如果出现了,则表示不能够进行旋转。 触底检测 每完成一个移动的动作后,我们都需要进行方块的触底检测。也就是判断当前方块下,是否已经有元素占位,如果有的话,则表示已经触底了,当前元素就会被固定进矩阵数组中。同样的,我们在判断时,不需要将方块所有的下标都检查一遍,只需要检查最底部一层的有效元素即可。 [1, 1], [0, 1], [0, 1], 像这样的一个方块,我们仅需要判断第一列的第二行&第二列的第四行是否有元素即可完成检查。 移除行 当某一行被填满元素后,我们就要将它进行移除。在触底检测触发后,如果有方块被固定进数组,此时我们再进行移除行的操作。因为如果没有新的方块进入,移除行的这步操作就不是必要的。同时,得分的计数也应该在此处进行,我们将移除的行数进行记录,获取到的行数便是得分了。 至此,所有有关矩阵数据的操作就结束了。Game对象只去维护这么一个二维数组,对象本身不包含任何游戏相关的操作,只会在被调用时进行对应的处理。然后生成新的二维数组。 utils 这里放置了一些比较通用的方法,用来提高开发效率使用。比如获取方块最底部一层的下标之类的工具函数。 enum 存放了一些状态的枚举,游戏状态以及方块所对应的状态,类似这样的数据: { empty: 0, newBrick: 1, oldBrick: 2 } data 存放了游戏中各种使用到的方块信息。正方形,梯形之类的方块在二维数组中所对应的描述。 controller 就是上边我们所说的,用来与用户交互的模块,由Controller来获取游戏相关的信息,并调用Render进行渲染。监听键盘事件,在页面中渲染一些控制按钮。以及定时触发Game的下落方法。 view 游戏界面的渲染部分,目前选定的是使用canvas,所以只写了RenderCanvas。在渲染的这部分,稍微做了一些优化处理,将活动中的方块与固定的方块进行分开渲染。这样在用户操作上下左右移动时,并不会重新渲染整个游戏布局,而只是渲染活动方块的canvas。 小记 两天多的时间进行开发,其中有半天时间在修复FlowType的Warning提示。。。搞完了以后,觉得实现这个的主要难点就在于方块旋转&触底的判断这里了。能够清晰的管理游戏对应的二维数组,这个游戏开发起来就会很顺畅。 界面还有待优化。 Tips 我的博客即将搬运同步至腾讯云+社区,邀请大家一同入驻:https://cloud.tencent.com/developer/support-plan?invite_code=1vas1z072yivn

资源下载

更多资源
Mario

Mario

马里奥是站在游戏界顶峰的超人气多面角色。马里奥靠吃蘑菇成长,特征是大鼻子、头戴帽子、身穿背带裤,还留着胡子。与他的双胞胎兄弟路易基一起,长年担任任天堂的招牌角色。

腾讯云软件源

腾讯云软件源

为解决软件依赖安装时官方源访问速度慢的问题,腾讯云为一些软件搭建了缓存服务。您可以通过使用腾讯云软件源站来提升依赖包的安装速度。为了方便用户自由搭建服务架构,目前腾讯云软件源站支持公网访问和内网访问。

Spring

Spring

Spring框架(Spring Framework)是由Rod Johnson于2002年提出的开源Java企业级应用框架,旨在通过使用JavaBean替代传统EJB实现方式降低企业级编程开发的复杂性。该框架基于简单性、可测试性和松耦合性设计理念,提供核心容器、应用上下文、数据访问集成等模块,支持整合Hibernate、Struts等第三方框架,其适用范围不仅限于服务器端开发,绝大多数Java应用均可从中受益。

WebStorm

WebStorm

WebStorm 是jetbrains公司旗下一款JavaScript 开发工具。目前已经被广大中国JS开发者誉为“Web前端开发神器”、“最强大的HTML5编辑器”、“最智能的JavaScript IDE”等。与IntelliJ IDEA同源,继承了IntelliJ IDEA强大的JS部分的功能。

用户登录
用户注册