第二十一天
(题目来源: 前端每日知识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.js
device.js