cosyer's Blog

Blog


  • 首页

  • 友链

  • 留言板

  • 归档

  • 关于

  • 搜索
7月
28
更新于
7月28
2020
知识

深浅拷贝

发表于 2018-10-31 | 热度 ℃
| 字数统计: 1,345 (字) | 阅读时长: 7 (分钟)

深浅拷贝概念

深拷贝和浅拷贝只针对象 Object, Array 这样的复杂对象(引用类型)的。

复制引用(引用类型)的拷贝方法称之为浅拷贝,创建一个新对象,这个对象有着原始对象属性值的一份精确拷贝。如果属性是基本类型,拷贝的就是基本类型的值,如果

属性是引用类型,拷贝的就是内存地址 ,所以如果其中一个对象改变了这个地址,就会影响到另一个对象。

深拷贝就是指完全的拷贝一个对象,将原对象的各个属性递归复制下来。这样即使嵌套了对象,两者也相互分离。

浅拷贝 对基本类型拷贝值,引用类型拷贝引用

Object.assign()

扩展运算符…

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
var shallowCopy = function(obj) {
if (typeof obj !== 'object') return; // 只拷贝对象
var newObj = obj instanceof Array ? [] : {}; // 根据obj的类型判断是新建一个数组还是对象
for (var key in obj) { // 遍历obj,并且判断是obj的属性才拷贝
if (obj.hasOwnProperty(key)) {
newObj[key] = obj[key];
}
}
return newObj;
}

function shallowCopy2(source) {
if (source === null || typeof source !== 'object') return source;
const copy = Array.isArray(source) ? [] : {};

Object.keys(source).forEach(key => {
copy[key] = source[key];
});
return copy;
}

var obj = { a:1, arr: [2,3] };
var shallowObj = shallowCopy(obj);
shallowObj.arr[1] = 5;
console.log(obj.arr[1]) // 5 互相影响 指向了同一块内存地址
shallowObj.a = 5;
console.log(obj.a) // 1

深拷贝(将一个对象从内存中完整的拷贝一份出来,从堆内存中开辟一个新的区域存放新对象,且修改新对象不会影响原对象。)

JSON.parse(JSON.stringify(a)): 性能最快

具有循环引用的对象时,报错 当值为函数、undefined、或symbol时,无法拷贝

递归复制

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// 不考虑循环引用
var deepCopy = function(obj) {
if (typeof obj !== 'object') return;
var newObj = obj instanceof Array ? [] : {};
for (var key in obj) {
if (obj.hasOwnProperty(key)) {
newObj[key] = typeof obj[key] === 'object' ? deepCopy(obj[key]) : obj[key];
}
}
return newObj;
}

var obj = { a:1, arr: [2,3] };
var shallowObj = shallowCopy(obj);
shallowObj.arr[1] = 5;
console.log(obj.arr[1]) // 3 没有影响 重新拷贝了新数据
shallowObj.a = 5;
console.log(obj.a) // 1
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// 不考虑循环引用
const clone = function(data){
if(typeof data !== 'object'){
return data;
}
let keys = Object.keys(data);
let result = Array.isArray(data) ? [] : {};
keys.forEach(key=>{
if(typeof data[key] === 'object'){
result[key] = clone(data[key]);
}else{
result[key] = data[key];
}
})
return result;
}
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
// 考虑循环引用 只考虑了普通的 object和 array两种数据类型
const clone = function(data){
let map = new WeakMap(); // 这里用WeakMap弱引用,会自动回收,不需要手动处理置为null
function dp(obj){
if(typeof obj !== 'object'){
return obj;
}
let o = map.get(obj);
if(o){
return o;
}
let result = Array.isArray(obj) ? [] : {};
map.set(obj, result);
let keys = Object.keys(obj);
keys.forEach(key=>{
if(typeof obj[key] === 'object'){
result[key] = dp(obj[key]);
}else{
result[key] = obj[key];
}
})
return result;
}
return dp(data);
}
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
// 终极版
const mapTag = '[object Map]';
const setTag = '[object Set]';
const arrayTag = '[object Array]';
const objectTag = '[object Object]';
const argsTag = '[object Arguments]';

const boolTag = '[object Boolean]';
const dateTag = '[object Date]';
const numberTag = '[object Number]';
const stringTag = '[object String]';
const symbolTag = '[object Symbol]';
const errorTag = '[object Error]';
const regexpTag = '[object RegExp]';
const funcTag = '[object Function]';

const deepTag = [mapTag, setTag, arrayTag, objectTag, argsTag];


function forEach(array, iteratee) {
let index = -1;
const length = array.length;
while (++index < length) {
iteratee(array[index], index);
}
return array;
}

function isObject(target) {
const type = typeof target;
return target !== null && (type === 'object' || type === 'function');
}

function getType(target) {
return Object.prototype.toString.call(target);
}

function getInit(target) {
const Ctor = target.constructor;
return new Ctor();
}

function cloneSymbol(targe) {
return Object(Symbol.prototype.valueOf.call(targe));
}

function cloneReg(targe) {
const reFlags = /\w*$/;
const result = new targe.constructor(targe.source, reFlags.exec(targe));
result.lastIndex = targe.lastIndex;
return result;
}

function cloneFunction(func) {
const bodyReg = /(?<={)(.|\n)+(?=})/m;
const paramReg = /(?<=\().+(?=\)\s+{)/;
const funcString = func.toString();
if (func.prototype) {
const param = paramReg.exec(funcString);
const body = bodyReg.exec(funcString);
if (body) {
if (param) {
const paramArr = param[0].split(',');
return new Function(...paramArr, body[0]);
} else {
return new Function(body[0]);
}
} else {
return null;
}
} else {
return eval(funcString);
}
}

function cloneOtherType(targe, type) {
const Ctor = targe.constructor;
switch (type) {
case boolTag:
case numberTag:
case stringTag:
case errorTag:
case dateTag:
return new Ctor(targe);
case regexpTag:
return cloneReg(targe);
case symbolTag:
return cloneSymbol(targe);
case funcTag:
return cloneFunction(targe);
default:
return null;
}
}

function clone(target, map = new WeakMap()) {

// 克隆原始类型
if (!isObject(target)) {
return target;
}

// 初始化
const type = getType(target);
let cloneTarget;
if (deepTag.includes(type)) {
cloneTarget = getInit(target, type);
} else {
return cloneOtherType(target, type);
}

// 防止循环引用
if (map.get(target)) {
return map.get(target);
}
map.set(target, cloneTarget);

// 克隆set
if (type === setTag) {
target.forEach(value => {
cloneTarget.add(clone(value, map));
});
return cloneTarget;
}

// 克隆map
if (type === mapTag) {
target.forEach((value, key) => {
cloneTarget.set(key, clone(value, map));
});
return cloneTarget;
}

// 克隆对象和数组
const keys = type === arrayTag ? undefined : Object.keys(target);
forEach(keys || target, (value, key) => {
if (keys) {
key = value;
}
cloneTarget[key] = clone(target[key], map);
});

return cloneTarget;
}

module.exports = {
clone
};

尽管使用深拷贝会完全的克隆一个新对象,不会产生副作用,但是深拷贝因为使用递归,性能会不如浅拷贝,在开发中,还是要根据实际情况进行选择。

7月
28
更新于
7月28
2020
React

Docker

发表于 2020-07-28 | 热度 ℃
| 字数统计: 672 (字) | 阅读时长: 2 (分钟)

前言

react-native开发使用的是JS,但是并不是纯正的JS,而是一种JSX语言,就是在JS中嵌入XML语言,因此,只要有一些JS的语法基础的原生开发者,就可以肯容易理解JSX的语法了,在RN中,推荐使用ES6的语法。

性能

使用react-native开发的最大的有点在于开发效率,加入APP并不复杂的话,那么完全可以使用纯JS开发,也就是Android和iOS公用一套界面和逻辑。极大的提高了开发效率。在性能上,RN的表现比原生弱一些,但 是远好于H5。所以总体来看,其实RN的未来还是可以期待的。

运行机制

RN是运行JS的,Android是运行Java字节码的,所以,实际上JS代码的最终运行是通过一层封装,把JS的代码映射成原生代码,而界面上的元素最终使用的也是原生的组件,而不是自己渲染(所以在性能上,RN比H5要 好很多)。

Component简介

在Android中,主要交互容器是activity或Fragment,而在RN中,界面的交互容器是Component:组件。我觉得Component和原生的Fragment其实很像,都存在于activity中,都受制于activity的生命周期,都可卸 载和装载。


阅读全文 »
7月
24
更新于
7月24
2020
CSS

响应式网页设计

发表于 2018-06-20 | 热度 ℃
| 字数统计: 789 (字) | 阅读时长: 3 (分钟)

什么是响应式网站

响应式布局是Ethan Marcotte在2010年5月份提出的一个概念,简而言之,就是一个网站能够兼容多个终端——而不是为每个终端做一个特定的版本。这个概念是为解决移动互联网浏览而诞生的。Web设计应该做到根据不同设备环境自动响应及调整。当然响应式Web设计不仅仅是关于屏幕分辨率自适应以及自动缩放的图片等等,它更像是一种对于设计的全新思维模式;我们应当向下兼容、移动优先。


阅读全文 »
7月
22
更新于
7月22
2020
知识

babel的.babelrc配置

发表于 2018-10-29 | 热度 ℃
| 字数统计: 488 (字) | 阅读时长: 2 (分钟)

Babel 是一个工具链,主要用于将 ECMAScript 2015+ 版本的代码转换为向后兼容的 JavaScript 语法,以便能够运行在当前和旧版本的浏览器或其他环境中。Babel 内部所使用的语法解析器是 Babylon

一个基本的.babelrc配置:

1
2
3
4
5
6
7
{
"presets": [
"env",
"stage-0"
],
"plugins": ["transform-runtime"]
}

阅读全文 »
7月
22
更新于
7月22
2020
Ng

大漠穷秋angular7讲座

发表于 2018-12-14 | 热度 ℃
| 字数统计: 330 (字) | 阅读时长: 1 (分钟)

h5 132合法标签 大而全的angular emmm一上午要讲基础–还都是基本例子基本都见过

编译器

集成开发环境@angular/cli

模板引擎

组件库

  • datagrid
  • tree z-tree
  • datepicker
  • formvalid ng2-admin 比较接地气
  • JHipster
  • nicefish

  • 生成组件

    ng g c User

1
npm install -g @angular/cli

阅读全文 »
7月
22
更新于
7月22
2020
Ng

Angular组件通讯

发表于 2020-03-15 | 热度 ℃
| 字数统计: 759 (字) | 阅读时长: 4 (分钟)

组件通讯,意在不同的指令和组件之间共享信息。

父->子 input

1
2
3
4
5
// parent.html
<child [content]="i"></child>

// child.ts
@Input() content:string;

子->父 output

1
2
3
4
5
6
7
// parent.html
<child (changeNumber)="changeNumber($event)"></child>

// child.ts
@Output() changeNumber: EventEmitter<number> = new EventEmitter();

this.changeNumber(1);

阅读全文 »
7月
22
更新于
7月22
2020
React

react SSR教程

发表于 2020-06-10 | 热度 ℃
| 字数统计: 2,361 (字) | 阅读时长: 10 (分钟)

前言

本文是基于react ssr的入门教程,在实际项目中使用还需要做更多的配置和优化,比较适合第一次尝试react ssr的小伙伴们。技术涉及到 koa2 + react,案例使用create-react-app创建。

客户端渲染与服务端渲染

客户端渲染

  • 客户端渲染,实际上就是客户端向服务端请求页面,服务端返回的是一个非常简单的 HTML 页面,在这个页面里,只有很少的一些 HTML 标签
  • 客户端渲染时,页面中有两个比较重要的点,第一个是 script 标签,可能会有好几个 script 标签,这个标签是打包后的 js 代码,用来生成 DOM 元素,发送请求,事件绑定等。但是,生成的 DOM 元素需要有一个在页面上展示的容器,所以另外一个点就是容器,一般是一个 id 名为 root 或 app 的 div 标签,类似于这样 <div id="root"></div> 或<div id="app"></div>
  • 客户端渲染的特点
    • 客户端加载所有的 js 资源,渲染 DOM 元素
    • 在浏览器页面上的所有资源,都由客户端主动去获取,服务端只负责静态资源的提供和 API 接口,不再负责页面的渲染,如果采用 CDN 的话,服务端仅仅需要提供 API 接口
    • 优点: 前后端分离,责任区分,前端专注页面的开发,后端专注接口的开发
    • 缺点: 首屏加载资源多,首屏加载时响应慢。页面上没有 DOM 元素,不利于 SEO 优化

服务端渲染

  • 服务端渲染,就是客户端页面上的 HTML 元素,都要由服务端负责渲染。服务端利用模板引擎,把数据填充到模板中,生成 HTML 字符串,最终把 HTML 字符串返回到浏览器,浏览器接收到 HTML 字符串,通过 HTML 引擎解析,最终生成 DOM 元素,显示在页面上
  • 比如 Node.js 可以渲染的模板引擎有 ejs,nunjucks,pug 等。Java 最常见的是 JSP 模板引擎。Python 最常见的是 Jinja2 模板引擎。
  • 服务端渲染的特点
    • 优点: 页面资源大多由服务端负责处理,所以页面加载速度快,缩短首屏加载时间。有利于 SEO 优化。无需占用客户端资源
    • 缺点: 不利于前后端分离,开发效率低。占用服务器资源

区分与选择

  • 客户端渲染和服务端渲染本质的区别就是,是谁负责 HTML 页面的拼接,那么就是谁渲染的页面
  • 如果对首屏加载时间有非常高的需求,或者是需要 SEO 优化,那么就选择服务端渲染
  • 如果对首屏加载时间没有要求,也不需要做 SEO 优化,类似于做后台管理系列的业务,那么就可以选择客户端渲染
  • 具体选择客户端渲染还是服务端渲染,没有强制的要求,具体要根据项目的需求来区分选择

阅读全文 »
7月
21
更新于
7月21
2020
JS

如何用js实现JSON.parse()

发表于 2018-12-22 | 热度 ℃
| 字数统计: 328 (字) | 阅读时长: 2 (分钟)

eval

1
2
var json = '{"a":"1", "b":2}';
var obj = eval("(" + json + ")"); // obj 就是 json 反序列化之后得到的对象

为什么要加括号呢? 因为js中{}通常是表示一个语句块,eval只会计算语句块内的值进行返回。加上括号就变成一个整体的表达式。

1
2
console.log( eval('{}') );      // undefind
console.log( eval('({})') ); // Object {}

eval作用域问题

1
2
3
4
5
6
7
var s = 1;
function a() {
eval('var s=2');
console.log(s);
}
a(); // 2
console.log(s); // 1
在局部环境使用eval便会创建局部变量。可以显示指定eval调用者来改变上下文环境。

1
2
3
4
5
6
7
var s = 'global';
function a() {
eval('var s = "local"');
console.log(s); // local
console.log(eval('s')); // local
console.log(window.eval('s')); // global
}

对参数json进行校验防止xss漏洞

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
var rx_one = /^[\],:{}\s]*$/;
var rx_two = /\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g;
var rx_three = /"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g;
var rx_four = /(?:^|:|,)(?:\s*\[)+/g;

if (
rx_one.test(
json
.replace(rx_two, "@")
.replace(rx_three, "]")
.replace(rx_four, "")
)
) {
var obj = eval("(" +json + ")");
}

递归手动扫描每个字符

new Function 函数声明的传参形式

1
2
var add = new Function('a, b', 'return a+b;');
console.log( add(2, 3) ); // 5
1
2
var jsonStr = '{ "age": 20, "name": "jack" }',
json = (new Function('return ' + jsonStr))();

插入script

模拟jsonP的方式拼接字符串然后以callBack的方式返回。

7月
21
更新于
7月21
2020
JS

JavaScript深入之执行上下文

发表于 2018-06-13 | 热度 ℃
| 字数统计: 2,256 (字) | 阅读时长: 9 (分钟)

执行上下文(EC)就是当前JavaScript代码被解析和执行是所在环境的抽象概念,JavaScript中运行任何的代码都是在执行上下文中运行。

变量/函数提升(函数及变量的声明都将被提升到函数的最顶部,且函数声明在变量声明上边)

1
2
3
4
5
if(!("a" in window)){ // false
var a=1;
}
console.log(a) // undefined
// if(o.x){} // 不能判断属性存不存在 假值undefine,null,false," ",0或NaN
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
function foo() {
console.log('foo1');
}

foo(); // foo2

function foo() {
console.log('foo2');
}

foo(); // foo2
---
var getName = function () { alert (4);};
function getName() { alert (5);}
getName(); // 4
---
function getName() { alert (5);}
var getName = function () { alert (4);};
function getName() { alert (6);}
getName(); // 4

函数表达式执行的优先级==!主要原因是函数声明都被提前了,所以函数表达式在最后会覆盖。

JavaScript 引擎并非一行一行地分析和执行程序,而是一段一段地分析执行。插槽slot 可执行代码的类型:全局代码、函数代码、eval代码。 JavaScript 引擎创建了执行上下文栈(Execution context stack,ECS)来管理执行上下文


阅读全文 »
7月
21
更新于
7月21
2020
JS

JavaScript停止冒泡和阻止浏览器默认行为

发表于 2018-06-18 | 热度 ℃
| 字数统计: 429 (字) | 阅读时长: 2 (分钟)

防止冒泡

w3c的方法是e.stopPropagation(),IE则是使用e.cancelBubble = true

stopPropagation也是事件对象(Event)的一个方法,作用是阻止目标元素的冒泡事件,但是会不阻止默认行为。什么是冒泡事件?如在一个按钮是绑定一个”click”事件,那么”click”事件会依次在它的父级元素中被触发 。stopPropagation就是阻止目标元素的事件冒泡到父级元素。


阅读全文 »
1…789…16
陈宇(cosyer)

陈宇(cosyer)

不去做的话永远也做不到。

159 日志
10 分类
51 标签
RSS
GitHub Twitter E-Mail FB Page
推荐阅读
  • Callmesoul
  • JsTips
  • Personal Site
  • Resume
© 2021 陈宇(cosyer)
终于等到你(UV):   |   欢迎再来(PV):
Blog总字数: 312.5k字
苏ICP备17005342号-1