0%

实现效果:

用户调用接口时鉴权,如果没有合法的access_token则不允许接入,抛出401

实现要点:

mongoDB的简单操作,async与await

code:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
var db = require('../db')
var express = require('express')
var router = express.Router()
var utils = require('../utils')

var checkLogin = async function(req, res, next) {
try{
if (await checkAccessToken(req.query.userId, req.query.access_token)) {
next()
} else {
res.status(401)
res.send()
}
}catch(e){
console.error(e)
res.status(500)
res.send()
}

}
module.exports = checkLogin;

async function checkAccessToken(userId, accessToken) {
if (!db) {
console.error("DataBase error")
} else {
var userInfo = await db.user.findOne({
userId: userId
}).exec()
return userInfo.access_token === accessToken
}
}

mongoDB中,使用db.xx.find读出的是数组,需要用[0]或者findOne

mongoDB的读取为异步过程,可以使用async await等待异步回调

在处理时如果不使用res.send而直接调用next(),中间件向后传递

代码地址:https://github.com/lsvih/Wechat-JSSDK-API/blob/master/index.js

如果需要在微信浏览器中调用微信的底层支持(如调用相机等),需要使用微信jssdk。为了使用微信jssdk,需要计算出所需要的相关签名信息。

微信jssdk文档:http://mp.weixin.qq.com/wiki/7/aaa137b55fb2e0456bf8dd9148dd613f.html#.E6.A6.82.E8.BF.B0

附录1为签名计算方法,大致过程如下:

微信的签名需要使用jssdk_ticket生成,jssdk_ticket需要使用access_token生成。它们的生命周期都只有2个小时而且每天的请求数量是有限制的,因此需要在获取到access_token与ticket之后使用各种方法,如缓存,文件,数据库来将它存储住。

根据业务需求,我使用node+express+mongoDB写了微信签名的计算.

在需要使用jssdk的页面调用 xxxxx/wx?url=location.href就能计算出当前页面的微信jssdk签名等信息。

可以使用微信的签名校验工具来测试签名是否正确

微信签名校验工具:https://mp.weixin.qq.com/debug/cgi-bin/sandbox?t=jsapisign

calc()在css中可以很方便的使用,但是在使用less时calc()内的东西会被编译器当作算式进行计算,例如

1
height:calc( 100% - 20px );

会被编译成

1
height:calc ( 80% );

此时,需要用到less的e()字符串函数来让其以css方式解析 > ### e > > CSS escaping, replaced with ~"value" syntax. > > It expects string as a parameter and return its content as is, but without quotes. It can be used to output CSS value which is either not valid CSS syntax, or uses proprietary syntax which Less doesn't recognize. > > Parameters: string - a string to escape. > > Returns: string - the escaped string, without quotes. > > Example: >
filter: e("ms:alwaysHasItsOwnSyntax.For.Stuff()");
Output:
filter: ms:alwaysHasItsOwnSyntax.For.Stuff();

Note: The function accepts also ~"" escaped values and numbers as parameters. Anything else returns an error.

因此,需要这样写

1
height: calc( e("100% - 20px") );

1
height: calc(~"100% - 20px");

这时就能满足需求,编译成css后会保持

1
height: calc( 100% - 20px );

的样子。

在有多个异步请求的情况下,如何将它们全部正确的返回请求是个问题。如果不适用async,一般有几种实现的情况。

1、对于result需要按照顺序请求的情况直接使用回调-回调-回调

直接使用这样的回调就能完成相应需求:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
var allResult = {}
asyncFunction("1",function(error,result){
if(error==null)
allResult["1"]=result
asyncFunction("2",function(error,result){
if(error==null)
allResult["2"]=result
asyncFunction("3",function(error,result){
if(error==null)
allResult["3"]=result
else
console.error(error)
})
else
console.error(error)
})
else
console.error(error)
})

这种请求方式虽然能很明确地描述出整个流程,能保证result按顺序输出,但是代码一层套一层,不利于阅读。

这种情况可以使用async.series进行控制,暂且不提

2、如果不要求按照顺序输出result,因此上面那种做法就显得非常浪费时间,因为每个请求都要等到前一个请求完成后才会进行下一个请求,它们的时间是相加的。因此可以同时进行所有的请求,将所有请求的result都拿到,不需要管它们哪个先输出哪个后输出。

