js中的一些基础语法整理

2021-04-26  本文已影响0人  南枫小谨

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]]]]))
上一篇 下一篇

猜你喜欢

热点阅读