-
Notifications
You must be signed in to change notification settings - Fork 4
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
js 知识点及问题汇总(一) #4
Comments
数字转化为千分位格式 function toThousands(num) {
var num = (num || 0).toString(), result = '';
while (num.length > 3) {
result = ',' + num.slice(-3) + result;
num = num.slice(0, num.length - 3);
}
if (num) { result = num + result; }
return result;
} |
Array.fromconst getItems = count =>
Array.from({ length: count }, (v, k) => k).map(k => ({
id: item-${k},
content: item ${k},
})); 上面没看懂,主要是 Array.from 方法用于将两类对象转为真正的数组:类似数组的对象(array-like object)和可遍历(iterable)的对象(包括 ES6 新增的数据结构 Set 和 Map)。 查了一下才知道,原来 { length: count } 是类数组对象,再加一个例子就看明白了,如下: let arrayLike = {
'0': 'a',
'1': 'b',
'2': 'c',
length: 3
};
// ES5的写法
var arr1 = [].slice.call(arrayLike); // ['a', 'b', 'c']
// ES6的写法
let arr2 = Array.from(arrayLike); // ['a', 'b', 'c']
Array.from(arrayLike, (v, k) => v); // ["a", "b", "c"]
Array.from(arrayLike, (v, k) => k); // [0, 1, 2] |
Object.defineProperty(obj, prop, descriptor) Parameters
Return value The object that was passed to the function. Property descriptors present in objects come in two main flavors: data descriptors and accessor descriptors. A data descriptor is a property that has a value, which may or may not be writable. An accessor descriptor is a property described by a getter-setter pair of functions. A descriptor must be one of these two flavors; it cannot be both.
如果一个描述符不具有 value, writable, get 和 set 任意一个关键字,那么它将被认为是一个数据描述符。如果一个描述符同时有( value 或 writable)和( get 或 set)关键字,将会产生一个异常。 Bear in mind that these attributes are not necessarily the descriptor's own properties. Inherited properties will be considered as well. In order to ensure these defaults are preserved, you might freeze the |
String.prototype.match()const name = '@kk/eslint-plugin-myself'
const matchs = name.match(/^(@[^/]+)\/eslint-plugin(?:-(.*))?$/)
console.log(matchs)
/*
[ '@kk/eslint-plugin-myself',
'@kk',
'myself',
index: 0,
input: '@kk/eslint-plugin-myself',
groups: undefined ]
*/ |
self if (window.parent.frames[0] != window.self) {
// this window is not the first frame in the list
} |
检测当前环境下全局对象下的属性 function getGlobal(property) {
if (typeof self !== 'undefined' && self && property in self) {
return self[property];
}
if (typeof window !== 'undefined' && window && property in window) {
return window[property];
}
if (typeof global !== 'undefined' && global && property in global) {
return global[property];
}
if (typeof globalThis !== 'undefined' && globalThis) {
return globalThis[property];
}
}; |
reduce 应用 计算数组中每个元素出现的次数 var names = ['kk', 'mivi', 'dd', 'minghao', 'kk', 'mivi', 'kk', 'dd']
var countss = names.reduce((allNames, name) => {
if (name in allNames) {
allNames[name] = allNames[name] + 1
} else {
allNames[name] = 1
}
return allNames
}, {})
// {kk: 3, mivi: 2, dd: 2, minghao: 1} 按属性把对象分类 var people = [
{ name: 'kk', age: 25 },
{ name: 'mivi', age: 29 },
{ name: 'dd', age: 27 },
{ name: 'minghao', age: 26 },
{ name: 'kk', age: 25 },
{ name: 'nana', age: 24 }
]
var groupBy = (objectArray, property) => (
objectArray.reduce((acc, cur) => {
var key = cur[property]
if (!acc[key]) {
acc[key] = []
}
acc[key].push(cur)
return acc
}, {})
)
var ageGroup = groupBy(people, 'age') 数组去重 let arr = [1,2,1,2,3,5,4,5,3,4,4,4,4];
let result = arr.sort().reduce((init, current)=>{
if(init.length===0 || init[init.length-1]!==current){
init.push(current);
}
return init;
}, []);
console.log(result); //[1,2,3,4,5] 功能型函数管道 // Building-blocks to use for composition
const double = x => x + x;
const triple = x => 3 * x;
const quadruple = x => 4 * x;
// Function composition enabling pipe functionality
const pipe = (...functions) => input => functions.reduce(
(acc, fn) => fn(acc),
input
);
// Composed functions for multiplication of specific values
const multiply6 = pipe(double, triple);
const multiply9 = pipe(triple, triple);
const multiply16 = pipe(quadruple, quadruple);
const multiply24 = pipe(double, triple, quadruple);
// Usage
multiply6(6); // 36
multiply9(9); // 81
multiply16(16); // 256
multiply24(10); // 240 |
Object.prototype.hasOwnProperty()
|
Class 中的 super 1、Class 中的 super(),它在这里表示父类的构造函数,用来新建父类的 this 对象 super() 相当于 class Demo {
constructor(x, y) {
this.x = x;
this.y = y;
}
customSplit() {
return [...this.y]
}
}
class Demo2 extends Demo {
constructor(x, y) {
super(x, y);
}
customSplit() {
return [...this.x]
}
task1() {
return super.customSplit();
}
task2() {
return this.customSplit();
}
}
let d = new Demo2('hello', 'world');
d.task1() //["w", "o", "r", "l", "d"]
d.task2() //["h", "e", "l", "l", "o"] 2、子类没有自己的 this 对象,而是继承父亲的 this 对象,然后进行加工。如果不调用 super,子类就得不到 this 对象 class Demo2 extends Demo{
constructor(x,y){
this.x = x; //this is not defined
}
} ES5 的继承,实质上是先创造子类的实例对象 this,然后再将父类的方法添加到 this 上(Parent.call(this)). 如果子类没有创建 constructor,这个方法会被默认添加: class Demo{
constructor(x) {
this.x = x;
}
}
class Demo2 extends Demo{}
let d = new Demo2('hello');
d.x // hello 3、super 在静态方法之中指向父类,在普通方法之中指向父类的原型对象 class Parent {
static myMethod(msg) {
console.log('static', msg);
}
myMethod(msg) {
console.log('instance', msg);
}
}
class Child extends Parent {
static myMethod(msg) {
super.myMethod(msg);
}
myMethod(msg) {
super.myMethod(msg);
}
}
Child.myMethod(1); // static 1
var child = new Child();
child.myMethod(2); // instance 2 |
Promise.race()
const p = Promise.race([p1, p2, p3]); 上面代码中,只要 p1、p2、p3 之中有一个实例率先改变状态,p 的状态就跟着改变。那个率先改变的 Promise 实例的返回值,就传递给 p 的回调函数。 Promise.race 方法的参数与 Promise.all 方法一样,如果不是 Promise 实例,就会先调用Promise.resolve 方法,将参数转为 Promise 实例,再进一步处理。 下面是一个例子,如果指定时间内没有获得结果,就将 Promise 的状态变为 reject,否则变为 resolve,用于 timeout 实现。 const p = Promise.race([
fetch('/resource-that-may-take-a-while'),
new Promise(function (resolve, reject) {
setTimeout(() => reject(new Error('request timeout')), 5000)
})
]);
p
.then(console.log)
.catch(console.error); 上面代码中,如果 5 秒之内 fetch 方法无法返回结果,变量 p 的状态就会变为 rejected,从而触发 catch 方法指定的回调函数。 |
URL & URLSearchParams
var path = '/hello'
var url = new URL(path, 'http://api.com')
// url is as show as follows
// {
// hash: ""
// host: "api.com"
// hostname: "api.com"
// href: "http://api.com/hello"
// origin: "http://api.com"
// password: ""
// pathname: "/hello"
// port: ""
// protocol: "http:"
// search: ""
// searchParams: URLSearchParams {}
// username: ""
// }
console.log(url.toString())
// "http://api.com/hello"
if (searchParams) {
const url = new URL(this._input, document && document.baseURI);
if (typeof searchParams === 'string' || (URLSearchParams && searchParams instanceof URLSearchParams)) {
url.search = searchParams;
} else if (Object.values(searchParams).every(param => typeof param === 'number' || typeof param === 'string')) {
url.search = new URLSearchParams(searchParams).toString();
} else {
throw new Error('The `searchParams` option must be either a string, `URLSearchParams` instance or an object with string and number values');
}
this._input = url.toString(); |
Object.is() 和 === 不同之处只有两个:一是+0不等于-0,二是NaN等于自身。 +0 === -0 //true
NaN === NaN // false
Object.is(+0, -0) // false
Object.is(NaN, NaN) // true ES5 可以通过下面的代码,部署 Object.defineProperty(Object, 'is', {
value: function(x, y) {
if (x === y) {
// 针对+0 不等于 -0的情况
return x !== 0 || 1 / x === 1 / y;
}
// 针对NaN的情况
return x !== x && y !== y;
},
configurable: true,
enumerable: false,
writable: true
}); |
文件批量上传 async multipleUpload (toBeUploadList) {
let formData = new FormData()
toBeUploadList.forEach(t => {
formData.append('files', t.file, t.name)
})
try {
const res = await this.$post(`towerTasks/${this.$route.params.taskId}/batchUpload?fileKey=markov`, {
headers: null,
body: formData
})
if (res.code === 0) Message.success('马尔科夫文件上传成功')
} catch (error) {
Message.error('马尔科夫文件上传失败')
}
} |
TypeError: Invalid attempt to spread non-iterable instance 这个错误是和变量解构有关,于是定位到了代码 formatData () {
const { headers, items } = this.data
return [headers, ...items]
} this.data 初试值是 formatData () {
const { headers, items } = this.data
if (headers && items) return [headers, ...items]
return []
} |
对象循环引用 var a = { n: 1}
a.b = a; 这里 其实 其次的话,用递归也可以实现 function isCircular() {
let stack = []
return function fn(obj) {
let len = stack.length
for (; len--;) {
if (stack[len] === obj) {
throw new TypeError('There is circular structure')
}
}
stack.push(obj)
for (let k in obj) {
const value = obj[k]
if (typeof value === 'object') fn(value)
}
}
}
isCircular()(a) |
装箱转换每一种基本类型 Number、String、Boolean、Symbol 在对象中都有对应的类,所谓装箱转换,正是把基本类型转换为对应的对象,它是类型转换中一种相当重要的种类。 强制 Symbol 装箱: var normal = Symbol("aa");
var symbolObject = (function(){ return this; }).call(Symbol("a"));
console.log(typeof normal); //symbol
console.log(typeof symbolObject); //object
console.log(symbolObject instanceof Symbol); //true
console.log(symbolObject.constructor == Symbol); //true
// 当然,可以显式的调用装箱能力
var symbolObject2 = Object(Symbol('a')) Object.prototype.toString 是可以准确识别对象对应的基本类型的方法,它比 instanceof 更加准确。 拆箱转换即对象类型到基本类型的转换。 对象到 String 和 Number 的转换都遵循“先拆箱再转换”的规则。通过拆箱转换,把对象变成基本类型,再从基本类型转换为对应的 String 或者 Number。 拆箱转换会尝试调用 valueOf 和 toString 来获得拆箱后的基本类型。如果 valueOf 和 toString 都不存在,或者没有返回基本类型,则会产生类型错误 TypeError。 到 Number 的拆箱,会先调用 valueOf 再调用 toString,到 String 的拆箱,则相反。 ES6 允许对象显式指定 Sumbol.toPrimitive 覆盖原有行为: var o = {
valueOf : () => {console.log("valueOf"); return {}},
toString : () => {console.log("toString"); return {}}
}
o[Symbol.toPrimitive] = () => {console.log("toPrimitive"); return "hello"}
console.log(o + "")
// toPrimitive
// hello |
函数的 length 属性指定了默认值以后,函数的 (function (a) {}).length // 1
(function (a = 5) {}).length // 0
(function (a, b, c = 5) {}).length // 2 上面代码中, 这是因为 (function(...args) {}).length // 0 如果设置了默认值的参数不是尾参数,那么 (function (a = 0, b, c) {}).length // 0
(function (a, b = 1, c) {}).length // 1 |
js 从入门到继续学习
The text was updated successfully, but these errors were encountered: