Skip to content

前端手写编程常见面试题 #18

Open
@george-wq

Description

@george-wq

JavaScript深入之new的模拟实现

new 运算符创建一个用户定义的对象类型的实例或具有构造函数的内置对象类型之一

new操作符做了这些事:

它创建了一个全新的对象
它会被执行[[Prototype]](也就是__proto__)链接
它使this指向新创建的对象
通过new创建的每个对象将最终被[[Prototype]]链接到这个函数的prototype对象上
如果函数没有返回对象类型Object(包含Functoin, Array, Date, RegExg, Error),那么new表达式中的函数调用将返回该对象引用

function objectFactory() {
    var obj = new Object(),
    Constructor = [].shift.call(arguments);
    obj.__proto__ = Constructor.prototype;
    var ret = Constructor.apply(obj, arguments);
    return typeof ret === 'object' ? ret : obj;
};

参考: mqyqingfeng/Blog#13

JavaScript深入之call和apply的模拟实现

call() 方法在使用一个指定的 this 值和若干个指定的参数值的前提下调用某个函数或方法。

Function.prototype.call2 = function (context) {
    var context = context || window;
    context.fn = this;

    var args = [];
    for(var i = 1, len = arguments.length; i < len; i++) {
        args.push('arguments[' + i + ']');
    }

    var result = eval('context.fn(' + args +')');

    delete context.fn
    return result;
}
// apply
Function.prototype.apply = function (context, arr) {
    var context = Object(context) || window;
    context.fn = this;

    var result;
    if (!arr) {
        result = context.fn();
    }
    else {
        var args = [];
        for (var i = 0, len = arr.length; i < len; i++) {
            args.push('arr[' + i + ']');
        }
        result = eval('context.fn(' + args + ')')
    }

    delete context.fn
    return result;
}

参考:mqyqingfeng/Blog#11

JavaScript深入之bind的模拟实现

一句话介绍 bind:

bind() 方法会创建一个新函数。当这个新函数被调用时,bind() 的第一个参数将作为它运行时的 this,之后的一序列参数将会在传递的实参前传入作为它的参数。(来自于 MDN )

Function.prototype.bind2 = function (context) {
    if (typeof this !== "function") {
      throw new Error("Function.prototype.bind - what is trying to be bound is not callable");
    }

    var self = this;
    var args = Array.prototype.slice.call(arguments, 1);

    var fNOP = function () {};

    var fBound = function () {
        var bindArgs = Array.prototype.slice.call(arguments);
        return self.apply(this instanceof fNOP ? this : context, args.concat(bindArgs));
    }

    fNOP.prototype = this.prototype;
    fBound.prototype = new fNOP();
    return fBound;
}

参考: mqyqingfeng/Blog#12

防抖 & 节流

function debounce(fuc, wait) {
  let timeout = null;
  return function() {
	clearTimeout(timeout);
	timeout = setTimeout(function() {
	  func.apply(this, arguments);
	}, wait)
  }
}
function throttle(func, wait) {
  var pre = 0;
  var timeout = null;
  return function() {
	if (!timeout) {
	  timeout = setTimeout(function() {
		func.apply(this, arguments);
		timeout = null;
	  }, wait);
	}
  }
}

参考:mqyqingfeng/Blog#22
mqyqingfeng/Blog#26

深浅拷贝

浅拷贝:

var shallowCopy = function(obj) {
  // 只拷贝对象
  if (typeof obj !== 'object') return;
  // 根据obj的类型判断是新建一个数组还是对象
  var newObj = obj instanceof Array ? [] : {};
  // 遍历obj,并且判断是obj的属性才拷贝
  for (var key in obj) {
      if (obj.hasOwnProperty(key)) {
          newObj[key] = obj[key];
      }
  }
  return newObj;
}

深拷贝

var deepCopy = function(obj) {
  if (typeof obj !== 'object') return;
  var newObj = obj instanceof Array ? [] : {};
  for (var key in obj) {
      if (obj.hasOwnProperty(key)) {
          newObj[key] = typeof obj[key] === 'object' ? deepCopy(obj[key]) : obj[key];
      }
  }
  return newObj;
}

参考: mqyqingfeng/Blog#32

手写Promise

参考: https://juejin.im/post/6844904094079926286#heading-0

手写数组去重、扁平化函数

  1. flat
  2. reduce
function flattenDeep(arr) { 
  return Array.isArray(arr)
    ? arr.reduce( (acc, cur) => [...acc, ...flattenDeep(cur)] , [])
    : [arr]
}
  1. 模拟栈结构
function flattenDeep(arr) {
  const result = [] 
  // 将数组元素拷贝至栈,直接赋值会改变原数组
  const stack = [...arr]
  // 如果栈不为空,则循环遍历
  while (stack.length !== 0) {
    const val = stack.pop() 
    if (Array.isArray(val)) {
      // 如果是数组再次入栈,并且展开了一层
      stack.push(...val) 
    } else {
      // 如果不是数组,就用头插法插入到结果数组中
      result.unshift(val)
    }
  }
  return result
}

数组去重
方式一:Set(ES6)

方式二:reduce

function unique (arr) {
  return arr.sort().reduce((acc, cur) => {
    if (acc.length === 0 || acc[acc.length - 1] !== cur) {
        acc.push(cur);
    }
    return acc
}, [])}

方法三:filter

function unique(arr) {
  return arr.filter( (element, index, array) => {
    return array.indexOf(element) === index
})
}

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions