1. 概念
1. 改变 & 不改变数组方法
1. 改变原数组
+ pop
+ push
+ reverse
+ shift / unshift
+ sort
+ splice
2. 不改变原数组
+ concat
+ join
+ slice
+ JSON.parse / JSON.stringfy
+ indexOf / lastindexOf
+ filter
+ reduce
+ map
+ [...arr]
2. slice splice区别
// splice(start, count, item1, item2, itemN)
let fruits = ["Banana", "Orange", "Apple", "Mango"];
let ret = fruits.splice(2, 1, "Lemon", "Kiwi");
console.log(fruits) //["Banana", "Orange", "Lemon", "Kiwi", "Mango"]
console.log(ret) //["Apple"]
// slice(start, end)
var fruits = ["Banana", "Orange", "Lemon", "Apple", "Mango"];
var citrus = fruits.slice(1,3);
console.log(citrus) // [Orange,Lemon]
3. for of & for in
1. `for...in` 便利数组或对象属性
2. `for in` 得到对象key 或 字符串下标
3. `for of` 和 `forEach` 一样, 可以直接得到值
4. `for of` 不能用于对象, 可以遍历string, 和 0xFFFF码点
// 遍历对象
const obj = {
a: 1,
b: 2,
c: 3
}
for (let i in obj) {
console.log(i) //输出 : a b c
}
for (let i of obj) {
console.log(i) //输出: Uncaught TypeError: obj is not iterable 报错了
}
// 遍历数组
const arr = ['a', 'b', 'c']
// for in 循环
for (let i in arr) {
console.log(i) //输出 0 1 2
}
// for of
for (let i of arr) {
console.log(i) //输出 a b c
}
4. event loop => 宏任务 & 微任务
宏:
+ script
+ setTimeout / setInterval / setImmediate(node)
⚠️ setTimeout延迟时间: 也就是说小于1ms的值,默认使用1ms, 超过5层, 最小间隔 4ms
+ ajax
+ 事件绑定
+ requestAnimationFrame(浏览器)
+ I / O
+ UI render(浏览器)
微:
+ new Promise的then catch
+ process.nextTick(node)
1. 事件循环由宏任务和在执行宏任务期间产生的所有微任务组成, 完成当下的宏任务后, 会立刻执行所有在此期间入队的微任务.
2. 区分了微任务和宏任务后,本轮循环中的微任务实际上就是在插队, 这样微任务中所做的状态修改, 在下一轮事件循环中也能得到同步.
3. 宏任务队列只有一个,而每一个宏任务都有一个自己的微任务队列, 每轮循环都是由一个宏任务+多个微任务组成.
4. w3c新规则: 存放定时器的队列是延时队列,存放用户交互操作的是交互队列, 还有浏览器一定要准备好的微任务队列, 优先级是最高的.
5. 原始数据类型
+ undefined
+ null
+ boolean
+ string
+ number
+ object
+ symbol(es6)
2. 方法
1. Array
2. Object
Object.defineProperty
配置项:
writable: 是否可重写
value: 当前值
get: 读取时内部调用的函数
set: 写入时内部调用的函数
enumerable: 是否可以遍历
configurable: 是否可再次修改配置项
let person = {
name: '码农',
age: 18,
};
Object.defineProperty(person, 'sex', {
value: '男', //设置属性值
enumerable: false, //控制属性是否可以枚举,默认值是true
writable: true, //控制属性是否可以被修改,默认值是true
configurable: true, //控制属性是否可以被删除,默认值是true
});
// 可以用getOwnPropertyDescriptors方法查看对象属性配置项
console.log(Object.getOwnPropertyDescriptors(person));
3. this
1. 区别:
+ bind 调用后触发
+ apply 跟参数, 为一个数组
// 小白对象
let xiaobai = {
name: "小白",
pet: "splider"
}
// 小杨对象
let xiaoyang = {
name: '小杨',
pet: 'pig',
say: function (...args) {
console.log(this)
console.log(`${this.name}有一只${this.pet}宠物 to say${args[0]} and ${args[1]}`)
}
}
xiaoyang.say.call(xiaobai, 'fff', 'ddd')
xiaoyang.say.apply(xiaobai, ['fff', 'ddd'])
xiaoyang.say.bind(xiaobai, 'fff', 'ddd')() // 调用后触发
let arrayLike = {
'0': 'a',
'1': 'b',
'2': 'c',
length: 3
};
// ES5的写法 -- 改变this指向
var arr1 = [].slice.call(arrayLike); // ['a', 'b', 'c']
4. reduce
var arr = [1, 2, 3, 4];
var sum = arr.reduce(function (prev, cur, index, arr) {
console.log(prev, cur, index, arr);
return prev + cur; // return后的值赋给prev, 此处可以认为 prev = prev + cur
}, 22); // 第二个参数, 实际为index == 0 的prev 赋值为 initValue
console.log(arr, sum);
// 1. 计算每个元素出现的次数
let names = ['Alice', 'Bob', 'Tiff', 'Bruce', 'Alice'];
let nameNum = names.reduce((pre, cur) => {
if (cur in pre) {
pre[cur]++;
} else {
pre[cur] = 1;
}
console.log(pre, cur);
return pre; // 若prev是复杂数据类型, return 后 pre元素相累计为一个新的复杂数据类型
}, {});
console.log(nameNum); //{Alice: 2, Bob: 1, Tiff: 1, Bruce: 1}
// 2. 数组去重
let reArr = [1, 2, 3, 4, 4, 1];
let newArr = arr.reduce((pre, cur) => {
if (!pre.includes(cur)) {
return pre.concat(cur);
} else {
return pre;
}
}, []);
console.log(reArr); // [1, 2, 3, 4]
// 3. 数组扁平化
let flatArr = [
[0, 1],
[2, 3],
[4, [5, 6, 7, [9, 11, [33, 23, [1, 2, 3, 4]]]]],
];
const newFlatArr = function (arr) {
return arr.reduce((pre, cur) => pre.concat(Array.isArray(cur) ? newFlatArr(cur) : cur), []);
};
console.log(newFlatArr(flatArr)); //[0, 1, 2, 3, 4, 5, 6, 7]
// 4. 对象里属性求和
var result = [
{
subject: 'math',
score: 10,
},
{
subject: 'chinese',
score: 20,
},
{
subject: 'english',
score: 30,
},
];
var resSum = result.reduce(function (prev, cur) {
return cur.score + prev;
}, 0);
console.log(resSum); //60
5. slice
1. slice 不会改元素, 只会返回一个浅复制了原数组中的元素和一个新数组.
2. 如果该元素是个 对象引用 (不是实际的对象), slice 会拷贝这个对象引用到新的数组里, 两个对象引用都引用了同一个对象。如果被引用的对象发生改变,则新的和原来的数组中的这个元素也会发生改变.
var arr = [];
let arrayLike = {
0: 'a',
1: 'b',
2: 'c',
length: 3
}
for (var i = 0; i < arrayLike.length; i++) {
arr.push(arrayLike[i]);
}
console.log('原理=>', arr);
// 等价写法
// 这里可以改变this的call出现了,假如我用call将arguments把this给slice
// slice会得到具有长度属性的对象,就实现了对象转数组的
console.log('快捷=>', [].slice.call(arrayLike));
3. ES6
1. 类
class Person {
constructor(name, age) {
// 通过new创建对象时, 实际上就是在调用类的构造函数
console.log('constructor!!')
// 在构造函数中, 可以通过this来引用当前对象
this.name = name
this.age = age
}
// 方法
sayHi() {
console.log('hi I am lily')
}
// this
/*
类中所有代码都会在严格模式中执行
*/
fn() {
console.log('-->', this)
}
}
const p = new Person('lily', 18) // 创建对象
p.sayHi() // 调用方法
console.log(p) // {name: 'lily', age: 18}
console.log(p.fn()) // Person {}
const test = p.fn
2. ...
`...` 展开语法本质是是“浅拷贝”——它只会复制一层, 这使得它的执行速度很快, 但是也意味着当你想要更新一个嵌套属性时, 你必须得多次使用展开语法.
3. 函数
1. rest函数:
+ rest函数实际上是 ... 的相反用法.
2. 箭头函数:
1. 箭头函数没有arguments.
2. 箭头函数没有自己的this.
3. 剪头函数中的this无法通过call(), apply(), bind()修改.
4. 箭头函数无法作为构造函数使用.
5. pipeline 管道机制, 前一个函数的输出是后一个函数的输入.
3. 尾调用:
+ 尾调用(Tail Call), 就是指某个函数的最后一步是调用另一个函数.
4. 柯里化:
+ 将多参数的函数转换成单参数的形式, 希望函数功能尽可能单一.
// 1. rest
function demo(...params) {
console.log(params)
}
demo(1, 2, 3, 4) // [1, 2, 3, 4]
// 2. pipeline 例子
const pipeline = (...funcs) =>
val => funcs.reduce((a, b) => b(a), val);
const plus1 = a => a + 1;
const mult2 = a => a * 2;
console.log(pipeline(plus1, mult2)(5)) // 12
// 3. 尾调用
// eg
function f(x){
return g(x);
}
// 尾递归1 -- 阶乘
function factorial(n, total = 1) {
if (n === 1) return total;
return factorial(n - 1, n * total);
}
// 尾递归2 -- Fibonacci函数的实现
function Fibonacci2 (n , ac1 = 1 , ac2 = 1) {
if( n <= 1 ) {return ac2};
return Fibonacci2 (n - 1, ac2, ac1 + ac2);
}
// 4. 柯里化
// eg
const fn = a => b => c => a + b + c;
console.log(fn(1)(2)(3))
5. 数组
1. Array.from:
+ 伪数组类型转为真正的数组 Set, Map, arguments
2. Array.of:
+ 将一组值转为数组
3. copyWithin:
4. find & findIndex:
+ findeIndex, 类似 indexOf方法, 可以识别NaN.
5. entries & keys & values:
+ entries 对整个键值对遍历.
6. includes:
+ Array.prototype.includes 与 字符串 includes方法类似.
7. flat & flatMap:
+ flatMap 相当于对元素组每个成员执行一个map函数, 再对返回值执行flat方法.
+ `flatMap()` 方法还可以有第二个参数,用来绑定遍历函数里面的 `this`
// 1. Array.from
let arrayLike = {
'0': 'a',
'1': 'b',
'2': 'c',
length: 3
};
// ES5的写法 -- 改变this指向
var arr1 = [].slice.call(arrayLike); // ['a', 'b', 'c']
// ES6的写法
let arr2 = Array.from(arrayLike); // ['a', 'b', 'c']
// 2. Array.of
// eg
Array.of(3, 11, 8) // [3,11,8]
// 实现原理
function ArrayOf () {
return [].slice.call(arguments);
}
// 3. copyWithin
<!---->
// 4. find & findIndex
// 5. entries & keys & values
for (let index of ['a', 'b'].keys()) {
console.log(index);
}
// 0
// 1
for (let elem of ['a', 'b'].values()) {
console.log(elem);
}
// 'a'
// 'b'
for (let [index, elem] of ['a', 'b'].entries()) {
console.log(index, elem);
}
// 0 "a"
// 1 "b"
// 6. includes
// 7. flat & flatMap
// eg
[1, 2, [3, 4]].flat() // 默认拉平一层
// [1, 2, 3, 4]
[1, 2, [3, [4, 5]]].flat(2) // 拉平2层
// [1, 2, 3, 4, 5]
[1, [2, [3]]].flat(Infinity) // 全部拉平
// [1, 2, 3]
// eg -- flagMap
[2, 3, 4].flatMap((x) => [x, x * 2])
// [2, 4, 3, 6, 4, 8]
arr.flatMap(function callback(currentValue[, index[, array]]) {
// ...
}, [thisArg])
// flatMap eg
const studioList = [{
Authorized: "2",
CompanyType: "1",
Id: "3729",
Name: "阿我打完的",
ServiceProviderId: "6",
TenantId: "1",
},
{
Authorized: "1",
CompanyType: "1",
Id: "3134",
Name: "纳税统计-启用时间202101无期初",
ServiceProviderId: "6",
TenantId: "1",
},
{
Authorized: "1",
CompanyType: "1",
Id: "427",
Name: "美丽人生工作室",
ServiceProviderId: "6",
TenantId: "1",
},
{
Authorized: "1",
CompanyType: "1",
Id: "410",
Name: "凭证测试专用2",
ServiceProviderId: "6",
TenantId: "1",
}]
/**
* 目标格式:
* [
{
text: '公司名称',
value: '公司ID'
}
]
*/
// filter + map
const filterList1 = studioList.filter(r => r.Authorized == '1').map(i => ({ text: i.Name, value: i.Id }))
// flatMap
const filterList2 = studioList.flatMap(r => r.Authorized == '1' ? { text: r.Name, value: r.Id } : [])
6. 对象
1. Object.is:
+ 比较两值是否相等
2. Object.keys & Object.getOwnPropertyNames:
+ same: 都是返回自身的属性,不会返回原型链上的.
+ diff: Object.keys()返回可枚举的,Object.getOwnPropertyNames()返回所有的.
3. Object.assign:
1. 当对象中只有一级属性,没有二级属性的时候,此方法为深拷贝,但是对象中有对象的时候,此方法,在二级属性以后就是浅拷贝.
2. 如果目标对象与源对象有同名属性,或多个源对象有同名属性,则后面的属性会覆盖前面的属性 (同名属性替换).
3. 如果该参数不是对象,则会先转成对象,然后返回.
4. super:
1. Object.setPrototypeOf(obj, params) -- 将属性写在对象原型链上
2. Object.getPrototypeOf(params) -- 从对象原型链上的属性
5. ?. (链判断运算符) ?? (Null判断运算符):
6. Object.keys & Object.values & Object.entries:
7. Object.fromEntries:
// 1. Object.is
Object.is(+0, -0) // false
Object.is({}, {}) // false
Object.is(NaN, NaN) // true
// 3. Object.assign
// 3.1. 对象合并
var target = {name:'带你飞',age:16}
var source = {age:18}
var result = Object.assign(target,source)
console.log(result,target===result); // {name: '带你飞', age: 18} true
// 3.2. 原始类型封装为对象
var source1 = "abc";
var source2 = true;
var source3 = 10;
var result = Object.assign({}, source1, null, source2, undefined, source3);
// 原始类型会被包装,null 和 undefined 会被忽略。
// 注意,只有字符串的包装对象才可能有自身可枚举属性。
console.log(result); // {0: 'a', 1: 'b', 2: 'c'}
// 3.3. 将数组认为是对象
Object.assign([1, 2, 3], [4, 5])
// [4, 5, 3]
// 4. super
// super.foo指向原型对象proto的foo方法,但是绑定的this却还是当前对象obj,因此输出的就是world
const proto = {
x: 'hello',
foo() {
console.log(this.x);
},
};
const obj = {
x: 'world',
foo() {
super.foo();
}
}
Object.setPrototypeOf(obj, proto);
obj.foo() // "world"
// 5. ?. ??
const obj = {
x: 'hello',
y: 'world',
zero: 0,
}
// ?. 类似三目 判断属性是否存在
let objP = obj?.x || 'default'
console.log(objP) // hello
// delete 存在则删除
delete obj?.x
console.log(obj) // {y: 'world'}
// ?? 类似|| 只有null才生效, false 和 0 不生效
let objZ = obj?.zero ?? true
console.log(objZ) // true
// 6. Object.keys & Object.values & Object.entries
// keys -- 键
// values -- 值
// entries -- 键值对 (单项数组形式)
let { keys, values, entries } = Object;
let objEn = { a: 1, b: 2, c: 3 };
for (let key of keys(objEn)) {
console.log(key); // 'a', 'b', 'c'
}
for (let value of values(objEn)) {
console.log(value); // 1, 2, 3
}
for (let [key, value] of entries(objEn)) {
console.log([key, value]); // ['a', 1], ['b', 2], ['c', 3]
}
for (let item of entries(objEn)) {
console.log(item); // ['a', 1], ['b', 2], ['c', 3]
}
// 7. Object.fromEntries
// 例一
const entries = new Map([
['foo', 'bar'],
['baz', 42]
]);
Object.fromEntries(entries)
// { foo: "bar", baz: 42 }
// 例二
const map = new Map().set('foo', true).set('bar', false);
Object.fromEntries(map)
// { foo: true, bar: false }
7. Set & Map
set中 NaN 是相同的, 两个空对象 是不同的
1. Set.prototype.constructor:
+ 构造函数,默认就是`Set`函数.
2. Set.prototype.size:
+ 返回`Set`实例的成员总数.
3. Set.prototype.add(value):
+ 添加某个值,返回 Set 结构本身.
4. Set.prototype.delete(value):
+ 删除某个值,返回一个布尔值,表示删除是否成功.
5. Set.prototype.has(value):
+ 返回一个布尔值,表示该值是否为`Set`的成员.
6. Set.prototype.clear():
+ 清除所有成员,没有返回值.
const map = new Map()
let params1 = ['a']
let params2 = ['a']
map.set(params1, 111).set(params2, 222).set('aaa', 'aaa') // 可链式, 对象做键同值不同址
console.log(map.size) // 2
console.log(map.get(params1)) // 111
console.log(map.has(['a']), map.has(params1)) // false true
//map.delete('aaa') // 删除 'aaa' => 'aaa'
//map.clear() // 清空所有
// map.keys()
console.log(map.keys()) // MapIterator {Array(1), Array(1), 'aaa'}
for (let key of map.keys()) {
console.log(key) // ['a'] ['a'] 'aaa' (三次循环)
}
// map.values()
console.log(map.values()) // MapIterator {111, 222, 'aaa'}
for (let val of map.values()) {
console.log(val) // 111 222 'aaa' (三次循环)
}
// map.entries()
console.log(map.entries()) // MapIterator {Array(1) => 111, Array(1) => 222, 'aaa' => 'aaa'}
for (let [key, val] of map.entries()) {
console.log(key, val) // ['a'] 111; ['a'] 222; 'aaa' 'aaa'
}
// 拓展运算符...
console.log([...map.keys()])
// [1, 2, 3]
console.log([...map.values()])
// ['one', 'two', 'three']
console.log([...map.entries()])
// [[1,'one'], [2, 'two'], [3, 'three']]
console.log([...map])
// [[1,'one'], [2, 'two'], [3, 'three']]
8. Promise
1. then
function runAsync () {
return new Promise(function (resolve, reject) {
//做一些异步操作
setTimeout(function () {
console.log('执行完成');
resolve('随便什么数据');
}, 1000);
});
}
runAsync().then(v => {
console.log(v)
return runAsync()
}).then(v => {
console.log(v)
return runAsync()
}).then(v => {
console.log(v)
return runAsync()
})
执行完成 // 1000
随便什么数据 // 1000
执行完成 // 2000
随便什么数据 // 2000
执行完成 // 3000
随便什么数据 // 3000
执行完成 // 4000
2. resolve & reject
function getNumber () {
return new Promise(function (resolve, reject) {
//做一些异步操作
setTimeout(function () {
var num = Math.ceil(Math.random() * 10); //生成1-10的随机数
console.log('num', num)
if (num <= 5) {
resolve(num);
reject('数字刚刚好') // 执行完resolve 不会继续执行 reject
}
else {
reject('数字太大了');
resolve(num); // 同理 执行完 reject 不会执行 resolve
}
}, 1000);
});
}
getNumber()
.then(
function (data) {
console.log('resolved');
console.log(data);
},
function (reason, data) {
console.log('rejected');
console.log(reason);
}
);
// eg1: resolve情况
num 4
resolved
4
// eg2: reject情况
num 10
rejected
数字太大了
3. catch
function getNumber () {
return new Promise(function (resolve, reject) {
//做一些异步操作
setTimeout(function () {
var num = Math.ceil(Math.random() * 10); //生成1-10的随机数
console.log('num', num)
if (num <= 5) {
resolve(num);
reject('数字刚刚好') // 执行完resolve 不会继续执行 reject
}
else {
reject('数字太大了');
resolve(num); // 同理 执行完 reject 不会执行 resolve
}
}, 1000);
});
}
// then中回调函数只有一个参数, 默认参数是resolve回调函数
// 若有reject, 没有第二个参数, 则被catch承接
// 遇到 reject(没有第二个参数), err情况 都会直接执行到catch
getNumber()
.then(function (data) {
console.log('resolved');
console.log(data);
// console.log(somedata); //此处的somedata未定义
return getNumber()
})
.then(function (data) {
console.log('resolved');
console.log(data);
return getNumber()
})
.then(function (data) {
console.log('resolved');
console.log(data);
return getNumber()
})
.catch(function (reason) {
console.log('rejected catch');
console.log(reason);
});
// eg1: 没有执行到catch
num 5 // 1000
resolved // 1000
5 // 1000
num 4 // 2000
resolved // 2000
4 // 2000
num 5 // 3000
resolved // 3000
5 // 3000
num 3 // 4000
// eg2: 执行过程中 执行到reject
num 1 // 1000
resolved // 1000
1 // 1000
num 9 // 2000
rejected catch // 2000
数字太大了 // 2000
// eg3: 首次执行 执行到reject
num 10 // 1000
rejected catch // 1000
数字太大了 // 1000
// eg4: 放开console.log(somedata), 数字太大 先执行reject, 直接中断
num 8 // 1000
rejected catch // 1000
数字太大了 // 1000
// eg5: 放开console.log(somedata), 数字正常 先执行resolve, 再执行catch
num 3 // 1000
resolved // 1000
3 // 1000
rejected catch // 1000 (同步)
somedata is not defined // 1000 (同步)
4.all & race
function runAsync1 () {
return new Promise(function (resolve, reject) {
//做一些异步操作
setTimeout(function () {
console.log('异步任务1执行完成');
resolve('随便什么数据1');
}, 1000);
});
}
function runAsync2 () {
return new Promise(function (resolve, reject) {
//做一些异步操作
setTimeout(function () {
console.log('异步任务2执行完成');
resolve('随便什么数据2');
}, 1000);
});
}
function runAsync3 () {
return new Promise(function (resolve, reject) {
//做一些异步操作
setTimeout(function () {
console.log('异步任务3执行完成');
resolve('随便什么数据3');
}, 1000);
});
}
// all----------------------------
// all接收一个数组参数,里面的值最终都算返回Promise对象。这样,三个异步操作的并行执行的
// 等全部执行完
Promise
.all([runAsync1(), runAsync2(), runAsync3()])
.then(function (results) {
console.log(results);
});
// eg1: all
异步任务1执行完成
异步任务2执行完成
异步任务3执行完成
(3) ['随便什么数据1', '随便什么数据2', '随便什么数据3']
// race----------------------------
// race 是 第一个执行完的 执行回调 然后其他继续执行 (回调后并不会像catch那样中断其他任务)
Promise
.race([runAsync1(), runAsync2(), runAsync3()])
.then(function (results) {
console.log('first ok ', results);
});
// eg2: race
异步任务1执行完成
first ok 随便什么数据1
异步任务2执行完成
异步任务3执行完成
// race demo----------------------------
//请求某个图片资源
function requestImg () {
return new Promise(function (resolve, reject) {
var img = new Image();
img.onload = function () {
resolve(img);
}
img.src = '../../img/img01.png'; // right
// img.src = 'xxxxxxx'; // fault
});
}
//延时函数,用于给请求计时
function timeout () {
return new Promise(function (resolve, reject) {
setTimeout(function () {
reject('图片请求超时');
}, 5000);
});
}
Promise
.race([requestImg(), timeout()])
.then(function (results) { // 成功请求到返回 (立刻)
console.log('right', results);
})
.catch(function (reason) { // 报错返回 (5000ms后)
console.log('fail', reason);
});
// eg3: race success
right <img src="../../img/img01.png">
// eg4: race fail
GET http://127.0.0.1:5500/img/img1.png 404 (Not Found)
promise.js:188 fail 图片请求超时 // 5000
9. class
1. getter & setter
class MyClass {
constructor () {
this.con_var = 'constructor中的变量'
this.con_fun = function () {
return 'constructor中的方法'
}
this.self2 = this.self2.bind(this)
}
params () {
return 'this is params'
}
get prop () {
return 'this is prop'
}
set prop (value) {
console.log('setter', value)
}
var1 = '定义的变量直接属于类本身方法'
self1 = () => {
return '箭头函数或者在constructor中重绑this指向会属于类本身方法而非prototype中属性'
}
self2 () {
return 'this中重新指向(同时也会在prototype中隐式属性中保留)'
}
self3 () {
return '普通方法会在prototype中隐式属性显示'
}
}
let my = new MyClass()
my.attr = 'set attr 属性' // 最后attr属性值以get方法return为准
console.log(my)
console.log(my.attr, my.__proto__.attr) // this is params this is params
// getPrototypeOf定义的变量 / 方法 都在prototype的显式属性
// 直接定义的变量 / 方法 则在实例的显式属性中
my.out_var1 = 'out定义实例变量1'
Object.getPrototypeOf(my).out_var2 = 'out定义实例变量2 (prototype中)'
my.out_fun1 = function () {
return 'out定义实例方法1'
}
my.out_fun2 = () => {
return 'out定义实例方法2'
}
Object.getPrototypeOf(my).out_fun3 = function () {
return 'out定义实例方法3 (prototype中)'
}
Object.getPrototypeOf(my).out_fun4 = () => {
return 'out定义实例方法4 (prototype中)'
}
2. 属性表达式
var funName = 'outTing'
class AA {
constructor (val) {
this.name = val
this.description = 'aaaaaa'
}
[funName] () {
return 'prototype中的隐式属性'
}
}
// 直接赋值
let person1 = new class {
constructor (name) {
this.name = name;
}
sayName () {
console.log(this.name);
}
}('张三');
person1.sayName(); // "张三"
console.log(person1)
3. 静态方法static
// 静态
4. 封装
1. 时间
时间戳格式化
function timestampToTime(timestamp) {
// 时间戳为10位需*1000,时间戳为13位不需乘1000
var date = new Date(timestamp * 1000);
var Y = date.getFullYear() + '-';
var M =
(date.getMonth() + 1 < 10 ? '0' + (date.getMonth() + 1) : date.getMonth() + 1) + '-';
var D = (date.getDate() < 10 ? '0' + date.getDate() : date.getDate()) + ' ';
var h = date.getHours() + ':';
var m = date.getMinutes() + ':';
var s = date.getSeconds();
return Y + M + D + h + m + s;
}
console.log(new Date().getTime());
console.log(timestampToTime(1670145353)); //2022-12-04 17:15:53
2. obj 按key排序
function objKeySort(arys) {
//先用Object内置类的keys方法获取要排序对象的属性名,再利用Array原型上的sort方法对获 取的属性名进行排序,newKey是一个数组
var newKey = Object.keys(arys).sort();
//console.log('newKey='+newKey);
var newObj = {}; //创建一个新的对象,用于存放排好序的键值对
for (var i = 0; i < newKey.length; i++) {
//遍历newKey数组
newObj[newKey[i]] = arys[newKey[i]]; //向新创建的对象中按照排好的顺序依次增加键值对
}
return newObj; //返回排好序的新对象
}
3. 深拷贝
JSON.stringfy 方法无法拷贝属性值为undefined的项
//使用递归的方式实现数组、对象的深拷贝
function deepClone(obj) {
let objClone = Array.isArray(obj) ? [] : {};
if (obj && typeof obj === 'object') {
for (var key in obj) {
if (obj.hasOwnProperty(key)) {
//判断ojb子元素是否为对象,如果是,递归复制
if (obj[key] && typeof obj[key] === 'object') {
objClone[key] = deepClone(obj[key]);
} else {
//如果不是,简单复制
objClone[key] = obj[key];
}
}
}
}
return objClone;
}