this指向&&手写call...
- 非严格模式下
- 在 浏览器 环境中,全局对象是 window。
- 在 Node.js 环境中,全局对象是 global
globalThis.name='martin'
- 严格模式下
this是undefined
函数this永远指向最后调用他的对象
改变this指向
apply和call都只是临时改变一次函数的this指向并立即执行该函数
- apply()
var arr=[1,10,5,8,3];
console.log(Math.max.apply(null, arr));
//第一个参数为调用函数的this指向,第二个参数必须是数组或类数组对象作为参数列表传入
//在ES6中可以用
Math.max(...arr)
- call()
var arr=[1,10,5,8,3];
console.log(Math.max.call(null,arr[0],arr[1],arr[2],arr[3],arr[4]));
//与apply()不同的是this之后传入的是参数列表
- bind()
函数不会立即执行,可以分多次传参
var arr=[1,10,5,8,12];
var max=Math.max.bind(null,arr[0],arr[1],arr[2],arr[3])
console.log(max(arr[4])); //12,分两次传参
手写实现
- call()
call和apply的区别就是参数的传递
Function.prototype.myCall=function(){
let context=arguments[0]
if(context==null||context==undefined){
context=window
}else{
context=Object(context)
const args=Array.from(arguments).slice(1)
const randomKey='_key'+Math.random()
context[randomKey]=this
if(!context[randomKey]){
context={...context,[randomKey]:this}
}
const result=context[randomKey](...args)
delete context[randomKey]
return result
}}
- Apply()
Function.prototype.myApply=function(){
let context=arguments[0]
if(context==null||context==undefined){
context=window
}else{
context=Object(context)//转换为对象类型,不然基本类型会转换为对象类型
}
let args=arguments[1]
let randomKey=Symbol('call_key')
context[randomKey]=this
if(!context[randomKey]){
context={...context,[randomKey]:this}
}//防止挂载失败
let result=context[randomKey](...args)
delete context[randomKey] //删除添加的属性,不影响原对象避免每次调用都添加属性
return result
}
为什么要在挂载之后再检查一遍呢?
因为有一些对象,比如
const obj_2 = Object.freeze({ a: 1 }); // obj 被冻结,不能添加新属性
const fn = function() { console.log('hello'); };
fn.myCall(obj_2); // hello
- Bind()
Function.prototype.myBind = function() {
if (typeof this !== "function") {
throw new TypeError("Bind must be called on a function");
}
const context = arguments[0];
const args = Array.from(arguments).slice(1);
const fn = this;//调用bind的函数
function boundFunction(...newArgs) {
// 如果 new 调用 boundFunction,this 应该指向新实例
return fn.myApply(this instanceof boundFunction ? this : context, [...args, ...newArgs]);
}
// 维护原函数的 prototype
boundFunction.prototype = Object.create(fn.prototype);
return boundFunction;
};
const fn = function() { console.log('hello'); };
const obj_3 = Object.freeze({ a: 1 }); // obj 被冻结,不能添加新属性
const obj_3 = Object.create({ a: 1 });
// const fn = function() { console.log('hello'); };
fn.myBind(obj_3);
fn()//hello
或者用const isNew = typeof new.target !== 'undefined'
判断是否函数被new调用
普通调用是undefined