前端知识点——常见手撕题

目录

一、解析URL

二、功能函数实现

1、防抖和节流

(1)防抖

(2)节流

2、函数柯里化

(1) 

(2)

3、setTimeout实现setInterval

三、字符串

1、清除字符串前后空格

(1) .replace()

(2) 循环

2、驼峰命名

四、数组

1、 数组拍平

(1)、递归法

(2)、toString & split

(3)、join & split

2、数组去重

3、根据属性,对象数组去重

4、数组乱序

五、浅拷贝、深拷贝

1、浅拷贝

2、深拷贝 

六、bind,apply,call

1、bind函数

2、apply函数

 3、call函数

 七、实现原生API

1、实现new

2、实现create()

3、instanceof实现

4、实现reduce()

5、实现forEach

6、用reduce实现map

7、实现indexOf

8、实现Object.assign()

八、图片懒加载

九、实现一个简单路由

1、hash路由

2、history路由

十、 发布订阅模式(event bus)

十一、HTTP请求

1、jsonp

2、实现AJAX

(1)简易版

(2)promise实现版

十二、Promise系列

1、promise

2、promise.all

3、promise.race

4、promise经典题

十三、链表

1、单链表

2、双向链表

十四、数据双向绑定

(1)vue2.0

(2)proxy双向数据绑定

十五、判断两个对象是否相等

十六、判断一个对象是空对象

十七、实现函数判断类型的函数

十八、数据绑定基本实现

十九、有一个祖先树状 json 对象,当一个人有一个儿子的时候,其 child 为其儿子对象,如果有多个儿子,child 为儿子对象的数组。

二十、js继承




一、解析URL

 

二、功能函数实现

1、防抖和节流

(1)防抖

频繁操作时,只执行最后一次

前端知识点——常见手撕题_第1张图片

(2)节流

频繁操作时,只有在一定时间内执行一次


    

2、函数柯里化

(1) 

前端知识点——常见手撕题_第2张图片

(2)

前端知识点——常见手撕题_第3张图片

(3)

3、setTimeout实现setInterval

三、字符串

1、清除字符串前后空格

(1) .replace()

前端知识点——常见手撕题_第4张图片

(2) 循环

//(2)
function myTrim(str) {//记录前后空格的个数,最后对字符串进行截取
	let first=0,last=str.length
	for (let i in str) {
		if (str[i]===' ') {
			first++
		} else {
			break
		}
	}
	for (let i=last;i>first;i--) {
		if (str[i]===' ') {
			last--
		} else {
			break
		}
	}
	return str.substr(first,last-first)
}

2、驼峰命名

var s1 = "get-element-by-id"

// 转化为 getElementById

var f = function(s) {
    return s.replace(/-\w/g, function(x) {
        return x.slice(1).toUpperCase();
    })
}

四、数组

1、 数组拍平

(1)、递归法

前端知识点——常见手撕题_第5张图片

(2)、toString & split

(3)、join & split


        function flatten(res) {
            // join 把数组中的所有元素转换为一个字符串
            // split 会将 string 中按照括号里的内容进行分割并存入一个新数组,返回数组
            // map 会对数组中的所有数据按照函数进行处理后返回一个处理后的数组
            return res.join().split(',').map((item) => {
                return parseInt(item)
            })
        }

2、数组去重

3、根据属性,对象数组去重

const responseList = [
  { id: 1, a: 1 },
  { id: 2, a: 2 },
  { id: 3, a: 3 },
  { id: 1, a: 4 },
];
const result = responseList.reduce((acc, cur) => {
    const ids = acc.map(item => item.id);
    return ids.includes(cur.id) ? acc : [...acc, cur];
}, []);
console.log(result); // -> [ { id: 1, a: 1}, {id: 2, a: 2}, {id: 3, a: 3} ]

4、数组乱序

// 著名的Fisher–Yates shuffle 洗牌算法
function shuffle(arr){
    let m = arr.length;
    while(m > 1){
        let index = parseInt(Math.random() * m--);
        [arr[index],arr[m]] = [arr[m],arr[index]];  //解构赋值
    }
    return arr;
}

五、浅拷贝、深拷贝

1、浅拷贝

// 1. ...实现
let copy1 = {...{x:1}}

// 2. Object.assign实现
let copy2 = Object.assign({}, {x:1})

2、深拷贝 

六、bind,apply,call

1、bind函数

前端知识点——常见手撕题_第6张图片

2、apply函数

前端知识点——常见手撕题_第7张图片

 3、call函数

前端知识点——常见手撕题_第8张图片

 七、实现原生API

1、实现new

3、instanceof实现

4、实现reduce()

    

5、实现forEach

6、用reduce实现map

7、实现indexOf

8、实现Object.assign()

   

八、图片懒加载

前端知识点——常见手撕题_第9张图片

九、实现一个简单路由

1、hash路由


    
    

2、history路由


  
  

十、 发布订阅模式(event bus)

十一、HTTP请求

1、jsonp

 

2、实现AJAX

