普通函数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