在async中,可以这样实现:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
async.parallel({
one:function(done){
asyncFunction('1',function(error,result){
if(!error)
done(null,result)
else
done(error,null)
})
},
two:function(done){
asyncFunction('2',function(error,result){
if(!error)
done(null,result)
else
done(error,null)
})
},
three:function(done){
asyncFunction('3',function(error,result){
if(!error)
done(null,result)
else
done(error,null)
})
}
},function(error,result){
if(!error)
callback(null,result)
else
callback(error,null)
});

以上代码的含义是,同时调用3个asyncFunction,当三个函数都成功取到result之后将result输出,如果其中有任何一个函数出现了错误(收到了error)则输出错误信息。通过这种方式可以节省请求时间且便于查看代码。

实现async.parallel

async.parallel参数由2部分,第一部分是由请求组成的对象,第二部分是全部完成时处理的函数

需要处理的第一点就是如何判断所有的asyncFunction都成功完成,且在那时候调用之后的函数.

可以采用for in 来获取第一部分参数的请求数量

1
2
3
4
5
6
7
async.parallel = function(actions,allDone){
var Result = {}
var n = 0
for(var action in actions){
if(actions.hasOwnProperty(action)) n++
}
}

这样就能获得请求总数,hasOwnproperty防止计数时遍历到其原型的属性

接着,就可以遍历请求,分别处理它们的回调了

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
async.parallel = function(actions,allDone){
var Result = {}
var n = 0
for(var action in actions){
if(actions.hasOwnProperty(action)) n++
}
//得到了n
for(var action in actions){
var done = function(error,result){
if(error==null){
Result[action] = result
n--
if(n==0) allDone(null,Result)
}else{
allDone(error,Result)//如果asyncFunction发生错误,将错误返回
}
}
action(done)//将done作为参数放入每个请求中,用于处理result和error
}
}

通过这种方式,简单实现了async.parallel的功能。

当做出了不正确的commit还push到远程仓库后,可以用强推的方法回退远程仓库

  1. 先从远程仓库clone下最新的版本
  2. 使用git reset --hard HEAD^ 来将仓库所有内容回退到上一个版本,在运行命令的时候可以看到当前的commit点 upload successful
  3. 使用git status确认信息是否正确 upload successful 可以看到本地仓库是处于远程仓库4个commit版本前的位置
  4. 强行将本地仓库推送到远程仓库,覆盖原来的master

使用 git push origin +master:master

此时远程仓库就回到了4个commit版本前。

情景:老板规定在指定日期必须分享文章

使用selenium进行微信的自动化操作,适用requests获取目标网站的内容,适用BeautifulSoup快速获得需要选择的元素及内容。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
#coding=utf-8
#encoding=utf-8
from selenium import webdriver
import time
import requests
from BeautifulSoup import BeautifulSoup
browser = webdriver.Chrome()
browser.get( "https://wx.qq.com/ ")
print( "请登录 ")
time.sleep(10)
chat_elems = browser.find_elements_by_class_name( "ng-scope ")
for elem in chat_elems:
if(elem.text.encode('UTF-8') == u'文件传输助手'.encode('UTF-8')):
elem.click()
break
while True:
current_time = time.localtime(time.time())
if ((current_time.tm_mday%10 == 5) and (current_time.tm_hour == 1)):
headers = { "Accept ": "text/html,application/xhtml+xml,application/xml; ",
"Accept-Encoding ": "gzip ",
"Accept-Language ": "zh-CN,zh;q=0.8 ",
"Referer ": "http://daily.zhihu.com/ ",
"User-Agent ": "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/42.0.2311.90 Safari/537.36 "
}
zhihu = BeautifulSoup(requests.get(url= "http://daily.zhihu.com/ ",headers=headers).text)
frist_q = zhihu.find(attrs={'class':'wrap'}).find( "a ")
frist_q_content = frist_q.text
frist_q_link = 'http://daily.zhihu.com' + frist_q.get( "href ")
browser.find_element_by_id( "editArea ").send_keys(frist_q_content)
browser.find_element_by_id( "editArea ").send_keys(frist_q_link)
browser.find_element_by_class_name( "btn_send ").click()
time.sleep(60*59)

其中,headers 为了反防爬虫策略。

图片是由许多像素组成的,每个像素都有r,g,b,a4个值。如果对像素的这些值进行改变,就会改变像素的颜色或透明度。

对整个图片的像素进行有选择的改变就能改变整个图片的现实效果(图片滤镜)

首先要确定,rgba值的数据格式是UInt8,不能随意和Int值进行计算,因此在一些求平均值的情况要先将rgba用Int()将这些值转换为int再计算。

源码地址:https://github.com/lsvih/ImageProcessor

首先读取图片

1
let image = UIImage(named: "sample")

运行结果:

upload successful

写一个滤镜,用于在遍历像素时去掉照片中所有的红色

1
2
3
4
func removeRed(var pixel: Pixel) ->Pixel{
pixel.red = 0
return pixel
}

上述函数的作用为将每个读取到的像素的red值设为0之后再返回。

测试一下这个滤镜:

1
2
3
4
5
6
7
8
9
10
11
func testRemoveRedFilter(image: UIImage) -> UIImage {
var thisImage = RGBAImage(image: image)!
for y in 0..<thisImage.height {
for x in 0..<thisImage.width {
let sub = y * thisImage.width + x
let pixel = thisImage.pixels[sub]//遍历每个像素
thisImage.pixels[sub] = removeRed(pixel)
}
}
return thisImage.toUIImage()!
}

上述函数作用为遍历图片中的每一个像素,应用上面取出红色的函数后,将像素返回图片。最终得到了如下图片:

upload successful

根据这个原理,可以进行各种滤镜的编写。

1、去除指定颜色

1
2
3
4
5
6
7
8
9
10
func removeColor(var pixel:Pixel,conf:Int) -> Pixel{
if(conf == 0){
pixel.red = 0
}else if(conf == 1){
pixel.green = 0
}else if(conf == 2){
pixel.blue = 0
}
return pixel
}

传值0为去除红色,1为去除绿色,2为去除蓝色

运行结果如下

upload successful

2、灰度图

1
2
3
4
5
6
7
func grayScale(var pixel:Pixel,conf:Int)->Pixel{
let gray = UInt8((Int(pixel.red)+Int(pixel.green)+Int(pixel.blue))/conf)
pixel.red = gray
pixel.green = gray
pixel.blue = gray
return pixel
}

conf可以控制图片灰度,通常为3.对每个像素把他们的rgb值求平均值,这个像素就变成相应的灰色了。

运行结果如下

upload successful

3、更改透明度

像素rgba中的a值即为透明度,改变a值照片的透明度将发生变化

1
2
3
4
func transparentFilter(var pixel:Pixel,opacity:Int)->Pixel{
pixel.alpha = UInt8(opacity)
return pixel
}

由于a为UInt8,因此需要转换。输入的opacity为透明度,从0-255

效果如下

upload successful

4、黑白照片

定义一个阀值,rgb平均值超过这个阀值的为白否则为黑

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
func blackAndWhite(var pixel:Pixel,conf:Int)->Pixel{
if(conf==1){
let avg = UInt8((Int(pixel.red)+Int(pixel.green)+Int(pixel.blue))/3)
if(avg>100){
pixel.red = 255
pixel.green = 255
pixel.blue = 255
}else{
pixel.red = 0
pixel.green = 0
pixel.blue = 0
}
}else{
let avg = UInt8((Int(pixel.red)+Int(pixel.green)+Int(pixel.blue))/3)
if(avg<100){
pixel.red = 255
pixel.green = 255
pixel.blue = 255
}else{
pixel.red = 0
pixel.green = 0
pixel.blue = 0
}

}
return pixel
}

传值conf为0时生成黑白图片,如果为1则反色

效果如下

upload successful

5、反相

用255减去rgb值即为反相效果

1
2
3
4
5
6
func inverseColor(var pixel:Pixel,conf:Int)->Pixel{
pixel.red = min(max(UInt8(conf) - pixel.red,0),255)
pixel.green = min(max(UInt8(conf) - pixel.green,0),255)
pixel.blue = min(max(UInt8(conf) - pixel.blue,0),255)
return pixel
}

要对减法得到的值进行约束防止出现负数。

