gzl的博客

  • 首页

  • 关于

  • 标签

  • 分类

  • 归档

JS逗号运算符和undefined

发表于 2019-08-05 更新于 2019-11-29 分类于 JavaScript

逗号运算符

先看外面的括号(优先级高),然后返回,后面的值,逗号运算符会返回 “()” 中的最后一个

1
2
3
4
let a = 42, b;
b = (a++, a);
console.log(a); // 43
console.log(b); // 43

a++, a中的第二个表达式 a 在 a++ 之后执行,结果为 43 ,并被赋值给 b。

如果去掉 () 会出现什么情况 ?

1
2
3
4
let a = 42, b;
b = a++, a;
console.log(a); // 43
console.log(b); // 42

原因是逗号运算符的优先级比 = 低。b = a ++ , a 可以理解为 (b = a ++) , a。

1
2
3
4
5
6
7
8
9
10
11
12
13
let x = (1, 2);
console.log(x); // 2

let f = (
function f() {
return "1";
},
function g() {
return 2;
}
)(); //f是函数g()执行后的返回值,所以f是2

console.log(typeof f); // number

undefined

undefined returned when trying to access an undeclared object property:

1
2
3
4
var obj = {}
console.log(obj.a) // undefined

console.log(window.a) // undefined

JS赋值、浅拷贝与深拷贝

发表于 2019-08-03 更新于 2019-08-12 分类于 JavaScript

赋值

b = a

赋值 = 是将某一数值或对象赋给某个变量的过程,分为下面 2 部分

  • 基本数据类型:赋值,赋值之后两个变量互不影响
  • 引用数据类型:赋址,两个变量具有相同的引用,指向同一个对象,相互之间有影响
1
2
3
4
5
6
7
8
9
10
11
let c = 1;
let d = c;
d ++;
console.log(d); // 2
console.log(c); // 1

let a = [1,2,3];
let b = a;
b[2] = 4;
console.log(a); // [1, 2, 4]
console.log(b); // [1, 2, 4]

因为基本类型值不会随之改变,因此下面的浅拷贝和深拷贝是针对对象类型的。

浅拷贝

b = a.slice()

浅拷贝即创建一个新对象,改变新对象的基本类型值,原对象不会随之改变,但如果改变新对象中引用类型内的值,原对象也会随之改变。Object.assign() 就是浅拷贝,用于将所有可枚举属性的值从一个或多个源对象复制到目标对象。它将返回目标对象。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
let a = {
name: "muyiy",
book: {
title: "You Don't Know JS",
price: "45"
}
}
let b = Object.assign({}, a);
b.name = "change";
b.book.price = "55";
console.log(b);
// {
// name: "change",
// book: {title: "You Don't Know JS", price: "55"}
// }
console.log(a);
// {
// name: "muyiy",
// book: {title: "You Don't Know JS", price: "55"}
// }

同理,对于对象类型下的数组,slice()、concat()、...运算符 经过测试后发现都是浅拷贝

1
2
3
4
5
6
let arr1 = [1 , 2 , 3 , {"name" : "张一"} , {"sex" : "male"}];
let arr2 = arr1.slice();
arr2[0] = 2;
arr2[3].name = "张三";
console.table(arr1) // 1 2 3 { name: "张三" } { sex: "male" }
console.table(arr2) // 2 2 3 { name: "张三" } { sex: "male" }
1
2
3
4
5
let arr2 = arr1.slice();
let arr2 = [].concat(arr1);
let arr2 = Array.from(arr1);
let arr2 = Array.of(...arr1);
let arr2 = [...arr1];

这里推荐使用扩展运算符…来进行浅拷贝({}、[]都推荐…),而不是Object.assign,详情请看下面的代码

Prefer the object spread operator over Object.assign to shallow-copy objects. Use the object rest operator to get a new object with certain properties omitted.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// very bad
const original = { a: 1, b: 2 };
const copy = Object.assign(original, { c: 3 }); // this mutates `original` ಠ_ಠ
delete copy.a; // so does this

// bad
const original = { a: 1, b: 2 };
const copy = Object.assign({}, original, { c: 3 }); // copy => { a: 1, b: 2, c: 3 }

// good
const original = { a: 1, b: 2 };
const copy = { ...original, c: 3 }; // copy => { a: 1, b: 2, c: 3 }

const { a, ...noA } = copy; // noA => { b: 2, c: 3 }

深拷贝

b = cloneDeep(a)

深拷贝即完全改变变量 b 之后对 a 没有任何影响。深拷贝相比于浅拷贝速度较慢并且花销较大。

