Harry的博客


  • Startseite

  • Archiv

  • Tags

  • View

数组交集/并集

Veröffentlicht am 2017-11-24 | Visitors:

今天用到处理数组交集的问题,顺手总结一下用原生API处理数组交集/并集的方法。

首先介绍连个原生js方法:

1.Array.prototype.filter()方法

1
array.filter(function(currentValue,index,arr), thisValue)

currentValuex是当前元素,
index,当前元素下标,
arr当当期数组对象。

filter()方法接收一个函数,和一个可选值thisValue,返回符合条件的一个新数组。

实例

1
2
3
4
var o = [345,23,1,2];
var b = o.filter(function(cur) {
return cur > 40;
})//b = [345]

2.Array.prototype.reduce()方法

array.reduce(function(total, currentValue, currentIndex, arr), initialValue)

reduce()方法接收一个计数器函数和initialValue初始值(可选)

其中,函数的参数
total结果值, currentValue当前元素, currentIndex当前元素索引值, arr当期数组对象
实例:

1
2
3
4
var a = [1,2];
var sum = a.reduce(function(res,cur,index) {
return res + cur
})//3

多数组交集

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
/* 求多个数组交集
* @param arr [[1,,,],[b,,,],,,] 数组集合
*/
function intersection(arr) {
var result = arr[0];
arr.reduce(function(res,cur,index){
result = result.filter(function(n){
return cur.indexOf(n)!=-1;
})
return result;
})
return result;
}
var a = [[1,2,11],[11,11,2,1,3]];
var res = intersection(a);
console.log(res);//[1,2,11]

多数组并集

1
2
3
4
5
6
7
8
function merge() {
return Array.prototype.concat.apply([], arguments)
}
merge(arr1,arr2,arr3,...)
var arr1 = [1,2],
arr2 = [3],
arr3 = [2];
var union = merge(arr1,arr2,arr3)//[1,2,3,2]

ES7有更简洁的方法

交集

1
2
3
let a = [1,2]
let b = [2,3]
let intersection = a.filter(v => b.includes(v))console.log(intersection)//[2]

并集

1
2
3
4
let a = [1]
let b = [2]
let union = a.concat(b.filter(v => !a.includes(v)))
console.log(union)//[1,2]

判断元素是否在数组中

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
/** 判断参数值是否在数组中
* @param id 参数值
* @param source 源数组
*/
var inArray = function (id, source) {
var inFlag = false;
source.map(item => {
if (id == item) {
inFlag = true;
}
})
return inFlag;
}
//使用
var id = 1;
var arr = [1,3,4];
var isInArray = inArray(id,arr);//true

跨域解决方法-JSONP

Veröffentlicht am 2017-10-24 | Visitors:

之前的文章谈到由于浏览器的同源策略,当请求不同源的资源时就会遇到跨域问题,今天尝试用jsonp来解决跨域问题。

JSONP是什么

JSONP(JSON with Padding)是json的一种“使用模式”,可以让网页取得不同源上的资源数据,它不需要使用XMLHttpRequest对象,而是使用script标签来请求不同源的数据资源。
使用JSONP的关键是使用回调函数进行服务器和客户端的数据交互。来看下面的实例:

解决实例

在客户端,即html文件:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>JSONP-demo</title>
</head>
<body>
<p>test</p>
<script>
function test(data){
let p = document.getElementsByTagName('p')[0];
p.innnerHTML = data;
}
</script>
<script src="http://localhost:3002?callback=test"></script>
<!--src里的问号?后的参数(callback=test)可以在3002端口页面中可以通过req.query.callback获取-->
</body>
</html>

在客户端起一个服务在3000端口(这里用express):

1
2
3
4
5
6
7
var express = require('express'); // 引用express模块
var app = express(); // 创建一个简单的服务器
var requestPort = 3000;
app.use(express.static(__dirname));

在3002端口页面,即服务器:

1
2
3
4
5
6
7
8
9
var express = require('express');
var app = express();
var responsePort = 3002;
app.get('/',function(req,res){
var callbackName = req.query.callback;
res.send(callbackName + "('hello jsonp!')");
})

跨域解决方法

1.CORS(cross-origin resourse sharing)跨域资源共享
2.JSONP
3.document.domain + iframe
4.window.name + iframe
5.postMessage
6.proxy

跨域解决方法-proxy

Veröffentlicht am 2017-10-23 | Visitors:

今天尝试使用http-proxy-middleware插件解决本地开发中的跨域问题。这篇文章主要讲的是跨域解决方法6.proxy,使用代理。

跨域解决方法-proxy

http-proxy-middleware

下面在本地开发中复现AJAX跨域请求。
本地开发,需要请求远程服务器资源,使用ajax请求获取远程资源:

1
2
3
4
5
6
7
8
9
10
$(document).ready(function() {
$.ajax({
type:"GET",
url:"./api/.....",//远程地址
dataType:"json",
success:function(data) {
console.log(data);
}
});
})

此时浏览器会报错,跨域问题。
意思是出现跨域请求错误。

解决方法一:browser-sync+http-proxy-middleware做代理

在gulpfile.js文件中做配置:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
var browserSync = require('browser-sync').creat();
var proxyMiddleware = require('http-proxy-middleware');
var proxy = ('./api',{
target:"http://echo.websocket.org",//远程地址url
changeOrigin:true,//虚拟主机站点需要
pathRewrite:{
'^/api/(.*)':'/$1' //正则匹配,替换api起始的路径
}
});
gulp.task('server',function(){
browserSync.init({
server:'./dist',
notify:false,
middleware:[proxy]
});
});

其他解决方法参看如下:

跨域解决方法

1.CORS(cross-origin resourse sharing)跨域资源共享
2.JSONP
3.document.domain + iframe
4.window.name + iframe
5.postMessage
6.proxy

CORS(cross-origin resourse sharing)跨域资源共享

Veröffentlicht am 2017-10-12 | Visitors:

今天从同源策略出发,探究跨域问题出现的原因及其原理,以及一些常见解决方法。这篇文章主要讲跨域解决办法1.CORS(cross-origin resourse sharing)跨域资源共享。

同源策略

所谓同源,就是比较两个页面的协议、域名、端口是否相同,相同则是同源,有一个不同就视为不同源。

根据MDN给出的例子:
下表给出了相对http://store.company.com/dir/page.html同源检测的示例:

URL 结果 原因
http://store.company.com/dir2/other.html 成功
http://store.company.com/dir/inner/another.html 成功
https://store.company.com/secure.html 失败 不同协议 ( https和http )
http://store.company.com:81/dir/etc.html 失败 不同端口 ( 81和80)
http://news.company.com/dir/other.html 失败 不同域名 ( news和store )

跨域问题

浏览器为了保证信息安全,规定了资源访问使用同源策略。所以,当浏览器访问的资源来自不同源,就会出现跨源资源访问,即跨域问题。

解决方法

1.CORS(cross-origin resourse sharing)跨域资源共享

CORS是浏览器解决跨域问题的一种策略,在CORS中,浏览器把ajax发起的请求分为简单请求和非简单请求,分别对两种请求进行处理,再将ajax请求发往服务器。

①简单请求就是满足以下条件的:

请求方式为这几种:

1
GET,POST,HEAD

HTTP头信息不超出以下几种:

1
2
3
4
5
Accept
Accept-Language
Content-Language
Last-Event-ID
content-type只限于三种:text/plain,multipart/form-data,application/x-www-form-urlencoded

对于简单请求,浏览器直接发出CORS请求,在头信息中增加一个字段:Origin,表示请求源域名。例子:

