1.JS设计模式片段
Function.prototype.addMethod = function (name,fn) {
this.prototype[name] = fn;
return this;
};
var Methods = (){};
Methods.addMethod('checkName', () {
//验证姓名
console.log('姓名');
}).addMethod('checkEmail',1)">验证邮箱
console.log('邮箱');
});
var m = new Methods();
m.checkName();
m.checkEmail();
2.canvas图片预加载及进度条的实现
/*star
*loading模块
*实现图片的预加载,并显示进度条
*参数:图片数组对象,加载完成的回调函数
*/
loadImages(sources,callback){
var loadedImages = 0;
var numImages = 0;
ctx.font='14px bold';
ctx.lineWidth=5;
var clearWidth=canvas.width;
var clearHeight=canvas.height;
get num of sources
for (var src in sources) {
numImages++;
}
sources) {
images[src] = Image();
当一张图片加载完成时执行
images[src].onload = (){
重绘一个进度条
ctx.clearRect(0,0,clearWidth,clearHeight);
ctx.fillText('Loading:'+loadedImages+'/'+numImages,200,280);
ctx.save();
ctx.strokeStyle='#555';
ctx.beginPath();
ctx.moveTo(200,300);
ctx.lineTo(600,1)">);
ctx.stroke();
ctx.beginPath();
ctx.restore();
ctx.moveTo(200,1)">);
ctx.lineTo(loadedImages/numImages*400+200,300);
ctx.stroke();
当所有图片加载完成时,执行回调函数callback
if (++loadedImages >= numImages) {
callback();
}
};
把sources中的图片信息导入images数组
images[src].src = sources[src];
}
}
定义预加载图片数组对象,执行loading模块
window.onload = (){
var sources = {
PaperBoy1: "images/run/PaperBoy1.png"
};
执行图片预加载,加载完成后执行main
loadImages(sources,main);
};
end*/
3.JS实现跨浏览器添加事件与移除事件怎样做才最优?
一般的兼容做法,如下:
跨浏览器添加事件
跨浏览器添加事件
addEvent(obj,type,fn){
if(obj.addEventListener){
obj.addEventListener(type,fn,1)">false);
}else if(obj.attachEvent){IE
obj.attchEvent('on'+type,fn);
}
}
跨浏览器移除事件
跨浏览器移除事件
removeEvent(obj,fn){
(obj.removeEventListener){
obj.removeEventListener(type,1)">);
}if(obj.detachEvent){兼容IE
obj.detachEvent('on'+
addEvent( obj,fn ) {
( obj.attachEvent ) {
obj['e'+type+fn] = fn;
obj[type+fn] = function(){obj['e'+type+fn]( window.event );}
obj.attachEvent( 'on'+type,obj[type+fn] );
} else
obj.addEventListener( type,1)"> );
}
removeEvent( obj,1)"> ( obj.detachEvent ) {
obj.detachEvent( 'on'+type,1)">fn] );
obj[type+fn] = null;
}
obj.removeEventListener( type,1)"> );
}
参考地址:
addEvent()
recoding contest entry
4.Ajax用jsonp方式跨域发送请求小实例
众所周知,Ajax是通过创建XMLHttpRequest对象或ActiveXObject来连接服务器、发送请求以及响应数据,但它却不能跨域。而在分布式系统中我们又需要跨域发送接受数据,于是jsonp出现了...
它是一种跨域请求方式,主要利用了script标签里的src属性,该属性可以跨域发送请求,然后服务器返回js代码,网页端便响应其信息,然后我们可以对其传过来的js代码做处理提取其中的信息。
jsonp发送请求只需在src后面添加“?callback=函数名”就可以,例如“http://www.item.com/list?callback=myfunction
",则只需在服务端接受参数myfunction
并将函数名与想要返回的数据拼接就可以例如在java中响应该请求,可以获取参数callback的值myfunction,再拼接成myfunction+"("+data+")"格式返回就行,在前端写同名函数接受data并处理就可以了。但在jquery中对jsonp进行了封装,返回函数就是success
,数据也用success接受。
例如:
前端代码:
发送请求
$.ajax({
url:"http://localhost:8081/rest/itemcat/list?callback=getMessage",url:"http://localhost:8081/rest/itemcat/message"这里定义了callback的参数名称,以便服务获取callback的函数名即getMessage
jsonpCallback:"getMessage",1)">这里定义了jsonp的回调函数
success:(data){
alert("success:"+data);
},error:(){
alert("发生异常");
}
});
getMessage(jsonp){
alert("message:"+jsonp);
}
这样发出的请求为:http://localhost:8081/rest/itemcat/message?callback=getMessage
jsonp:"callback",
jsonpCallback:"getMessage",
这两个参数的值会自动拼接在url后面,所以用jquery的$.ajax方法发出的url可以不用在后面添加callback=getMessag,返回函数则变为了success而不是getMessage
5.使用高德地图API创建地图以及获取当前地址经纬度
创建API地图带有点标记
<script src="http://webapi.amap.com/maps?v=1.4.1&key=bcf87f3263f98cc37309298bca20c622"></script>
type="text/javascript">
实例化点标记
addMarker() {
marker = AMap.Marker({
icon: "http://webapi.amap.com/theme/v1.3/markers/n/mark_b.png116.4139.91]
});
marker.setMap(map);
}
var map AMap.Map('containertrue116.40],zoom: 13
});
addMarker();
</>
根据浏览器定位获取当前经纬度
div id="container_display"div="https://webapi.amap.com/maps?v=1.4.1&key=bcf87f3263f98cc37309298bca20c622" loadingCurrentPosition(callback){
document.getElementById(container_display).innerHTML '';
加载地图,调用浏览器定位服务
map
});
map.plugin(AMap.Geolocation() {
geolocation AMap.Geolocation({
enableHighAccuracy: 是否使用高精度定位,默认:true
timeout: 10000超过10秒后停止定位,默认:无穷大
buttonOffset: AMap.Pixel(1020),1)">定位按钮与设置的停靠位置的偏移量,默认:Pixel(10,20)
zoomToAccuracy: 定位成功后调整地图视野范围使定位位置及精度范围视野内可见,默认:false
buttonPosition:RB
});
map.addControl(geolocation);
geolocation.getCurrentPosition();
AMap.event.addListener(geolocation,1)">complete返回定位信息
AMap.event.addListener(geolocation,1)">error返回定位出错信息
});
解析定位结果
onComplete(data) {
getLngdata = data.position.getLng();
getLatdata data.position.getLat();
(callback){
callback(getLngdata,getLatdata); 回调参数中传递经度与纬度
}
}
解析定位错误信息
onError(data) {
alert(定位失败);
}
}
$((){
getLng ; 存经度
getLat 存纬度
默认加载一次自动获取当前人的位置
loadingCurrentPosition((lngdata,Latdata){
getLng lngdata;
getLat Latdata;
});
$(.getCurrentPosition).on(click(){
loadingCurrentPosition( lngdata;
getLat Latdata;
});
});
})
>
高德地图根据浏览器定位获取当前经纬度API案例地址:http://lbs.amap.com/api/javascript-api/example/location/browser-location
高德开放平台:http://lbs.amap.com/api
6.JS创建canvas学习小例代码
1.HTML5中的Canvas标签的创建
window.onload = (){
createCanvas();
}
createCanvas(){
var canvas_width= 200,canvas_height = 200;
document.body.innerHTML = "<canvas id=\"canvas\" width=\""+canvas_width+"\" height=\""+canvas_height+"\"></canvas>";
}
2.HTML5Canvas标签绘制图形
var canvas_width= 500,canvas_height = 500;
mycanvas,context;
window.onload = (){
createCanvas();
drawRect();
}
createCanvas(){
document.body.innerHTML = "<canvas id=\"mycanvas\" width=\""+canvas_width+"\" height=\""+canvas_height+"\"></canvas>";
mycanvas = document.getElementById("mycanvas");
context = mycanvas.getContext("2d");
}
drawRect(){
context.fillStyle ="#FF0000"context.rotate(45);//旋转45度
context.translate(200,200);//移动
context.scale(2,0.5);//缩放
context.fillRect(0,200);
}
(){
createCanvas();
drawImage();
}
createCanvas(){
document.body.innerHTML = "<canvas id=\"mycanvas\" width=\""+canvas_width+"\" height=\""+canvas_height+"\"></canvas>";
mycanvas = document.getElementById("mycanvas");
context = mycanvas.getContext("2d" drawImage(){
var img = Image();
img.onload = (){
context.drawImage(img,1)">);
}
img.src = "1.png";
}
7.Promise里的代码为什么比setTimeout先执行实例
Promise和setTimeout实例
我们把宿主发起的任务称为宏观任务,把 JavaScript 引擎发起的任务称为微观任务。许多的微观任务的队列组成了宏观任务。
为了理解微任务始终先于宏任务,我们设计一个实验:执行一个耗时 1 秒的 Promise。
setTimeout(()=> console.log('d'),1)">); var r = new Promise(function(resolve,reject){ resolve(); }); r.then(() => { var begin = Date.now(); while(Date.now() - begin < 1000); console.log("c1"); )); }) //c1 c2 d
这里我们强制了 1 秒的执行耗时,这样,我们可以确保任务 c2 是在 d 之后被添加到任务队列。
我们可以看到,即使耗时一秒的 c1 执行完毕,再 enque 的 c2,仍然先于 d 执行了,这很好地解释了微任务优先的原理。
再看一个复杂点的例子:
sleep(duration) { return ); setTimeout(resolve,duration); }) } console.log("a"); sleep(5000).then(()=>console.log("c")); a b c
这是一段非常常用的封装方法,利用 Promise 把 setTimeout 封装成可以用于异步的函数。
我们首先来看,setTimeout 把整个代码分割成了 2 个宏观任务,这里不论是 5 秒还是 0 秒,都是一样的。
第一个宏观任务中,包含了先后同步执行的 console.log(“a”); 和 console.log(“b”);。
setTimeout 后,第二个宏观任务执行调用了 resolve,然后 then 中的代码异步得到执行,所以调用了 console.log(“c”),最终输出的顺序才是: a b c。
Promise 是 JavaScript 中的一个定义,但是实际编写代码时,我们可以发现,它似乎并不比回调的方式书写更简单,但是从 ES6 开始,我们有了 async/await,这个语法改进跟 Promise 配合,能够有效地改善代码结构。
新特性:async/await
async/await 是 ES2016 新加入的特性,它提供了用 for、if 等代码结构来编写异步的方式。它的运行时基础是 Promise,面对这种比较新的特性,我们先来看一下基本用法。
async 函数必定返回 Promise,我们把所有返回 Promise 的函数都可以认为是异步函数。
async 函数是一种特殊语法,特征是在 function 关键字之前加上 async 关键字,这样,就定义了一个 async 函数,我们可以在其中使用 await 来等待一个 Promise。
foo(){ console.log("a") await sleep(2000) console.log("b") } foo(); a b
这段代码利用了我们之前定义的 sleep 函数。在异步函数 foo 中,我们调用 sleep。
async 函数强大之处在于,它是可以嵌套的。我们在定义了一批原子操作的情况下,可以利用 async 函数组合出新的 async 函数。
foo(name){ await sleep(2000) console.log(name); } async foo2(){ await foo('a'); await foo('b'); } foo2(); a b
练习:我们现在要实现一个红绿灯,把一个圆形 div 按照绿色 3 秒,黄色 1 秒,红色 2 秒循环改变背景色。
( (){ var btn = document.getElementById('status'); sleep(duration){ changeColor(duration,color){ btn.style.background = color; await sleep(duration); }; async fn(){ while(true){ await changeColor(3000,'green'); await changeColor(1000,'yellow'); await changeColor(2000,'red'); } } fn(); })();
8.正则匹配设置电话号码格式为XXX-XXXX-XXXX
var _formatType = 'XXX-XXXX-XXXX'; var i= 0var phone = '15510900909'var result = _formatType.replace(/X/g,1)">() { return phone[i++]; });
9.语音播报
语音播报:在项目中需要对ajax请求返回的消息进行语音播报,str 为返回的data(可以在浏览器控制台尝试哟~)
voiceAnnouncements(str){ 百度 var url = "http://tts.baidu.com/text2audio?lan=zh&ie=UTF-8&text=" + encodeURI(str); baidu var n = new Audio(url); n.src = url; n.play(); } voiceAnnouncements('你好,今天吃的什么?')
10.数组展开的N种方法
- 循环加递归
- flat
- flatMap
- toString后split
- join后split
var arr1 = [[1,2],[3,4,[5,6,4]]]; var arr2 = [[1,2,{a:1}],1)">]]]; console.log(arr1.toString().split(',')) console.log(arr2.toString().split(',1)">)) console.log(arr1.join(',').split(',1)">)) console.log(arr2.join(',1)">)) ["1","2","3","4","5","6","4"] //
11.使用instanceof判断原始类型
class PrimitiveString { static [Symbol.hasInstance](x) { typeof x === 'string' } } console.log('hello world' instanceof PrimitiveString) true
12.使用 Proxy 来实现一个数据绑定和监听
Proxy简介:
let onWatch = (obj,setBind,getLogger) => { let handler = { get(target,property,receiver) { getLogger(target,property) return Reflect.get(target,receiver); },set(target,value,receiver) { setBind(value); Reflect.set(target,value); } }; return Proxy(obj,handler); }; let obj = { a: 1 } let value let p = onWatch(obj,(v) => { value = v },(target,property) => { console.log(`Get '${property}' = ${target[property]}`); }) p.a = 2 bind `value` to `2` p.a -> Get 'a' = 2
定时器
requestAnimationFrame实现循环定时器
setInterval(callback,interval) { let timer const now = Date.now let startTime = now() let endTime = startTime const loop = () => { endTime = now() if (endTime - startTime >= interval) { startTime = endTime = now() callback(timer) } timer = window.requestAnimationFrame(loop) } timer = window.requestAnimationFrame(loop) timer } let a = 0 setInterval(timer => { console.log(1) a++ if (a === 3) cancelAnimationFrame(timer) },1000)
修正setTimeout定时器
let period = 60 * 1000 * 60 * 2 let startTime = Date().getTime() let count = 0 let end = new Date().getTime() + period let interval = 1000 let currentInterval = interval loop() { count++ 代码执行所消耗的时间 let offset = new Date().getTime() - (startTime + count * interval); let diff = end - Date().getTime() let h = Math.floor(diff / (60 * 1000 * 60)) let hdiff = diff % (60 * 1000 * 60) let m = Math.floor(hdiff / (60 * 1000)) let mdiff = hdiff % (60 * 1000) let s = mdiff / (1000) let sCeil = Math.ceil(s) let sFloor = Math.floor(s) 得到下一次循环所消耗的时间 currentInterval = interval - offset console.log('时:'+h,'分:'+m,'毫秒:'+s,'秒向上取整:'+sCeil,'代码执行时间:'+offset,'下次循环间隔'+currentInterval) setTimeout(loop,currentInterval) } setTimeout(loop,currentInterval)