效果如下

upload successful

DCloud的webapp解决方案功能强大,但是官方所集成的是个推并且版本非常老,许多功能(比如说别名推送等等)不能使用,因此为它集成JPush(极光推送)。

集成具体方法如下:

1、下载极光sdk

在极光官方网站下载极光推送ios sdk 网址:http://docs.jiguang.cn/resources/

将其库文件(如下图所示)提取出来,

upload successful

将其导入Hbuilder XCode工程的Frameworks中(如下图所示)

(1)导入步骤1

upload successful

(2)导入步骤2

upload successful

2、添加文件

在inc/tools(或其它文件夹)下建立文件PGJiguanPush.h与PGJiguanPush.m,内容如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
//=========PGJiguanPush.h========
#import "PGPlugin.h"
#import "PGMethod.h"

@interface PGJiguanPush : PGPlugin
// +(id)alloc
// +(PGJiguanPush *)sharePGJGManager
- (void)PluginSetTagsFunction:(PGMethod*)commands;
- (void)PluginGetRegistrationIDFunction:(PGMethod*)commands;
- (void)changeStatus;
@end
//=========PGJiguanPush.m========
#import "JPUSHService.h"
#import "PGJiguanPush.h"

@interface PGJiguanPush()
{
Boolean registeredStatus ;
}
@end
@implementation PGJiguanPush
//获取自定义消息
//static PGJiguanPush * manager = Nil;
// +(PGJiguanPush *)sharePGJGManager
// {
// @synchronized(self)
// {
// if (!manager) {
// manager = [[PGJiguanPush alloc]init];
// }
// return manager;
// }
// }
// +(id)alloc
// {
// @synchronized(self)
// {
// if (!manager) {
// manager =[super alloc];
// }
// return manager;
// }
// }
// -(id)init
// {
// if (self = [super init])
// {
// NSNotificationCenter *defaultCenter = [NSNotificationCenter defaultCenter];
// [defaultCenter addObserver:self
// selector:@selector(networkDidSetup:)
// name:kJPFNetworkDidSetupNotification
// object:nil];
// [defaultCenter addObserver:self
// selector:@selector(networkDidClose:)
// name:kJPFNetworkDidCloseNotification
// object:nil];
// [defaultCenter addObserver:self
// selector:@selector(networkDidRegister:)
// name:kJPFNetworkDidRegisterNotification
// object:nil];
// [defaultCenter addObserver:self
// selector:@selector(networkDidLogin:)
// name:kJPFNetworkDidLoginNotification
// object:nil];
// [defaultCenter addObserver:self
// selector:@selector(networkDidReceiveMessage:)
// name:kJPFNetworkDidReceiveMessageNotification
// object:nil];
// [defaultCenter addObserver:self
// selector:@selector(serviceError:)
// name:kJPFServiceErrorNotification
// object:nil];
// }
// return self;
// }

#pragma mark 插件方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
//设置tags 、alias
- (void)PluginSetTagsFunction:(PGMethod*)commands
{
if ( commands ) {
NSString* cbId = [commands.arguments objectAtIndex:0];
NSString* pArgument1 = [commands.arguments objectAtIndex:1]; // tags
NSString* pArgument2 = [commands.arguments objectAtIndex:2]; // alias
NSSet * tags = [NSSet setWithObject:pArgument1];
[JPUSHService setTags:tags alias:pArgument2 fetchCompletionHandle:^(int iResCode, NSSet *iTags, NSString *iAlias){
NSArray* pResultString = [NSArray arrayWithObjects:[NSString stringWithFormat:@"%d",iResCode], iTags, iAlias, nil];
PDRPluginResult * result = [PDRPluginResult resultWithStatus:PDRCommandStatusOK messageAsArray: pResultString];
[self toCallback:cbId withReslut:[result toJSONString]];
}];
}
}

//获取 RegistrationID
- (void)PluginGetRegistrationIDFunction:(PGMethod*)commands
{
NSNotificationCenter *defaultCenter = [NSNotificationCenter defaultCenter];
[defaultCenter addObserver:self
selector:@selector(changeStatus)
name:kJPFNetworkDidLoginNotification
object:nil];
if ( commands &amp;&amp; registeredStatus) {
NSString* cbId = [commands.arguments objectAtIndex:0];
[self toCallback:cbId withReslut:[JPUSHService registrationID]];
}
}
-(void)changeStatus
{
registeredStatus = 1;
}