1
2
3
4
5
6
7
Accept:*/*
Accept-Encoding:gzip, deflate, br
Accept-Language:zh-CN,zh;q=0.8
Connection:keep-alive
Host:localhost:3001
Origin:http://localhost:3000

Origin:http://localhost:3000字段告诉服务器请求源是http://localhost:3000,服务器就可以做出相应响应。

如果服务器发现Oringin字段的源不在接受范围,就会发送一个正常HTTP回应,浏览器发现这个回应的头信息中没有包含Accsess-Control-Allow-Origin字段,就抛出一个错误,被XMLHttpRequest的onerror捕获,即跨域问题出现了。

好了,知道报错原因,我们就可以从以下方法解决跨域问题了:
概括为一句话:在服务器设置接受的源信息。

实例

客户端请求:

1
2
3
4
5
6
7
8
9
10
var xhr = new XMLHttpRequest();
var url = 'http://localhost:3000';
xhr.open('GET',url);
xhr.send(null);
xhr.onreadystatechange = () => {
if (xhr.readyState === XMLHttpRequest.DONE && xhr.status === 200) { // 如果请求成功
text.innerHTML = xhr.response;
}
}

服务器设置(例子用的express):

1
2
3
4
5
6
7
8
9
10
var express = require('express');
var test = express();
test.get('/',(req,res) => {
res.set('Access-Control-Allow-Origin','http://localhost:3000');
res.header('Access-Control-Allow-Methods', 'GET, POST, PUT');
res.header('Access-Control-Allow-Headers', 'X-Custom-Header');
res.header('Access-Control-Allow-Credentials', 'true');
res.send("hello CORS.");
})

如上,服务器对请求的头信息进行设置,
Access-Control-Allow-Origin字段表示接受的源,表示接受来自http://localhost:3000这个域名的请求。设置为*表示接受任意域名的请求。

Access-Control-Allow-Methods列举出服务器接受的请求方式。
Access-Control-Allow-Headers可以设置允许请求源的header特殊参数。
Access-Control-Allow-Credentials该字段可选。它的值是一个布尔值,表示是否允许发送Cookie。

如此,就可以实现跨域访问了。

②非简单请求

非简单请求,我的理解是排除了以上简单请求的,比如PUT请求。

浏览器对于非简单请求,在发送正式请求前,会先发送一个OPTION请求,向服务器询问是否接受请求,称为“预检”请求。
如果服务器接受才会发送正式请求,否则就报错。
与简单请求一样,服务器无非也就是判断请求的域名、头信息和HTTP动词等是否在允许范围。
实例:
客户端发送PUT请求:

1
2
3
4
5
6
7
8
9
10
var xhr = new XMLHttpRequest();
var url = 'http://localhost:3000';
xhr.open('PUT',url);
xhr.setRequestHeader('X-Custom-Header', 'value');
xhr.send();
xhr.onreadystatechange = () => {
if(xhr.readyState === XMLHttpRequest.DONE && xhr.status === 200) {
text1.innerHTML = xhr.response;
}
}

非简单请求例子中,我设置了特殊头信息“X-Custom-Header”,告知服务器接受这个参数信息。

在服务器设置接受信息:

1
2
3
4
5
6
7
8
9
10
11
var express = require('express');
var test = express();
var responsePort = 3001;//服务器端口
test.all('*', (req, res) => {
res.set('Access-Control-Allow-Origin', 'http://localhost:3000');
res.header('Access-Control-Allow-Methods', 'GET, POST, PUT');
res.header('Access-Control-Allow-Headers', 'X-Custom-Header');
res.header('Access-Control-Allow-Credentials', 'true');
res.send("hello CORS.");
})

至此,对于两种请求方式,都可以实现跨域访问了。
其他解决方法参看如下:

跨域解决方法

1.CORS(cross-origin resourse sharing)跨域资源共享
2.JSONP
3.document.domain + iframe
4.window.name + iframe
5.postMessage
6.proxy

angular+select2

Veröffentlicht am 2017-09-27 | Visitors:

select2 是一个jQuery的插件,扩展了select的功能。可以搜索,下面是使用方法:

官网地址:https://select2.org/

一、引入插件select2

1.访问GitHub下载:

https://github.com/select2/select2
解压后将js和css文件引入你的html文件:

1
2
3
4
//select2
require('../select2/select2.min.js');
require('../select2/select2.min.css');

2.或者通过远程动访问引入文件,在你的html文件引入js和css文件:

1
2
3
<link href="https://cdnjs.cloudflare.com/ajax/libs/select2/4.0.4/css/select2.min.css" rel="stylesheet" />
<script src="https://cdnjs.cloudflare.com/ajax/libs/select2/4.0.4/js/select2.min.js"></script>

二、使用

例子1:给select添加类名:

1
2
3
4
<select id="tags" class="js-example-basic-single" ng-model="someValue">
<option value="">请选择</option>
<option ng-repeat="s in arr" value="{{s.id}}" on-finish-render-filters>{{s.value}}</option>
</select>

在js文件中调用select2的API:

1
2
3
4
5
//select2插件实现下拉框的模糊搜索匹配功能
$(document).ready(function() {
$('.js-example-basic-multiple').select2();
});

三、select2初始化

通过在.select2()方法中添加一个对象实现:

1
2
3
4
5
6
7
8
$('.js-example-basic-multiple').select2({
width:200px,//设置默认宽度
//width: 'resolve', // 需要在html用行内样式重新定义宽度
multiple: 'multiple', // 多选
});

四、select2事件

1
2
3
4
5
6
7
8
$('#tags').on('select2:select', function (e) {
//获取select当前选中值得一些信息
var data = e.params.data;
console.log(data);
$scope.someValue = data.id;
});

五、Data sources

1
2
<select class="js-data-example-ajax"></select>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
$('.js-example-data-ajax').select2({
ajax: {
url: 'https://api.github.com/search/repositories',
//dataType: 'json'
// Additional AJAX parameters go here; see the end of this chapter for the full code of this example
data: function (params) {
var query = {
search: params.term,
type: 'public'
}
// Query parameters will be ?search=[term]&type=public
return query;
}
}
});

六、select2提供的event

摘自网友博客:

$(“#txt_tag”)
.on(“change”, function(e) {​})​ // 当 select2 值被改变的時候 ( 改变后触发 )​
.on(“select2-opening”,function(){}) // ​当下拉出现时 ( 开启选项下拉前触发)
.on(“select2-open”, function() {}) //当下拉出现时(开启选项下拉后触发)​
.on(“select2-close”,function(){}) // 当选项关闭的时候
.on(“select2-highlight”,function(e){})// hover 到下拉时
.on(“select2-selecting”,function(e){})// 选中选项的时候 (选中前触发 ) ​​
.on(“select2-removing”,function(e){}) // 移除选项的时候 ( 选中前触发) ​​
.on(“select2-removed”,function(e){}) //移除选项的时候 ( 选中后触发 ) ​​​
.on(“select2-loaded”,function(e){}) // load资料的时候 ( Loaded 完成后触发)
.on(“select2-focus”,function(e){}) // input 获得焦点的触发
.on(“select2-blur”,function(e) {}) // input 失去焦点触发

七、踩过的坑

1.在angular项目里使用时,select中的ng-model未绑定选中值,看起来似乎失效了。

1
2
3
4
<select id="tags" class="js-example-basic-single" ng-model="someValue">
<option value="">请选择</option>
<option ng-repeat="s in arr" value="{{s.id}}" on-finish-render-filters>{{s.value}}</option>
</select>

解决办法:在调用插件时,添加一个事件,将选中值赋值给变量:

1
2
3
4
5
6
7
8
9
//获取select选中值,赋值给全局变量$scope.someValue
$('#tags').on('select2:select', function (e) {
//获取select当前选中值得一些信息
var data = e.params.data;
console.log(data);
$scope.someValue = data.id;
});

总结:select2提供了很多配置参数,处理事件,可以更具业务需求进行设置。本文主要用到了select2的搜索功能,以及处理与angular同时使用时的问题。

BFC

Veröffentlicht am 2017-09-26 | Visitors:

BFC是什么?

BFC(Block Formatting Context)块级格式化上下文,也是CSS一种盒模型渲染样式,w3c定义只要满足一下条件之一,就能创建一个BFC:

1.float属性不为none;

2.display属性值不为static和relative;

3.display属性为以下之一:table-cell,table-caption,inline-block,flex,inline-flex;

4.overflow属性不为visible。

解决了什么问题?

创建一个BFC很简单,只需包含上文定义中的4点任意一个就OK,来看看能解决什么问题:

1.解决外边距折叠

1
2
3
4
5
6
7
<div class="container">
<div class="sub-div"></div>
<div class="bfc">
<div class="sub-div"></div>
</div>
</div>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
.container{
background-color:#ccc;
height: 200px;
width: 100%;
}
.sub-div {
background-color: red;
height:50px;
margin:10px 0;
}
.bfc {
overflow: hidden;//添加overflow属性,创建一个新BFC,从而避免外边距折叠
}

2.用于清除浮动

1
2
3
4
5
<div class="container">
<div class="sub"></div>
<div class="sub"></div>
</div>
1
2
3
4
5
6
7
8
9
10
11
12
.container{
background-color: #ccc;
overflow:hidden;//通过给父元素添加overflow 属性,创建一个BFC,达到清除浮动效果。
}
.sub {
float: left;
height:30px;
width:50px;
background-color: red;
margin:0 10px;
}

3.多列布局中避免折行显示

1
2
3
4
5
6
<div class="container">
<div class="sub"></div>
<div class="sub"></div>
<div class="sub"></div>
</div>

由于浏览器舍入规则,子元素的宽度可能会超过容器总宽度,将会导致折行:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
* {
margin:0;
}
.container{
background-color: #ccc;
}
.sub {
float: left;
height:30px;
background-color:green;
width:31.33%;
margin:0 1%;
}
.sub:last-child {//通过给最后一个子元素 创建一个BFC解决折行问题。
float:none;
overflow:hidden;
}

总结

BFC就是通过创建一个新的盒模型,使之脱离原本的布局限制,达到互不影响布局的效果。创建BFC 可以通过以上4种方式达到。

Javascript中的apply、call和bind

Veröffentlicht am 2017-09-12 | Visitors:

这三种方法的作用是一样的,都能改变函数的执行作用域,区别只是在调用时传入的参数不同。

apply方法

apply()方法接收两个参数,第一个参数是函数内this的作用域,第二个参数是一个数组对象或者arguments。

1
2
3
4
5
6
7
8
9
10
var oo = {
a:5,
b:3
}
var a = 9,b=1;
function foo(a,b) {
return this.a-this.b;
}
console.log(foo.apply(oo));//2
console.log(foo.apply());//8

call方法

bind方法

angular.copy()方法

Veröffentlicht am 2017-09-11 | Visitors:

angular.copy()方法的定义

angular.copy()方法实现对象属性的深度拷贝,返回一个新创建的对象。

用法实例

1
2
3
4
5
6
7
8
9
var a = {
name: 'lucy',
age: 20
}
var b = angular.copy(a);
console.log('a=',a);
//{name: "lucy", age: 20}
console.log('b=',b);
//{name: "lucy", age: 20}

当我们改变a对象的属性,b对象属性并不会随之改变:

1
2
3
4
5
a.name = 'angular';
console.log('a=',a);
//{name: "angular", age: 20}
console.log('b=',b);
//{name: "lucy", age: 20}

angular.copy()源码

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
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
/**
* @ngdoc function
* @name angular.copy
* @module ng
* @kind function
*
* @description
* Creates a deep copy of `source`, which should be an object or an array.
*
* * If no destination is supplied, a copy of the object or array is created.
* * If a destination is provided, all of its elements (for arrays) or properties (for objects)
* are deleted and then all elements/properties from the source are copied to it.
* * If `source` is not an object or array (inc. `null` and `undefined`), `source` is returned.
* * If `source` is identical to `destination` an exception will be thrown.
*
* <br />
* <div class="alert alert-warning">
* Only enumerable properties are taken into account. Non-enumerable properties (both on `source`
* and on `destination`) will be ignored.
* </div>
*
* @param {*} source The source that will be used to make a copy.
* Can be any type, including primitives, `null`, and `undefined`.
* @param {(Object|Array)=} destination Destination into which the source is copied. If
* provided, must be of the same type as `source`.
* @returns {*} The copy or updated `destination`, if `destination` was specified.
*
* @example
<example module="copyExample">
<file name="index.html">
<div ng-controller="ExampleController">
<form novalidate class="simple-form">
<label>Name: <input type="text" ng-model="user.name" /></label><br />
<label>Age: <input type="number" ng-model="user.age" /></label><br />
Gender: <label><input type="radio" ng-model="user.gender" value="male" />male</label>
<label><input type="radio" ng-model="user.gender" value="female" />female</label><br />
<button ng-click="reset()">RESET</button>
<button ng-click="update(user)">SAVE</button>
</form>
<pre>form = {{user | json}}</pre>
<pre>master = {{master | json}}</pre>
</div>
</file>
<file name="script.js">
// Module: copyExample
angular.
module('copyExample', []).
controller('ExampleController', ['$scope', function($scope) {
$scope.master = {};
$scope.reset = function() {
// Example with 1 argument
$scope.user = angular.copy($scope.master);
};
$scope.update = function(user) {
// Example with 2 arguments
angular.copy(user, $scope.master);
};
$scope.reset();
}]);
</file>
</example>
*/
function copy(source, destination) {
var stackSource = [];
var stackDest = [];
if (destination) {
if (isTypedArray(destination) || isArrayBuffer(destination)) {
throw ngMinErr('cpta', "Can't copy! TypedArray destination cannot be mutated.");
}
if (source === destination) {
throw ngMinErr('cpi', "Can't copy! Source and destination are identical.");
}
// Empty the destination object
if (isArray(destination)) {
destination.length = 0;
} else {
forEach(destination, function(value, key) {
if (key !== '$$hashKey') {
delete destination[key];
}
});
}
stackSource.push(source);
stackDest.push(destination);
return copyRecurse(source, destination);
}
return copyElement(source);
function copyRecurse(source, destination) {
var h = destination.$$hashKey;
var key;
if (isArray(source)) {
for (var i = 0, ii = source.length; i < ii; i++) {
destination.push(copyElement(source[i]));
}
} else if (isBlankObject(source)) {
// createMap() fast path --- Safe to avoid hasOwnProperty check because prototype chain is empty
for (key in source) {
destination[key] = copyElement(source[key]);
}
} else if (source && typeof source.hasOwnProperty === 'function') {
// Slow path, which must rely on hasOwnProperty
for (key in source) {
if (source.hasOwnProperty(key)) {
destination[key] = copyElement(source[key]);
}
}
} else {
// Slowest path --- hasOwnProperty can't be called as a method
for (key in source) {
if (hasOwnProperty.call(source, key)) {
destination[key] = copyElement(source[key]);
}
}
}
setHashKey(destination, h);
return destination;
}
/*
拷贝source的属性,并返回
*/
function copyElement(source) {
// Simple values
if (!isObject(source)) {
return source;
}
// Already copied values
var index = stackSource.indexOf(source);
if (index !== -1) {
return stackDest[index];
}
if (isWindow(source) || isScope(source)) {
throw ngMinErr('cpws',
"Can't copy! Making copies of Window or Scope instances is not supported.");
}
var needsRecurse = false;
var destination = copyType(source);
//创建数组或对象实例--destination
if (destination === undefined) {
destination = isArray(source) ? [] : Object.create(getPrototypeOf(source));
needsRecurse = true;
}
stackSource.push(source);
stackDest.push(destination);
return needsRecurse
? copyRecurse(source, destination)
: destination;
}
function copyType(source) {
switch (toString.call(source)) {
case '[object Int8Array]':
case '[object Int16Array]':
case '[object Int32Array]':
case '[object Float32Array]':
case '[object Float64Array]':
case '[object Uint8Array]':
case '[object Uint8ClampedArray]':
case '[object Uint16Array]':
case '[object Uint32Array]':
return new source.constructor(copyElement(source.buffer), source.byteOffset, source.length);
case '[object ArrayBuffer]':
//Support: IE10
if (!source.slice) {
var copied = new ArrayBuffer(source.byteLength);
new Uint8Array(copied).set(new Uint8Array(source));
return copied;
}
return source.slice(0);
case '[object Boolean]':
case '[object Number]':
case '[object String]':
case '[object Date]':
return new source.constructor(source.valueOf());
case '[object RegExp]':
var re = new RegExp(source.source, source.toString().match(/[^\/]*$/)[0]);
re.lastIndex = source.lastIndex;
return re;
case '[object Blob]':
return new source.constructor([source], {type: source.type});
}
if (isFunction(source.cloneNode)) {
return source.cloneNode(true);
}
}
}

