this指向
this-运行期绑定,this指向调用时决定。
- 全局 this指向window
- 函数中,若有调用者,则this指向调用者;若为独立调用,则this为undefined。在非严格模式中,当this指向undefined时,它会被自动指向全局对象。
- call/apply/bind 可以改变this指向为第一个参数
- new this指向新构造出来的实例对象
- 箭头函数,没有自己的this,会捕获上下文中的this指向,即最近的非箭头函数中的this指向。
- dom事件中,this指向DOM节点。
call
function.call(thisArg, arg1, arg2, ...)
thisArg
可选的。在function
函数运行时使用的this
值。请注意,this
可能不是该方法看到的实际值:如果这个函数处于非严格模式下,则指定为null
或undefined
时会自动替换为指向全局对象,原始值会被包装。
arg1, arg2, ...
指定的参数列表。
返回
调用有指定this值和参数的函数的结果。
!参数一个个列表式传入
Function.prototype.call2 = function (context) {
// 如果没传this指向,则指向window
var context = context || window;
// 把要调用的函数绑定到对象上, Symbol保证唯一性,不覆盖已有属性
var fn = Symbol();
context[fn] = this;
// 处理参数列表
var args = [];
for(var i = 1, len = arguments.length; i < len; i++) {
args.push(arguments[i]);
}
// 执行函数
var result = context.fn(...args);
// 删除绑定
delete context.fn
// 返回结果
return result;
}
Function.prototype.call3 = function(context) {
return this.apply([].shift.apply(arguments), arguments);
}
apply
func.apply(thisArg, [argsArray])
thisArg
必选的。在func
函数运行时使用的this
值。请注意,this
可能不是该方法看到的实际值:如果这个函数处于[非严格模式]下,则指定为null
或undefined
时会自动替换为指向全局对象,原始值会被包装。
argsArray
可选的。一个数组或者类数组对象,其中的数组元素将作为单独的参数传给func
函数。如果该参数的值为 [null
],则表示不需要传入任何参数。从ECMAScript 5 开始可以使用类数组对象。
返回
调用有指定this值和参数的函数的结果。
!参数以数组形式传入
Function.prototype.apply2 = function (context,args) {
// 如果没传this指向,则指向window
var context = context || window;
// 把要调用的函数绑定到对象上, Symbol保证唯一性,不覆盖已有属性
var fn = Symbol();
context[fn] = this;
// 执行函数
var result = context.fn(...args);
// 删除绑定
delete context.fn
// 返回结果
return result;
}
Function.prototype.apply3 = function(context, args) {
return this.call(context, ...args)
}
bind
Function.prototype.bind2 = function (context) {
var self = this;
// 获取bind2函数从第二个参数到最后一个参数
var args = Array.prototype.slice.call(arguments, 1);
return function () {
// 这个时候的arguments是指bind返回的函数传入的参数
var bindArgs = Array.prototype.slice.call(arguments);
return self.apply(context, args.concat(bindArgs));
}
}
Function.prototype.bind = Function.prototype.bind || function bind(thisArg){
// 非函数调用,直接报错
if(typeof this !== 'function'){
throw new TypeError(this + ' must be a function');
}
var self = this;
var args = [].slice.call(arguments, 1);
var bound = function(){
// 处理参数合并
var boundArgs = [].slice.call(arguments);
var finalArgs = args.concat(boundArgs);
// new 当构造函数使用
// 用new.target判断更准确
if(this instanceof bound){
if(self.prototype){
function Empty(){}
Empty.prototype = self.prototype;
bound.prototype = new Empty();
}
var result = self.apply(this, finalArgs);
// 构造函数返回值为非对象、函数,返回构造出的实例对象
var isObject = typeof result === 'object' && result !== null;
var isFunction = typeof result === 'function';
if(isObject || isFunction){
return result;
}
return this;
}
else{
return self.apply(thisArg, finalArgs);
}
};
return bound;
}