Instanceof 手写 *


判断一个实例是否是其父类或者祖先类型的实例。
instanceof 在查找的过程中会遍历左边变量的原型链,直到找到右边变量的prototype查找失败,返回false。

  1. let myInstanceof = (target,origin) => {
  2. while(target){
  3. if(target.__proto__ === origin.prototype){
  4. return true
  5. }
  6. target = target.__proto__
  7. }
  8. return false
  9. }

数组的map方法 *

数组的map()方法会返回一个新的数组,这个新的数组中的每个元素对应原数组中 的 对应位置 元素 调用一次 提供的函数后 的 返回值。
**

  1. //用法
  2. const a = [1, 2, 3, 4]
  3. const b = array1.map(x => x * 2)
  4. console.log(b) // [2,4,6,8]

map方法有两个参数,一个是操作数组元素的方法fn,一个是this指向,其中使用fn时可以获取三个参数。
**

  1. //原生实现
  2. Array.prototype.myMap = function(fn, thisValue) {
  3. let res = []
  4. thisValue = thisValue || []
  5. let arr = this
  6. for(let i = 0;i < arr.length;i ++){
  7. res.push(fn.call(thisValue,arr[i],i,arr)) //参数分别为this指向,当前数组项,当前索引,当前数组
  8. }
  9. return res
  10. }
  11. //实现
  12. const a = [1, 2, 3]
  13. const b = a.myMap((a, index) => {
  14. console.log(`索引${index}的值为`,a + 1)
  15. return a + 1
  16. }
  17. )
  18. console.log(b) // 2, 3, 4

reduce实现数组的map方法 *

利用数组内置的reduce方法实现map方法,考察对reduce原理的掌握。

  1. Array.prototype.myMap = function(fn,thisValue){
  2. var res = [];
  3. thisValue = thisValue||[];
  4. this.reduce(function(pre,cur,index,arr){
  5. return res.push(fn.call(thisValue,cur,index,arr));
  6. },[]);
  7. return res;
  8. }
  9. var arr = [2,3,1,5];
  10. arr.myMap(function(item,index,arr){
  11. console.log(item,index,arr);
  12. }
  13. )

手写数组的reduce方法 *

reduce方法接受一个函数作为累加器,数组中的每个值(从左到右)开始缩减,最终为一个值,是ES5中新增的又一个数组逐项处理方法。

参数:**

  • callback(一个在数组中每一项上调用的函数,接受四个函数:)
    • previousValue(上一次调用回调函数时的返回值,或者初始值)
    • currentValue(当前正在处理的数组元素)
    • currentIndex(当前正在处理的数组元素下标)
    • array(调用reduce()方法的数组)
  • initialValue(可选的初始值。作为第一次调用回调函数时传给previousValue的值)

**

  1. function reduce(arr, cb, initalValue) {
  2. var num = initalValue == undefined ? num = arr[0] : initalValue
  3. var i = initalValue == undefined ? 1 : 0
  4. for(i; i < arr.length;i ++){
  5. num = cb(num,arr[i],i)
  6. }
  7. return num
  8. }
  9. function fn(result, currentValue, index){
  10. return result + currentValue
  11. }
  12. var arr = [2, 3, 4, 5]
  13. var b = reduce(arr, fn, 10)
  14. var c = reduce(arr, fn)
  15. console.log(b) //24

数组扁平化

数组扁平化就是把多维数组转化为一维数组
**

1、ES6提供的新方法 flat(depth)

  1. let a = [1,[2,3]]
  2. a.flat()

2、利用concat

  1. function flatten(arr) {
  2. var res = [];
  3. for (let i = 0, length = arr.length; i < length; i++) {
  4. if (Array.isArray(arr[i])) {
  5. res = res.concat(flatten(arr[i])); //concat 并不会改变原数组
  6. //res.push(...flatten(arr[i])); //或者用扩展运算符
  7. } else {
  8. res.push(arr[i]);
  9. }
  10. }
  11. return res;
  12. }
  13. let arr1 = [1, 2,[3,1],[2,3,4,[2,3,4]]]
  14. flatten(arr1); //[1, 2, 3, 1, 2, 3, 4, 2, 3, 4]

3、函数柯里化

柯里化定义: 接受一部分参数,返回一个函数接受剩余参数,接受足够参数后,执行原函数。
当柯里化函数接收到足够参数之后,就会执行原函数,如何去确定何时达到足够的参数有两种思路。
1、 通过函数的length属性,获取函数的形参个数,形参的个数就是所需的参数个数。
2、在调用柯里化工具函数时,手动指定所需的参数个数。

  1. /**
  2. * 将函数柯里化
  3. * @param fn 待柯里化的原函数
  4. * @param len 所需的参数个数,默认为原函数的形参个数
  5. */
  6. function curry(fn,len = fn.length) {
  7. return _curry.call(this,fn,len)
  8. }
  9. /**
  10. * 中转函数
  11. * @param fn 待柯里化的原函数
  12. * @param len 所需的参数个数
  13. * @param args 已接收的参数列表
  14. */
  15. function _curry(fn,len,...args) {
  16. return function (...params) {
  17. let _args = [...args,...params];
  18. if(_args.length >= len){
  19. return fn.apply(this,_args);
  20. }else{
  21. return _curry.call(this,fn,len,..._args)
  22. }
  23. }
  24. }
  25. let _fn = curry(function(a,b,c,d,e){
  26. console.log(a,b,c,d,e)
  27. });
  28. _fn(1,2,3,4,5); // print: 1,2,3,4,5
  29. _fn(1)(2)(3,4,5); // print: 1,2,3,4,5
  30. _fn(1,2)(3,4)(5); // print: 1,2,3,4,5
  31. _fn(1)(2)(3)(4)(5); // print: 1,2,3,4,5

**

实现深拷贝

深拷贝和浅拷贝是只针对Object和Array这样的引用数据类型。

浅拷贝和深拷贝的区别:**

浅拷贝: 只拷贝引用,新旧对象仍共享同一份地址,修改新对象会影响到旧对象
深拷贝: 拷贝引用和内存地址,修改新对象不影响旧对象。
**

1、转化为Json格式然后再解析

  1. const a = JSON.parse(JSON.stringify(b))

2、

  1. //递归实现深拷贝
  2. function deepCopy(newObj,oldObj){
  3. for(var k in oldObj){
  4. let item = oldObj[k]
  5. // 判断是数组、对象、简单类型
  6. if(item instanceof Array){
  7. newObj[k] = []
  8. deepCopy(newObj[k],item)
  9. }else if(item instanceof Object){
  10. newObj[k] = {}
  11. deepCopy(newObj[k],item)
  12. }else{
  13. newObj[k] = item
  14. }
  15. }
  16. return newObj
  17. }

**

手写call、apply、bind

手写call

  1. Function.prototype.myCall=function(context=window){ // 函数的方法,所以写在Fuction原型对象上
  2. if(typeof this !=="function"){ // 这里if其实没必要,会自动抛出错误
  3. throw new Error("不是函数")
  4. }
  5. const obj=context||window //这里可用ES6方法,为参数添加默认值,js严格模式全局作用域this为undefined
  6. obj.fn=this //this为调用的上下文,this此处为函数,将这个函数作为obj的方法
  7. const arg=[...arguments].slice(1) //第一个为obj所以删除,伪数组转为数组
  8. res=obj.fn(...arg)
  9. delete obj.fn // 不删除会导致context属性越来越多
  10. return res
  11. }
  12. //用法:f.call(obj,arg1)
  13. function f(a,b){
  14. console.log(a+b)
  15. console.log(this.name)
  16. }
  17. let obj={
  18. name:1
  19. }
  20. f.myCall(obj,1,2) //否则this指向window
  21. obj.greet.call({name: 'Spike'}) //打出来的是 Spike

**

手写apply

  1. Function.prototype.myApply=function(context){ // 箭头函数从不具有参数对象!!!!!这里不能写成箭头函数
  2. let obj=context||window
  3. obj.fn=this
  4. const arg=arguments[1]||[] //若有参数,得到的是数组
  5. let res=obj.fn(...arg)
  6. delete obj.fn
  7. return res
  8. }
  9. function f(a,b){
  10. console.log(a,b)
  11. console.log(this.name)
  12. }
  13. let obj={
  14. name:'张三'
  15. }
  16. f.myApply(obj,[1,2]) //arguments[1]

手写bind

  1. this.value = 2
  2. var foo = {
  3. value: 1
  4. };
  5. var bar = function(name, age, school){
  6. console.log(name) // 'An'
  7. console.log(age) // 22
  8. console.log(school) // '家里蹲大学'
  9. }
  10. var result = bar.bind(foo, 'An') //预置了部分参数'An'
  11. result(22, '家里蹲大学') //这个参数会和预置的参数合并到一起放入bar中

手动实现new

  1. 创建一个空对象 obj;
  2. 将空对象的隐式原型(proto)指向构造函数的prototype。
  3. 使用 call 改变 this 的指向
  4. 如果无返回值或者返回一个非对象值,则将 obj 返回作为新对象;如果返回值是一个新对象的话那么直接直接返回该对象。
  1. function Person(name,age){
  2. this.name=name
  3. this.age=age
  4. }
  5. Person.prototype.sayHi=function(){
  6. console.log('Hi!我是'+this.name)
  7. }
  8. let p1=new Person('张三',18)
  9. ////手动实现new
  10. function create(){
  11. let obj={}
  12. //获取构造函数
  13. let fn=[].shift.call(arguments) //将arguments对象提出来转化为数组,arguments并不是数组而是对象 !!!这种方法删除了arguments数组的第一个元素,!!这里的空数组里面填不填元素都没关系,不影响arguments的结果 或者let arg = [].slice.call(arguments,1)
  14. obj.__proto__=fn.prototype
  15. let res=fn.apply(obj,arguments) //改变this指向,为实例添加方法和属性
  16. //确保返回的是一个对象(万一fn不是构造函数)
  17. return typeof res==='object'?res:obj
  18. }
  19. let p2=create(Person,'李四',19)
  20. p2.sayHi()
  21. [].shift.call(arguments) 也可写成:
  22. let arg=[...arguments]
  23. let fn=arg.shift() //使得arguments能调用数组方法,第一个参数为构造函数
  24. obj.__proto__=fn.prototype
  25. //改变this指向,为实例添加方法和属性
  26. let res=fn.apply(obj,arg)

https://segmentfault.com/a/1190000038910420