普通函数this指向进阶实例讲解
注:新版chrome浏览器下 全局是window 严格模式下:全局是undefined node下:全局是global
其实函数对于宿主对象来说,更专业的说法是绑定关系,fn的绑定对象为obj,obj为fn的执行环境,这篇再整理一些进阶的this实例
const obj = { a: 1, fn: function() { console.log(this.a) } } obj.fn() // 1 // fn绑定的对象为obj,所以console 为 1 const f = obj.fn f() //undefined // fn绑定的对象为全局,所以console 为 undefined
function fn () { console.log(this.a) } const obj = { a: 1 } const newFn = fn.bind(obj); newFn(); // 1 //给fn绑定obj为宿主对象,所以console 为 1
const obj1 = { a: 1, fn: function() { console.log(this.a) } } setTimeout(()=>{ obj1.fn(); }, 1000) //1 //这里的绑定对象是obj1,所以为1 setTimeout(obj1.fn,1000);// undefined //这里相当于把obj1.fn给全局windows,所以为undefined //函数作为参数传递 function run(fn) { fn() } run(obj1.fn) // undefined // 这里传进去的是一个引用,所以fn()是在windows下执行的
function fn () { console.log(this.a) } fn.call(null) // undefined //当call,bind,apply第一个参数为null的时候,则绑定全局
function fn() { console.log(this) } fn.bind(1).bind(2)() // Number(1) // 为啥可以绑定基本类型 ? // boxing(装箱) -> (1 ----> Number(1)) // bind 只看第一个 bind(堆栈的上下文,上一个,写的顺序来看就是第一个) new (fn.bind(1))(); // fn{}; //当bind有new的情况下,不看bind的看new //指向以fn为构造函数的生成的实例对象
所以衍生一个问题,手写一个bind方法
function bindFn(fn, ...args) { if (typeof fn !== function) { throw new TypeError(function is not callable); } //获取绑定对象 const otherThis = args.splice(1); //获取剩余参数 const letArgs = args; //获取当前方法 const fnThis = fn; //定义绑定函数 const fBound = function () { return fnThis.call( fnThis.prototype.isPrototypeOf(this) ? this : otherThis, ...letArgs, ...arguments ) } //寄生组合方式通过中间函数将fnThis的原形对象赋予fBound的原形对象 if (fnThis.prototype) { fBound.prototype = Object.create(fnThis.prototype) } }
function foo(a) { this.a = a } const f = new foo(2); f.a // 2 function foo(a) { this.a = a; return { }; } const f = new foo(2); f.a // undefined //new 关键字做了什么 //将函数的原形对象赋值给对象f的隐式原形对象__proto__ //**将函数foo,绑定给对象f //**如果函数有返回值且为对象,则返回那个新对象,否则返回对象f
function foo() { console.log( this.a ) // console what? 2 } var a = 2; (function(){ "use strict" // 迷惑大家的 foo(); })();
var obj1 = { a: 1, } var obj2 = { a: 2, fn: function () { console.log(this.a); } } obj2.fn.call(obj1); //1 //这里的bind,call,apply为显式绑定 //这里的obj.fn为隐式绑定 //之前的window.this为默认绑定 //之前的new为new绑定
所以综上所有的例子可以得出一个结论 优先级顺序为 new > 显式绑定 > 隐式绑定 > 默认绑定
over