第二十一天


(题目来源: 前端每日知识3+1)

Javascript题目

手撕bind, call, apply方法

问题解答

  • call 方法 改变this的指向, 立即执行函数, 第一个参数是表示要绑定的对象, 如果调用时不传参, 比如call() call(null) call(undefined)这三种的this都指向window
  • apply方法 也是改变this的指向, 立即执行, 与call方法不同的是 apply方法传入的第二个参数是数组
  • bind方法 与以上方法不同的是, 它不是一个立即执行的方法, 返回一个函数

解题思路

  • call方法
  1. function fn() {
  2. this.a = arguments[0]
  3. console.log(this.a, this.name);
  4. }
  5. Function.prototype._call = function(context = window, ...args) {
  6. // 判断调用对象
  7. if (typeof this !== 'function') {
  8. throw new TypeError('Error');
  9. }
  10. args = args ? args : []
  11. //创建独一无二属性,以免覆盖原属性
  12. const key = Symbol();
  13. context[key] = this;
  14. //通过隐式绑定的方式调用函数
  15. const result = context[key](...args);
  16. //删除添加的属性
  17. delete context[key];
  18. //返回函数调用的返回值
  19. return result;
  20. };
  21. let obj = {
  22. name: 'zs'
  23. }
  24. fn._call(obj, 'zs')
  • apply方法
  1. function fn() {
  2. this.a = arguments[0]
  3. console.log(this.a, this.name);
  4. }
  5. Function.prototype._apply = function(context = window, ...args) {
  6. // 判断调用对象
  7. if (typeof this !== 'function') {
  8. throw new TypeError('Error');
  9. }
  10. args = args ? [...args] : []
  11. //创建独一无二属性,以免覆盖原属性
  12. const key = Symbol();
  13. context[key] = this;
  14. //通过隐式绑定的方式调用函数
  15. const result = context[key](...args);
  16. //删除添加的属性
  17. delete context[key];
  18. //返回函数调用的返回值
  19. return result;
  20. };
  21. let obj = {
  22. name: 'zs'
  23. }
  24. fn._call(obj, [0, 1, 2, 3])
  • bind方法
  1. function fn() {
  2. this.a = arguments[0]
  3. console.log(this.a, this.name);
  4. }
  5. Function.prototype._bind = function() {
  6. if (typeof this !== 'function') {
  7. throw new Error(
  8. 'Function.prototype.bind - what is trying to be bound is not callable'
  9. )
  10. }
  11. let self = this
  12. // 需要传入self的参数
  13. let args = Array.prototype.slice.call(arguments, 1)
  14. return function() {
  15. return self.apply(self, args)
  16. }
  17. }
  18. let obj = {
  19. name: 'zs'
  20. }
  21. console.log(fn._bind(obj, 1)()); //1 "fn" 打印输出

知识扩展

  • script, script async, script defer 这三种的区别:
    script在执行的时候会阻塞 DOM 的渲染.
    页面内内联的script标签, 加载时立即执行所以会阻塞下面页面的渲染.async异步加载, 加载成功立即执行.defer异步加载, 但等到文档加载完成后才执行.async、defer这两个属性无法应用于内联script.

题目:手撕bind, call, apply方法 - 图1

  • 判断当前浏览器设备来源的方法使用window.navigator.userAgent, 也可以使用开源的npm包device.jsdevice.js