js中的一些基础语法整理
this 指向
普通函数
const teacher = {
name: 'xiaoming',
getName: function() { return `${this.name}`
} }
console.log(teacher.getName());// xiaoming
普通函数谁调用,函数中this就指向谁,teacher调用getName,getName中的this指向teacher
箭头函数
const teacher = {
name: 'xiaoming',
getName: ()=> { return `${this.name}`
} }
console.log(teacher.getName());// undefined
箭头函数⾥的this是定义的时候决定的,定义的时候 getName的this指向的是window,window 没有name ,所以输出undefine
var name = '123'
const teacher = {
name: 'xiaoming',
getName: ()=> { return `${this.name}`
} }
console.log(teacher.getName());// 123
因此箭头函数不能用作构造函数,构造函数需要改变this的指向到新实例例出来的对象,this指向是定义的时候决定的
手写一个模版字符串的实现
const year ='2021'
const month = '04'
const day = '25'
let template = '${year}-${month}-${day}'
let context = {year,month,day}
const str = render(template)(context)
console.log(str)
function render (template){
return function (context){
return template.replace(/\$\{(.*?)\}/g,(match,key)=>{
return context[key]
})
}
}// 2021-04-25
结构原理
针对可迭代对象的Iterator接⼝口,通过遍历器器按顺序获取对应的值进⾏行行赋值.
Iterator是⼀一种接⼝口,为各种不不⼀一样的数据解构提供统⼀一的访问机制。任何数据解构只要有 Iterator接⼝口,就能通过遍历操作,依次按顺序处理理数据结构内所有成员。ES6中的for of的语 法相当于遍历器器,会在遍历数据结构时,⾃自动寻找Iterator接⼝口。
手写iterator
function generateiterator(array){
let nextIndex = 0
return {
next:()=>{
return nextIndex<array.length ? {value:array[nextIndex++],done:false}:{value:undefined,done:true}
}
}
}
const iterator = generateiterator([3,4,5])
console.log(iterator.next())
console.log(iterator.next())
console.log(iterator.next())
console.log(iterator.next())
/*
{ value: 3, done: false }
{ value: 4, done: false }
{ value: 5, done: false }
{ value: undefined, done: true }
*/
可迭代对象是什什么?
可迭代对象是Iterator接⼝口的实现。这是ECMAScript 2015的补充,它不不是内置或语法,⽽而仅 仅是协议。任何遵循该协议点对象都能成为可迭代对象。可迭代对象得有两个协议:可迭代协 议和迭代器器协议。
可迭代协议:对象必须实现iterator⽅方法。即对象或其原型链上必须有⼀一个名叫 Symbol.iterator的属性。该属性的值为⽆无参函数,函数返回迭代器器协
⾃己来实现一个可以for of遍历的对象
通过以上可知,自定义数据结构,只要拥有Iterator接口,并将其部署到⾃己的
Symbol.iterator属性上,就可以成为可迭代对象,能被for of循环遍历.
const obj={
count:0,
[Symbol.iterator]:()=>{
return {
next:()=>{
if(obj.count<10){
return {value:obj.count++,done:false}
}else{
return {value:undefined,done:true}
}
}
}
}
}
for (const item of obj){
console.log(item)
}
/*
0
1
2
3
4
5
6
7
8
9
*/
const iterable={
0:'a',
1:'b',
2:'c',
length:3,
[Symbol.iterator]:Array.prototype[Symbol.iterator]
};
for (const item of iterable){
console.log(item)
}
/*
a
b
c
*/
遍历
1.for in 与 for of
遍历数组时,key为数组下标字符串串;遍历对象,key为对象字段名。
缺点:
for in 不不仅会遍历当前对象,还包括原型链上的可枚举属性
for in 不不适合遍历数组,主要应⽤用为对象
for of 仅遍历当前对象
let obj = {a: 'test1', b: 'test2'}
Object.prototype.name='小明'
for (let key in obj) {
console.log(key, obj[key]) }
/*
a test1
b test2
name 小明
*/
let arr = [3,4,5,6,7]
Array.prototype.text = '123'
for (item in arr){
console.log(item) // 0 1 2 3 4 text
}
let arr = [3,4,5,6,7]
Array.prototype.text = '123'
for (item of arr){
console.log(item) // 3 4 5 6 7
}
for in 遍历的是数组索引
for of 遍历的是数组中内容
let arr = [3,4,5,6,7]
for (item in arr){
console.log(item) // 0 1 2 3 4
}
let arr = [3,4,5,6,7]
for (item of arr){
console.log(item) // 3,4,5,6,7
}
for of 可迭代对象(包括 Array,Map,Set,String,TypedArray,arguments对象,NodeList对 象)上创建⼀一个迭代循环,调⽤用⾃自定义迭代钩⼦子,并为每个不不同属性的值执⾏行行语句句。
let arr = [{ age: 1 }, { age: 5 }, { age: 100 }, { age: 34 }]
for (let { age } of arr) {
if (age > 10) {
break
}
console.log(age) // 1 5
}
手写object.keys
function getObjectKeys(obj){
const result = []
for (let key in obj){
if (obj.hasOwnProperty(key)){
result.push(key)
}
}
return result
}
console.log(getObjectKeys({
a:1,b:2
})) // [ 'a', 'b' ]
手写 object.values
function getObjectValues(obj){
const result = []
for (let key in obj){
if (obj.hasOwnProperty(key)){
result.push(obj[key])
}
}
return result
}
console.log(getObjectValues({
a:1,b:2
})) // [ 1, 2 ]
手写 object.entries
const result = []
for (let key in obj){
if (obj.hasOwnProperty(key)){
result.push([key,obj[key]])
}
}
return result
}
console.log(getObjectEntries({
a:1,b:2
})) // [ [ 'a', 1 ], [ 'b', 2 ] ]
Object.getOwnPropertyNames
该⽅方法返回一个数组,该数组对元素是 obj⾃自身拥有的枚举或不不可枚举属性名称字符串串。
Object.prototype.aa = '1111'
const testData={
a:1,
b:2
}
for (const key in testData){
console.log(key) // a b aa
}
console.log(Object.getOwnPropertyNames(testData)) // [ 'a', 'b' ]
Object.create()
Object.create()方法创建一个新的对象,并以方法的第一个参数作为新对象的proto属性的值 (根据已有的对象作为原型,创建新的对象。) Object.create()方法还有第二个可选参数,是一个对象,对象的每个属性都会作为新对象的自身属性,对象的属性值以descriptor(Object.getOwnPropertyDescriptor(obj, ‘key’))的形式 出现,且enumerable默认为false
const person ={
isHuman:false,
printIntroduction:function(){
console.log(`My name is ${this.name}. Am I human? ${this.isHuman}`)
}
}
const me = Object.create(person);
me.name='1234'
me.isHuman = true
me.printIntroduction() // My name is 1234. Am I human? true
console.log(person) // { isHuman: false, printIntroduction: [Function: printIntroduction] }
function Person(name,sex){
this.name = name;
this.sex = sex
}
const b = Object.create(Person.prototype,{
name:{
value:'coco',
writable:true,
configurable:true,
enumerable:true
},
sex:{
enumerable:true,
get:function(){
return 'hello sex'
},
set:function(val){
console.log('~~~~~~~~',this.sex)
console.log('set value'+val)
}
}
})
b.sex = '1233'
console.log(b.name)
console.log(b.sex)
/*
~~~~~~~~ hello sex
set value1233
coco
hello sex
*/
手写promiseAll
function PromiseAll(proArr){
return new Promise((resolve,reject)=>{
if (!Array.isArray(proArr)){
return reject(new TypeError('必须是一个数组'))
}else{
let count = 0 ,length = proArr.length,resolveArr = []
for (let i = 0;i<length;i++){
Promise.resolve(proArr[i]).then(value=>{
count++
resolveArr[i] = value
if (count === length){
return resolve(resolveArr)
}
}).catch(e=>reject(e))
}
}
})
}
function PromiseAll2(proArr){
// 第二种写法
return new Promise((resolve,reject)=>{
if (!Array.isArray(proArr)){
return reject(new TypeError('必须是一个数组'))
}else{
let count = 0 ,length = proArr.length,resolveArr = []
for (let i = 0;i<length;i++){
Promise.resolve(proArr[i]).then(value=>{
resolveArr[i] = value
}).catch(e=>reject(e)).finally(()=>{
count++
if (count === length){
return resolve(resolveArr)
}
})
}
}
})
}
const pro1 = new Promise((resolve,reject)=>{
setTimeout(()=>{
resolve(1)
},1000)
})
const pro2 = new Promise((resolve,reject)=>{
setTimeout(()=>{
resolve(2)
},2000)
})
const pro3 = new Promise((resolve,reject)=>{
setTimeout(()=>{
resolve(3)
},3000)
})
const proAll = PromiseAll([pro1,pro2,pro3]).then(res=>{
console.log(res)
}).catch((e)=>{
console.log(e)
})
手写promiseallsettled
function PromiseAllSettled(promiseArray){
return new Promise((resolve,reject)=>{
if(!Array.isArray(promiseArray)){
return reject(new TypeError('必须是一个数组'))
}
let counter = 0
const length = promiseArray.length
const reseloveArray = []
for(let i = 0;i<length;i++){
Promise.resolve(promiseArray[i]).then(value=>{
reseloveArray[i]={
status:'fulfilled',
value
}
}).catch(reason=>{
reseloveArray[i]={
status:'rejected',
reason
}
}).finally(()=>{
counter++
if(counter === length){
resolve(reseloveArray)
}
})
}
})
}
const pro1 = new Promise((resolve,reject)=>{
setTimeout(()=>{
resolve(1)
},1000)
})
const pro2 = new Promise((resolve,reject)=>{
setTimeout(()=>{
resolve(2)
},2000)
})
const pro3 = new Promise((resolve,reject)=>{
setTimeout(()=>{
resolve(3)
},3000)
})
const proAll = PromiseAllSettled([pro1,pro2,pro3]).then(res=>{
console.log(res)
}).catch((e)=>{
console.log(e)
})
/*
[
{ status: 'fulfilled', value: 1 },
{ status: 'fulfilled', value: 2 },
{ status: 'fulfilled', value: 3 }
]
*/
手写 flat 打平数组
const arr1 = [1,2,3,[1,2,3,4,[2,3,4,5,6,[7,9,10,12]]]]
function flatDeep(arr,d=1){
if(d>0){
return arr.reduce((res,val)=>{
if (Array.isArray(val)){
res = res.concat(flatDeep(val,d-1))
}else{
res = res.concat(val)
}
return res
},[])
}else{
return arr.slice()
}
}
console.log(flatDeep(arr1,Infinity))
// 没有深度
function faltten(array){
if(!Array.isArray(array)){
return new TypeError('必须是数组')
}
let length = array.length,resArr = []
for (let i = 0;i<length;i++){
if(Array.isArray(array[i])){
resArr = resArr.concat(faltten(array[i]))
}else{
resArr.push(array[i])
}
}
return resArr
}
console.log(faltten([1,2,3,4,[5,6,7,[8,9,10,[11]]]]))
// 如果数组元素都是Number类型
function flatten(arr) {
return arr.toString().split(',').map(item => Number(item))
}
console.log(flatten([1,2,3,4,[5,6,7,[8,9,10,[11]]]]))
function flatten(arr) {
while(arr.some(item=>Array.isArray(item))){
arr = [].concat(...arr)
}
return arr
}
console.log(flatten([1,2,3,4,[5,6,7,[8,9,10,[11]]]]))