源码中,copy()方法接收两个参数,第一个是源source,是一个对象或者数组,第二个参数destination可选,作为存储源source的对象,该方法返回一个和源source一样的对象,且该对象是新建的实例,使用时与源source不会相互影响。

JS中判断数据类型的几种方法

Veröffentlicht am 2017-09-01 | Visitors:

在搬砖途中看到一大神的代码,用Object.prototype.toString.call()判断数据类型,在这里学习总结下,在js中,判断数据类型除了用typeof运算符之外,还可以用Object.prototype.toString.call()方法、instanceof操作符。

几种判断方法的区别

typeof判断数据类型

使用typeof操作符,判断数据类型返回值如下:

1
2
3
4
5
6
typeof 1//"number"
typeof "a"//"string"
typeof true//"boolean"
typeof {}//"object"
typeof []//"object"
typeof function(){}//"function"

使用时的一个问题是,在判断数组和对象存储值时,都返回”object”。

Object.prototype上的原生toString()方法判断数据类型

Object.prototype.toString.call()方法既可以判断基本类型,也可以判断原生引用类型,还可以判断原生JSON对象。

判断基本类型

数字number、字符串string、布尔值boolean。

1
2
3
Object.prototype.toString.call(2);//"[object Number]"
Object.prototype.toString.call("s");//"[object String]"
Object.prototype.toString.call(true);//"[object Boolean]"

判断空类型

null和undefined。

1
2
Object.prototype.toString.call(null);//"[object Null]"
Object.prototype.toString.call(undefined);//"[object Undefined]"

判断复合类型

对象Object、数组Array、方法Function、日期Date、布尔Boolean、数字Number、字符串String、正则RegExp、Math。
例如上面例子中的引用类型存储值就可以使用Object.prototype.toString()方法区别出来:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
Object.prototype.toString.call({});//"[object Object]"
Object.prototype.toString.call([]);//"[object Array]"
Object.prototype.toString.call(function(){});//"[object Function]"
Object.prototype.toString.call(String);//"[object Function]"
var t = new Date();
Object.prototype.toString.call(t);//"[object Date]"
var bb = new Boolean();
Object.prototype.toString.call(bb);//"[object Boolean]"
var bb = new Number();
Object.prototype.toString.call(bb);//"[object Number]"
var str = new String();
Object.prototype.toString.call(str);//"[object String]"
var reg = new RegExp("^1[34578][0-9]{9}$","g");
Object.prototype.toString.call(reg);//"[object RegExp]"
var reg = Math.valueOf();
Object.prototype.toString.call(reg);//"[object Math]"

判断原生JSON对象
1
2
var isNativeJSON = window.JSON && Object.prototype.toString.call(JSON);
console.log(isNativeJSON);//[object JSON]