JSON.parse+JSON.stringify

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
let a = {
name: "muyiy",
book: {
title: "You Don't Know JS",
price: "45"
}
}
let b = JSON.parse(JSON.stringify(a));
b.name = "change";
b.book.price = "55";
console.log(b);
// {
// name: "change",
// book: {title: "You Don't Know JS", price: "55"}
// }
console.log(a);
// {
// name: "muyiy",
// book: {title: "You Don't Know JS", price: "45"}
// }
1
2
3
4
5
6
let arr1 = [1 , 2 , 3 , {"name" : "张一"} , {"sex" : "male"}];
let arr2 = JSON.parse(JSON.stringify(arr1));
arr2[0] = 2;
arr2[3].name = "张三";
console.table(arr1) // 1 2 3 { name: "张一" } { sex: "male" }
console.table(arr2) // 2 2 3 { name: "张三" } { sex: "male" }

这个方法很简便,但是有以下几个问题。

1、会忽略 undefined

2、会忽略 symbol

3、不能序列化函数

4、不能解决循环引用的对象

5、不能正确处理new Date()

6、不能处理正则

DFS

浅拷贝 + 递归

这里呢只实现最简单的深拷贝,只考虑 数组和{} 的情况,并且没有循环引用

1
2
3
4
typeof null //"object"
typeof {} //"object"
typeof [] //"object"
typeof function foo(){} //"function" (特殊情况)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
function isObject(obj) {
return typeof obj === 'object' && obj != null;
}
// 对 null 做一下判断
function cloneDeep(source) {
if (!isObject(source)) return source;
// 非对象、null 或者 function 的话返回自身
let target = Array.isArray(source) ? [] : {};
// 直接使用Array.isArray方法进行判断:克隆 [] 或者 {}
for (let key in source) {
if (Object.prototype.hasOwnProperty.call(source, key)) {
if (isObject(source[key])) {
target[key] = cloneDeep(source[key]); // 注意这里
} else {
target[key] = source[key];
}
}
}
return target;
}

小结

– 和原数据是否指向同一对象 第一层数据为基本数据类型 原数据中包含子对象
赋值 是 改变会使原数据一同改变 改变会使原数据一同改变
浅拷贝 否 改变不会使原数据一同改变 改变会使原数据一同改变
深拷贝 否 改变不会使原数据一同改变 改变不会使原数据一同改变

参考

https://github.com/airbnb/javascript

JS工具函数

发表于 2019-08-03 更新于 2019-11-30 分类于 JavaScript

判断数据类型

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// 工具函数
let _toString = Object.prototype.toString
let map = {
array: 'Array',
object: 'Object',
function: 'Function',
string: 'String',
null: 'Null',
undefined: 'Undefined',
boolean: 'Boolean',
number: 'Number'
}
let getType = (item) => {
return _toString.call(item).slice(8, -1)
}
let isTypeOf = (item, type) => {
return map[type] && map[type] === getType(item)
}

数组去重方法

键值对原理

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
let x = [1, 3, 4, 1, 4, 6, 9];

Array.prototype.unique = function () {
var temp = {},
arr = [],
len = this.length;
for(let i = 0; i < len; i ++){
if (!temp[this[i]]) {
temp[this[i]] = 'abc';
arr.push(this[i]);
}
}

return arr;
}

console.log(x.unique());

ES6 set

1
2
3
let arr = [1, 3, 4, 1, 4, 6, 9];
let b = [...new Set(arr)];
console.log(b); // [1, 3, 4, 6, 9]

判断是否为空

1
2
3
4
5
6
7
8
function isEmpty(value){
return (
value === undefined ||
value === null ||
(typeof value === 'object' && Object.keys(value).length===0) ||
(typeof value === 'string' && value.trim().length===0)
);
}

比较属性

不同的引用类型含有相同的属性

If they’re distinct objects, even if they contain identical properties, the comparison will result in false.

1
2
3
4
var arr1 = ['Hi!'];
var arr2 = ['Hi!'];
console.log(arr1 === arr2);
// false

If we have two distinct objects and want to see if their properties are the same, the easiest way to do so is to turn them both into strings and then compare the strings. When the equality operators are comparing primitives, they simply check if the values are the same.

1
2
3
4
var arr1str = JSON.stringify(arr1);
var arr2str = JSON.stringify(arr2);
console.log(arr1str === arr2str);
// true

Another option would be to recursively loop through the objects and make sure each of the properties are the same.

1…212223…32

gzl

96 日志
14 分类
37 标签
© 2020 gzl
由 Hexo 强力驱动 v3.7.1
|
主题 – NexT.Pisces v7.2.0