第二十一天
(题目来源: 前端每日知识3+1)
Javascript题目
手撕bind, call, apply方法
问题解答
- call 方法 改变this的指向, 立即执行函数, 第一个参数是表示要绑定的对象, 如果调用时不传参, 比如
call()call(null)call(undefined)这三种的this都指向window - apply方法 也是改变this的指向, 立即执行, 与call方法不同的是 apply方法传入的第二个参数是数组
- bind方法 与以上方法不同的是, 它不是一个立即执行的方法, 返回一个函数
解题思路
- call方法
function fn() {this.a = arguments[0]console.log(this.a, this.name);}Function.prototype._call = function(context = window, ...args) {// 判断调用对象if (typeof this !== 'function') {throw new TypeError('Error');}args = args ? args : []//创建独一无二属性,以免覆盖原属性const key = Symbol();context[key] = this;//通过隐式绑定的方式调用函数const result = context[key](...args);//删除添加的属性delete context[key];//返回函数调用的返回值return result;};let obj = {name: 'zs'}fn._call(obj, 'zs')
- apply方法
function fn() {this.a = arguments[0]console.log(this.a, this.name);}Function.prototype._apply = function(context = window, ...args) {// 判断调用对象if (typeof this !== 'function') {throw new TypeError('Error');}args = args ? [...args] : []//创建独一无二属性,以免覆盖原属性const key = Symbol();context[key] = this;//通过隐式绑定的方式调用函数const result = context[key](...args);//删除添加的属性delete context[key];//返回函数调用的返回值return result;};let obj = {name: 'zs'}fn._call(obj, [0, 1, 2, 3])
- bind方法
function fn() {this.a = arguments[0]console.log(this.a, this.name);}Function.prototype._bind = function() {if (typeof this !== 'function') {throw new Error('Function.prototype.bind - what is trying to be bound is not callable')}let self = this// 需要传入self的参数let args = Array.prototype.slice.call(arguments, 1)return function() {return self.apply(self, args)}}let obj = {name: 'zs'}console.log(fn._bind(obj, 1)()); //1 "fn" 打印输出
知识扩展
script,script async,script defer这三种的区别:
script在执行的时候会阻塞 DOM 的渲染.
页面内内联的script标签, 加载时立即执行所以会阻塞下面页面的渲染.async异步加载, 加载成功立即执行.defer异步加载, 但等到文档加载完成后才执行.async、defer这两个属性无法应用于内联script.

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