输出为

判断自定义类型
1
2
3
4
5
6
function Foo(name,age) {
this.name = name;
this.age = age;
}
var foo =new Foo("harry",20);
Object.prototype.toString.call(foo);//"[object Object]"

遇到的一个问题是,使用Object.prototype.toString.call()方法不能判断foo是Foo类的实例。只能用instanceof来判断。

instanceof判断数据类型

instanceof作用是判断原型与实例之间的关系。用法是:

1
实例 instanceof 原型

instanceof操作符会在实例的原型链上查找,直到找到右边构造函数的prototype属性,或者为null的时候停止。
引用自
http://blog.xieluping.cn/2017/08/18/instanceof/

1
console.log(foo instanceof Foo);//true

正则表达式学习总结

Veröffentlicht am 2017-08-30 | Visitors:

正则表达式的基本语法:

1
var expression = /pattern(模式)/flags(标识符);

pattern(模式)可以是由字符类、限定符、分组、向前查找以及反向引用。flags(标识符)取值为:i(不区分大小写),g(全局匹配),m(多行匹配),同一个正则表达式可以带有一个或多个flags。

创建正则表达式

字面量创建

1
2
3
4
//匹配字符串中所有“at”的实例
var e = /at/g;
//匹配第一个“bat”或“cat”,不区分大小写
var e = /[bc]at/i;