(1)简易版

 //get请求
        let xhr = new XMLHttpRequest()
        xhr.open('GET',url,true)
        xhr.onreadystatechange = function(){
            if(xhr.readystate === 4){
                if(xhr.status >= 200 && xhr.status < 300){
                    console.log(xhr.resopnseText);
                }
            }
        }
        xhr.send(null)

        //post请求
        let xhr = new XLMHttpRequest()
        xhr.open('POST',url,true)
        xhr.onreadystatechange = function(){
            if(xhr.readystate === 4){
                if(xhr.status >= 200 && xhr.status < 300){
                    console.log(xhr.responseText);
                }
            }
        }
        xhr.setRequestHeader('Content-Type','application/x-www-form-urlencoded;charset=UTF-8')
        xhr.send(data)

(2)promise实现版

十二、Promise系列

1、promise

    



如上代码可以说明p1.then()的结果是一个与p1不同的promise对象。

 

换句话说,then()会封装一个全新的promise对象p2。那既然 p2也是一个promise对象,那么,p2的状态(promiseStatus)和值(promiseValue)分别是什么?

 

规则如下:

如果p1的状态是pending,则p2的状态也是pending。

•如果p1的状态是resolved,then()会去执行f_ok,则p2的状态由f_ok的返回值决定。

•如果f_ok返回值不是promise对象,则p2的状态是resolved,且p2的promiseValue就是f_ok函数的return值。•如果f_ok返回值是一个promise对象,则p2的状态及promiseValue以这个promise对象为准。•如果f_ok这个函数内部发生了错误(或者是用户主动抛出错误),则p2的状态是rejected,且p2的promiseValue就是这个错误对象。

如果p1的状态是rejected,then()会去执行f_err,则p2的状态由f_err的返回值决定。

•如果f_err返回值不是promise对象,则p2的状态是resolved,且p2的promiseValue就是f_err函数的return值。•如果f_err返回值是一个promise对象,则p2的状态及promiseValue以这个promise对象为准。

•如果f_err这个函数内部发生了错误(或者是用户主动抛出错误),则p2的状态是rejected,且p2的promiseValue就是这个错误对象。

2、promise.all

    

3、promise.race

4、promise经典题

setTimeout(() => {
            console.log(0); //9
        }, 0);
        new Promise((resolve, reject) => {
            console.log(1); // 1
            resolve()
        }).then(() => {
            console.log(2); //3
            new Promise((resolve, reject) => {
                console.log(3); //4
                resolve()
            }).then(() => {
                console.log(4); //6
            }).then(() => {
                console.log(5); //8
            })
        }).then(() => {
            console.log(6); //7
        })
        new Promise((resolve, reject) => {
                console.log(7); //2
                resolve()
            }).then(() => {
                console.log(8); //5
            })
            // 1 7 2 3 8 4 6 5 0

// then() 里面放入的是函数就会放进队列中等待执行,下一个then中的内容,得等上一个then中状态转变才会放入队列中

    

十三、链表

1、单链表

    

2、双向链表

    

十四、数据双向绑定

(1)vue2.0


    

(2)proxy双向数据绑定


    
    
    

十五、判断两个对象是否相等

 

十六、判断一个对象是空对象

 

十七、实现函数判断类型的函数

function getType(obj) {
   if (obj === null) return String(obj);
   return typeof obj === 'object' 
   ? Object.prototype.toString.call(obj).replace('[object ', '').replace(']', '').toLowerCase()
   : typeof obj;
}

// 调用
getType(null); // -> null
getType(undefined); // -> undefined
getType({}); // -> object
getType([]); // -> array
getType(123); // -> number
getType(true); // -> boolean
getType('123'); // -> string
getType(/123/); // -> regexp
getType(new Date()); // -> date

十八、数据绑定基本实现

题目:
// 实现一个方法,可以给 obj 所有的属性添加动态绑定事件,当属性值发生变化时会触发事件
let obj = {
  key_1: 1,
  key_2: 2
}
function func(key) {
  console.log(key + ' 的值发生改变:' + this[key]);
}
bindData(obj, func);
obj.key_1 = 2; // 此时自动输出 "key_1 的值发生改变:2"
obj.key_2 = 1; // 此时自动输出 "key_2 的值发生改变:1"

答:
function bindData(obj, fn) {
  for (let key in obj) {
    Object.defineProperty(obj, key, {
      set(newVal) {
        if (this.value !== newVal) {
          this.value = newVal;
          fn.call(obj, key);
        }
      },
      get() {
        return this.value;
      }
    })
  }
}

十九、有一个祖先树状 json 对象,当一个人有一个儿子的时候,其 child 为其儿子对象,如果有多个儿子,child 为儿子对象的数组。

请实现一个函数,找出这个家族中所有有多个儿子的人的名字(name),输出一个数组。

// 样例数据
let data = {
  name: 'jack',
  child: [
    { name: 'jack1' },
    {
      name: 'jack2',
      child: [{
        name: 'jack2-1',
        child: { name: 'jack2-1-1' }
      }, {
        name: 'jack2-2'
      }]
    },
    {
      name: 'jack3',
      child: { name: 'jack3-1' }
    }
  ]
}

答:
function findMultiChildPerson(data) {
  let nameList = [];

  function tmp(data) {
    if (data.hasOwnProperty('child')) {
      if (Array.isArray(data.child)) {
        nameList.push(data.name);
        data.child.forEach(child => tmp(child));
      } else {
        tmp(data.child);
      }
    }
  }
  tmp(data);
  return nameList;
}

二十、js继承

你可能感兴趣的:(前端学习笔记,前端,javascript,面试)