Skip to content

原生js,call,apply,bind的区别以及实际应用场景是什么

js的this指向只有在运行时才能确定,一般都是.前面的对象,但是有时候代码需要手动的改变this指向,会有两种情况

  1. 改变this指向,函数立即执行
  2. 改变this指向,函数稍后执行

立即执行可以使用 call、apply

稍后执行可以使用bind

call、apply的第一个参数都是函数调用的this指向,apply第二个参数是数组,call是一个一个传参

bind比较特殊,会返回一个绑定过this的绑定函数

  1. 调用bind的时候第一个参数是this,后面可以传多个参数
  2. 执行绑定函数的时候还可以继续传参,新传的参数会跟之前绑定的参数合并
  3. 绑定函数的返回值,与原先函数的返回值一样
  4. 绑定函数可以使用new声明实例对象,效果就跟new 之前的构造函数一样 不过绑定的this会失效

手写一个call

js
Function.prototype.mycall = function (context, ...args) {
	context = context || window
	
	const key = Symbol()
	context[key] = this

	const x = context[key](...args)

	delete context[key]

	return x
}

手写一个apply

js
Function.prototype.myapply = function (context, args) {
	context = context || window
	args = args || []

	const key = Symbol()
	context[key] = this

	const x = context[key](...args)

	delete context[key]

	return x
}

手写一个bind

js
Function.prototype.mybind = function (context, ...args) {
	context = context || window
	const fn = this

	const bindFn = function (...args2) {
		const newArgs = [...args, ...args2]

		if (new.target !== undefined) {
			// 说明在new 绑定函数 忽略绑定的 context
			context = this
		}

		const x = fn.apply(context, newArgs)
		return x
	}

	/* 绑定函数使用new时 需要考虑原型链 使用寄生组合继承 */
	let TempFn = function () {}
	TempFn.prototype = fn.prototype
	bindFn.prototype = new TempFn()
	bindFn.prototype.constructor = fn

	return bindFn
}

Math.max如何实现传入数组的形式去对比最大值

两种方式

  1. 使用扩展运算符 Math.max(...[1, 2, 3])
  2. 使用apply Math.max.apply(null, [1, 2, 3])

promise为什么可以then,为什么可以实现链式调用,以及说一下如果自己封装promise的思路

promise是一个类,上面有个then方法,每次执行.then都会返回一个新的promise,所以可以链式调用。

js是单线程语言,为了避免阻塞主线程,js设计了异步函数,可以将大量的操作放在异步函数中执行,避免阻塞主线程。

但是处理复杂逻辑时,回调函数的嵌套层级过深时,会导致回调地狱,使得代码难以维护。

promise的出现就是为了解决这个问题。它有下面几个优势

  1. 解决了回调地狱问题
  2. 很方便处理代码错误:使用 .catch
  3. 提高了代码可读性可维护性

自己设计一个Promise 思路

  1. Promise使用 new 所以设计成一个类

  2. 有三种状态 pending fulfilled rejected

  3. 实例属性 有 value reason status fulfilled_callback_list rejected_callback_list

  4. resolve 干了两件事 设置value 更改状态为 fulfilled

  5. reject 干了两件事 设置reason 更改状态为 rejected

    status一改变 遍历回调数组 执行数组里收集的方法

  6. then 方法

    接收两个回调参数 onFulfilled onRejected

    返回的一个新的 Promise

    是微任务 讲 onFulfilled onRejected 两个函数使用queueMicrotask函数包裹下

    判断当前状态 状态为pending时,将 onFulfilled onRejected 保存到等待执行数组

    状态为fulfilled时,执行onFulfilled 回调

    状态为rejected时,执行 onRejected 回调

  7. 链式调用then方法的返回值会传递给下一个Promise中,创建解析函数 递归解析then的返回值

  8. resolvePromise(promise2, x, resolve, reject)

    promise2是上一个then创建的新的Promise

    x是上一个then方法的返回值

    resolve reject 是新Promise的resolve和reject

    如果 x 是 Promise,执行 x.then 继续递归解析

    如果 x 是 null,直接返回

    如果 x 是 对象 或者方法 看看有没有 then方法 有的话 执行then方法 然后继续递归解析返回值

    既不是Promise也不是对象或者方法,其他情况就是普通值,resolve(x)

    中间有报错 直接reject(r)

说一下判断数据类型的方法都有哪些

  1. typeof

    number boolean string undefined bitint symbol object function

  2. Object.prototype.toString.call()

    [object Function] [object Array] [object String] ...

  3. Array.isArray()

  4. instanceof