RegExp构造函数创建

RegExp构造函数接收两个参数,第一个参数是要匹配的字符串模式,第二个是可选的标识符字符串。

1
2
//匹配第一个“bat”或“cat”,不区分大小写
var e = new RegExp("[bc]at","i");

两种创建方式的比较:

在ECMAScript3中,字面量创建和RegExp对象创建区别是:字面量创建始终会共享同一个RegExp实例,而构造函数创建的每一个RegExp实例都是一个新实例
ECMAScript5明确规定:使用正则表达式字面量必须像直接调用RegExp构造函数一样,每次都创建新的RegExp实例。IE9+、Firefox 4+和Chrome都做出了修改。

正则表达式中的元字符必须转义。元字符有:

1
( [ { \ ^ $ | ) ? * + . ] }

例如:

1
2
3
4
//匹配第一个“[bc]at”,不区分大小写
var e = /\[bc\]at/i;
//在RegExp构造函数创建时,元字符需要双重on转义
var e = new RegExp("\\[bc\\]at","i");

RegExp实例的属性和方法

RegExp实例属性

1
2
3
4
5
6
7
8
ignoreCase 返回布尔值,表示RegExp对象是否具有标志 i
global 返回布尔值,表示RegExp对象是否具有表示 g
multiline 返回布尔值,表示RegExp对象是否具有表示 m
lastIndex 一个整数,标识开始下一次匹配的字符位置
soure 返回正则表达式的原文本 (不包括反斜杠)
i 执行对大小写不敏感的匹配
g 执行全局匹配 (查找所有匹配而非在找到第一个匹配后停止)
m 执行多行匹配

字符类匹配

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
[...]查找方括号之间的任何字符
[^..]查找任何不在方括号之间的字符
[a-z]查找任何从小写a到小写z的字符
[A-Z]查找任何从大写A到大写Z的字符
[A-z]查找任何从大写A到小写z的字符
. 查找单个字符,除了换行和行结束符
\w 查找单词字符,等价于 [a-zA-Z0-9]
\W 查找非单词字符,等价于 [^a-zA-Z0-9]
\s 查找空白字符
\S 查找非空白字符
\d 查找数字,等价于[0-9]
\D 查找非数字字符,等价于[^0-9]
\b 匹配单词边界
\r 查找回车符
\t 查找制表符
\0 查找NULL字符
\n 查找换行符

重复字符匹配