//- (void)networkDidSetup:(NSNotification *)notification {}
//- (void)networkDidClose:(NSNotification *)notification {}
// - (void)networkDidRegister:(NSNotification *)notification {}
// - (void)networkDidLogin:(NSNotification *)notification {}
//- (void)networkDidReceiveMessage:(NSNotification *)notification {}
// - (void)serviceError:(NSNotification *)notification {}
// - (void)unObserveAllNotifications {
// NSNotificationCenter *defaultCenter = [NSNotificationCenter defaultCenter];
// [defaultCenter removeObserver:self
// name:kJPFNetworkDidSetupNotification
// object:nil];
// [defaultCenter removeObserver:self
// name:kJPFNetworkDidCloseNotification
// object:nil];
// [defaultCenter removeObserver:self
// name:kJPFNetworkDidRegisterNotification
// object:nil];
// [defaultCenter removeObserver:self
// name:kJPFNetworkDidLoginNotification
// object:nil];
// [defaultCenter removeObserver:self
// name:kJPFNetworkDidReceiveMessageNotification
// object:nil];
// [defaultCenter removeObserver:self
// name:kJPFServiceErrorNotification
// object:nil];
// }
//- (void)serviceError:(NSNotification *)notification {}
@end

(根据业务需求,没有具体写自定义消息的方法,只使用了标准消息,如果有需要可以自己弄)

3、增加全局描述

在Supporting Files目录下找到pch文件,在文件最后加上

static NSString *appKey = @"你的appkey";// appkey,极光创建app时能拿到

static NSString *channel = @"0";// App Store等渠道,乱填也行~

static BOOL isProduction = 0; //值要与Build Settings的Code Signing配置的证书环境一致 0开发 1生产

4、添加注册、接收等方法

参考极光官方文档,网址:http://docs.jiguang.cn/guideline/ios_guide/

修改inc/AppDelegate.m如下:

(1)在头部添加引用

1
#import "JPUSHService.h"

如下图所示

upload successful

(2)在官方注释"程序启动时收到push消息"的代码做如下修改:

1
2
3
4
5
6
7
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
// 设置当前SDK运行模式
BOOL ret = [PDRCore initEngineWihtOptions:launchOptions
withRunMode:PDRCoreRunModeNormal];
return ret;
}

改成

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
// 设置当前SDK运行模式
BOOL ret = [PDRCore initEngineWihtOptions:launchOptions
withRunMode:PDRCoreRunModeNormal];
[JPUSHService registerForRemoteNotificationTypes:(UIUserNotificationTypeBadge |
UIUserNotificationTypeSound |
UIUserNotificationTypeAlert)
categories:nil];
[JPUSHService setupWithOption:launchOptions appKey:appKey
channel:channel
apsForProduction:isProduction
advertisingIdentifier:nil];
return ret;
}

(3)官方注释“远程push注册成功收到DeviceToken回调”的代码做如下修改:

1
2
3
4
- (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken
{
[PDRCore handleSysEvent:PDRCoreSysEventRevDeviceToken withObject:deviceToken];
}

改成

1
2
3
4
5
- (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken
{
[PDRCore handleSysEvent:PDRCoreSysEventRevDeviceToken withObject:deviceToken];
[JPUSHService registerDeviceToken:deviceToken];
}

(4)官方注释“远程push注册失败”的代码做如下修改:

1
2
3
4
5
6
7
- (void)application:(UIApplication *)application didFailToRegisterForRemoteNotificationsWithError:(NSError *)error
{
[PDRCore handleSysEvent:PDRCoreSysEventRegRemoteNotificationsError withObject:error];
}
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo {
[PDRCore handleSysEvent:PDRCoreSysEventRevRemoteNotification withObject:userInfo];
}
改成
1
2
3
4
5
6
7
8
9
10
- (void)application:(UIApplication *)application didFailToRegisterForRemoteNotificationsWithError:(NSError *)error
{
[PDRCore handleSysEvent:PDRCoreSysEventRegRemoteNotificationsError withObject:error];
NSLog(@"did Fail To Register For Remote Notifications With Error: %@", error);
}
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo {
[PDRCore handleSysEvent:PDRCoreSysEventRevRemoteNotification withObject:userInfo];
[JPUSHService handleRemoteNotification:userInfo];
NSLog(@"JPush成功接收消息,可以在webview中获取了");
}

5、在webview中获取推送事件

完成以上修改后,使用XCode运行APP可以在LOG中看到类似

2016-08-02 19:03:07.690 | JPUSH | I - [JPUSHDeviceTokenReport] upload device token success

的消息则说明极光推送已经集成成功,如果在极光推送后台统计页面可以看到此时的应用安装数量增加了1

由于是直接在AppDelegate.m的didReceiveRemoteNotification中写的[JPUSHService handleRemoteNotification:userInfo],因此消息直接传给了基座,可以直接在webview网页中用plus.push获取消息。

例如,我直接在index.html中写了

1
2
3
4
5
6
7
8
mui.plusReady(function() {
plus.push.addEventListener( "click", function ( msg ) {
alert( "用户点击了消息: " + JSON.stringify(msg) );
}, false );
plus.push.addEventListener( "receive", function ( msg ) {
alert( "app收到了消息: " + JSON.stringify(msg) );
}, false );
});

6、测试

在极光开发者后台增加一条推送消息试试

upload successful

在app中弹出了对应消息

upload successful

静默发送参数试试

upload successful

成功地获取了传送的参数

upload successful

不提ES6新声明的作用域声明(let等),单纯看js的作用域。

作用域的定义:作用域是某一变量和方法具有访问权限的代码控件。

在JS中作用域主要由全局作用域和本地(函数)作用域两种,全局变量在所有函数中都能被访问到,本地作用域声明的变量只能在当前函数代码块中被访问;

例如:

1、全局变量能被直接访问

1
2
var a = 0;
alert(a);//=> 0

2、全局变量能再函数内部访问

1
2
3
4
5
var a = 0;
function test(){
alert(a);
}
test();//=> 0

3、本地作用域(函数内部)声明的变量能被本作用域(本函数)内部直接访问

1
2
3
4
5
function test(){
var a = 0;
alert(a);
}
test();//=> 0

4、本地作用域(函数内部)声明的变量不能在作用域外(函数外部)被访问

1
2
3
4
5
function test(){
var a = 0;
}
test();
alert(a);//=> undefined

5、本地作用域声明的变量不能在其外部的别的本地作用域中被访问

1
2
3
4
5
6
7
8
function test(){
var a = 0;
}
function run(){
alert(a);
}
test();
run();//=> undefined

6、本地作用域内部的作用域能访问到上级声明的变量

1
2
3
4
5
6
7
function test(){
var a = 0;
function child(){
alert(a);
}
}
test();//=>0

7、本地作用域声明的变量级别比全局变量高,能在作用域内覆盖全局变量声明

1
2
3
4
5
6
7
var a - 0;
function test(){
var a = 1;
alert(a);
}
test();//=> 1
alert(a);//=> 0

由此可知,js的作用域是从上往下继承,作用域内部函数能访问本作用域声明的函数与外部作用域生成的函数。

由此可以明确js的作用域链概念。

例如:

1
2
3
4
5
6
7
8
9
10
11
12
13
var a = 0;
function parent(){
alert(a);
function child1(){
var a = 1;
alert(a);
}
function child2(){
alert(a);
}
}
parent();//=> 0,=> 1,=>0
alert(a);//=> 0

parent()内第一个alert(a)的作用域链是parent()->window,所以此时a是0;

child1()内alert(a)的作用域链是child1()->parent()->window,在child1中重新声明了a的值,覆盖了全局变量的值因此此时a是1;

child2()中alert(a)的作用域链是child2()->parent()->window,与child1中声明的a=1毫无关联,因此此时的a的值还是0;

最后一个alert(a)作用域链是window,此时a的值为0;

js的作用域与作用域链的概念可以简单清晰的按如上描述。

upload successful

按钮如图所示,长宽都很小,导致在使用时点击困难。

解决方案:在按钮之上覆盖一层点击区域,将按钮的触发事件放在此区域之上

upload successful

添加点击区域后可操作范围明显增大。