更多详细代码见:Github
手写深拷贝
- 我首先想到的就是
JSON.parse(JSON.stringify());
但是他有一些问题
- 无法解决循环引用的问题
- 无法拷贝一些特殊的对象,诸如 RegExp, Date, Set, Map等
- 无法拷贝函数(划重点)。
面试够用版本
function deepClone(obj){
if(typeof obj !== 'object' || obj === null){
return obj
}
let copy = {}
if (obj.constructor === Array){
copy = []
}
for( let key of obj){
if(obj.hasOwnProperty(key)){
obj[key] = deepClone(obj[key])
}
}
return copy
}
手写new
过程
- 创建了一个全新的对象
- 将创建的新对象的proto 指向 构造函数的原型prototype
- 执行构造函数,并通过call,apply改变this的指向
- 确保返回的是一个对象。返回值为Object类型则作为new方法的返回值返回。否则返回上述全新的对象
function myNew(fn, ...args) {
let instance = Object.create(fn.prototype);
let res = fn.apply(instance, args); // 改变this指向
// 确保返回的是一个对象(万一fn不是构造函数)
return typeof res === 'object' ? res: instance;
}
实现一个call
- 将函数作为对象的参数
- 执行&删除这个函数
- 指定this到函数并传入给定参数执行函数
- 如果不传入参数,默认指向window
Function.prototype.myCall = function(context = window, ...args){
let key = Symbol('key')
context[key] = this
let result = context[key](...args)
delete context[key]
return result
}
function f(a,b){
console.log(a+b)
console.log(this.name)
}
let obj={
name:1
}
f.myCall(obj,1,2) //否则this指向window
// 理解了,相当于this函数是在context的内部执行的。所以this自然而然地就继承了
实现一个apply
- 传入的参数为数组
Function.prototype.myApply = function(context = window , ...args){
let key = Symbol('key')
context[key] = this
let result = context[key](args)
delete context[key]
return result
}
function f(a,b){
console.log(a,b)
console.log(this.name)
}
let obj={
name:'张三'
}
f.myApply(obj,[1,2]) //arguments[1]
实现一个bind
-
bind返回了一个函数。可以有两种调用地方式。一种是直接调用。一种是通过 new 的方式,我们先来说直接调用的方式
-
对于直接调用来说,这里选择了 apply 的方式实现,但是对于参数需要注意以下情况:因为 bind 可以实现类似这样的代码 f.bind(obj, 1)(2),所以我们需要将两边的参数拼接起来
-
最后来说通过 new 的方式,对于 new 的情况来说,不会被任何方式改变 this,所以对于这种情况我们需要忽略传入的 this
Function.prototype.myBind = function (context, ...outerArgs) {
let self = this
return function F(...innerArgs){
if(self instanceof F){
return new self(...outerArgs,...innerArgs)
}
return self.apply(context,[...outerArgs,...innerArgs])
}
}
function f(a,b){
console.log(a+b)
console.log(this.name)
}
let obj={
name:1
}
// f.myCall(obj,1,2)
f.myBind(obj, 1)(2)
Object.create
Object.create()方法创建一个新对象,使用现有的对象来提供新创建的对象的 proto
function create(proto) {
function F() {}
F.prototype = proto;
return new F();
}
实现继承的那些事
最推荐
function Parent5 () {
this.name = 'parent5';
this.play = [1, 2, 3];
}
function Child5(){
Parent5.call(this)
this.type = 'woi'
}
Child5.prototype = Object.create(Parent5.prototype)
Child5.prototype.constructor = Child5
console.log(new Child5())
JSON.parse JSON.stringfy
正则匹配
必需 (总是学不会)
对象的扁平化
重点 add(1)(2)(3)
网上也找了一些代码示例,写得什么玩意呀
结果正确版本
// console.log(add(1)(2)(3)(4, 5)())
function addCurry(...args){return args.reduce((a,b)=> {
return a+b
}
)}
function currying(fn){
let args=[]
return function temp(...newArgs){
if(newArgs.length){
args = [...args, ...newArgs]
return temp
} else {
let val = fn.apply(this, args)
args = []
return val
}
}
}
let add = currying(addCurry)
console.log(add(1)(2)(3)(4, 5)())
console.log(add(1)(2)(3, 4, 5)())
console.log(add(1)(2, 3, 4, 5)())
但还是有一点问题 最后的 () 没有去掉。 有大哥能解决吗?
实现一个JS函数得柯里化
柯里化的定义:接收一部分参数,返回一个函数接收剩余参数,接收足够参数后,执行原函数
核心思路:通过函数的 length 属性,获取函数的形参个数,形参的个数就是所需的参数个数
function curry(fn,myargs){
// console.log(fn)
// console.log(fn.length)
var length = fn.length
var myargs = myargs || []
return function(...args){
newArgs = myargs.concat(args)
console.log(newArgs)
if (newArgs.length < length){
return curry.call(this,fn,newArgs)
}else{
return fn.apply(this,newArgs)
}
}
}
function multiFn(a, b, c) {
return a * b * c;
}
var multi = curry(multiFn);
console.log(multi(2)(3)(4))
// multi(2,3,4);
// multi(2)(3,4);
// multi(2,3)(4)
快速排序
核心就是利用递归得思想。从数组中取一个值,遍历后大的放值的右栈,小的放在左栈。而后对左右栈执行相同的操作
function quickSort(args){
let length = args.length
if (length<=1) {
return args
}
let mid = Math.floor(length/2)
let midVal = args[mid]
let left = []
let right = []
for(let i = 0 ; i < length ; i++){
if( i === mid ){
continue
}
if (args[i] <= midVal){
left.push(args[i])
}else{
right.push(args[i])
}
}
return quickSort(left).concat([midVal]).concat(quickSort(right))
}
console.log(quickSort([2,3,1,6]))