1
2
3
4
5
6
7
8
9
10
{n,m}匹配前一项至少n次,但不能超过m次
{n,}匹配前一项n次或更多次
{n}匹配前一项n次
n?匹配前一项0次或者1次,也就是说前一项是可选的,等价于{0,1}
n+匹配前一项一次或多次,等价于{1,}
n*匹配前一项0次或多次,等价于{0,}
n$匹配任何结尾为n的字符串
^n匹配任何开头为n的字符串
?=n匹配任何其后紧接指定字符串n的字符串
?!n匹配任何其后没有紧接指定字符串n的字符串

匹配特定数字

1
2
3
4
5
6
7
8
9
10
^[1-9]\d*$ 匹配正整数
^-[1-9]\d*$ 匹配负整数
^-?[0-9]\d*$ 匹配整数
^[1-9]\d*|0$ 匹配非负整数(正整数 + 0)
^-[1-9]\d*|0$ 匹配非正整数(负整数 + 0)
^[1-9]\d*.\d*|0.\d*[1-9]\d*$ 匹配正浮点数
^-([1-9]\d*.\d*|0.\d*[1-9]\d*)$ 匹配负浮点数
^-?([1-9]\d*.\d*|0.\d*[1-9]\d*|0?.0+|0)$ 匹配浮点数
^[1-9]\d*.\d*|0.\d*[1-9]\d*|0?.0+|0$ 匹配非负浮点数(正浮点数 + 0)
^(-([1-9]\d*.\d*|0.\d*[1-9]\d*))|0?.0+|0$ 匹配非正浮点数(负浮点数 + 0)

方法

exec()方法

exec()方法为模式的捕获组而设计的,该方法接收一个参数,即要匹配的字符串,该方法返回一个包含捕获组的数组Array,如果没有捕获组匹配返回null。返回的数组Array中,第一项是与整个模式匹配的字符串,其他项是与模式中的捕获组匹配到的字符串。数组Array中还有两个参数input(返回要匹配的字符串),index(返回匹配项在字符串中的位置)
模式中的捕获组就是指圆括号中的字符串。
exg:

1
2
3
4
5
6
7
8
9
var e = /do(es)(d)?/;
e.exec("ssdoesdo");
/**
array[0]:"doesd",
array[1]:"es",
array[2]:"d",
index:2,
input:"ssdoesdo"
**/

例子中,模式中包含两个捕获组”es”、”d”,即圆括号中的字符串。

test()方法

test()方法检索字符串中指定的值,该方法接收一个参数,如果字符串中含有与模式匹配的文本则返回true,否则返回false。
exg:

1
2
3
var e = /do(es)?/;
e.test("doesdo");
//true

如果正则表达式中带有g标识符,则每一次调用test方法和exec方法都从上一次匹配结束位置开始匹配;如果正则表达式中没有g标识符,则每次调用方法都从字符串起始位置开始匹配。
exg:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
var e = /do(es)?/g;
e.exec("ssdoesdoesdoes");
/*
array[0]:"does",
array[1]:"es",
index:2,
input:"ssdoesdoesdoes"
*/
e.exec("ssdoesdoesdoes");
/*
array[0]:"does",
array[1]:"es",
index:6,
input:"ssdoesdoesdoes"
*/

1
2
3
4
5
6
7
8
9
10
11
12
13
var e = /do(es)?/g;
console.log(e.test("ssdoesdoesdoes"));
console.log(e.lastIndex);
//true
//6
console.log(e.test("ssdoesdoesdoes"));
console.log(e.lastIndex);
//true
//10
console.log(e.test("ssdoesdoesdoes"));
console.log(e.lastIndex);
//true
//14
1
2
3
4
5
6
7
8
9
var e = /do(es)?/;
console.log(e.test("ssdoesdoesdoes"));
console.log(e.lastIndex);
//true
//0
console.log(e.test("ssdoesdoesdoes"));
console.log(e.lastIndex);
//true
//0

常用的正则校验

1
2
3
4
5
6
/^1[34578]\d{9}$/ //匹配手机号
/^(([0\+]\d{2,3}-)?(0\d{2,3})-)(\d{7,8})(-(\d{3,}))?$/ //匹配座机号
/^[0-9]\d*$/ //匹配正整数
/^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$/ //匹配ip地址
/^(\w-*\.*)+@(\w-?)+(\.\w{2,})+$/ //匹配邮箱
/^(\d{14}|\d{17})(\d|[xX])$/ //匹配身份证
123
yangjie

yangjie

29 Artikel
15 Tags
© 2020 yangjie
本站总访问量次 本站访客数人次
Erstellt mit Hexo
|
Theme — NexT.Muse