this 陷阱与原理
最后更新于
{foo: ƒ}
Window ... // 严格模式下指向 undefinedconst obj = { foo: 5 }const obj = { foo: function () {} }var f = function () {
console.log(this.x);
}
var x = 1;
var obj = {
f: f,
x: 2,
};
// 单独执行
f() // 1
// obj 环境执行
obj.f() // 2const obj = {
foo: function () {
console.log(this)
}
}
obj.foo() // obj
obj.foo.call(this) // window
Function.prototype.call = function (context, ...args) {
// 检查调用```call```的对象是否为函数
if (typeof this !== 'function') {
throw new TypeError('not a function')
}
// 将函数作为传入的```context```对象的一个属性,调用该函数
const fn = Symbol()
context[fn] = this
context[fn](...args)
// 不要忘了调用之后删除该属性
delete context[fn]
}function myNew (fn, ...args) {
// 第一步,创建一个空的简单JavaScript对象(即{});
let obj = {}
// 第二步,原型链绑定
fn.prototype !== null && (obj.__proto__ = fn.prototype)
// 第三步,改变this指向并运行该函数
let ret = fn.call(obj, ...args)
// 第四步,如果该函数没有返回对象,则返回this
// 别忘了 typeof null 也返回 'object' 的bug
if ((typeof ret === 'object' || typeof ret === 'function') && ret !== null) {
return ret
}
return obj
}class Demo {
constructor(x, y) {
this.x = x
this.y = y
}
sum() {
const sumVal = this.x + this.y
console.log(sumVal)
return sumVal
}
}
const myDemo = new Demo(2, 3)
// 用法1
myDemo.sum() // 5
// 用法2
const sum = myDemo.sum //将sum的引用赋值给新变量sum (写法等同于 const { sum } = myDemo;)
sum() // Uncaught TypeError: Cannot read property 'x' of undefined || window doesnt has property 'x'class Demo {
constructor(x, y) {
this.x = x;
this.y = y;
this.sum = this.sum.bind(this); // sum中this显式绑定
}
sum() {
let sumVal = this.x + this.y;
return sumVal;
}
}
const myDemo = new Demo(2, 3);
const sum = myDemo.sum;
sum() // 5function foo() {
console.log( this.a )
}
function doFoo(task, callback) {
console.log(task)
callback()
}
const obj = {
a: 2,
foo: foo
}
var a = "oops, global";
// 写法1
doFoo('show a', obj.foo ) // "oops, global"
// 写法2
const { foo: myFoo } = obj
doFoo('show a again', myFoo ) // "oops, global"var obj = {
i: 10,
b: () => console.log(this.i, this),
c: function() {
console.log( this.i, this)
},
d: () => () => console.log(this.i, this),
e: () => ({
i:100,
f: () => console.log(this.i, this)
}),
g: function() {
const h = () => console.log(this.i, this)
return h
}
}
obj.b();
// undefined, Window{...}
obj.c();
// 10, Object {...}
obj.d()()
// undefined, Window{...}
obj.e().f()
// undefined, Window{...}
obj.g()()
// 10, Object {...}
obj.g().call(this)
// 10, Object {...}
obj.g.call(this)()
// undefined, Window{...}
class Demo {
constructor(x, y) {
this.x = x
this.y = y
}
sum = () => {
const sumVal = this.x + this.y;
console.log(sumVal)
return sumVal
}
}
let myDemo = new Demo(2, 3)
// 用法1
myDemo.sum() // 😎 5
// 用法2
const sum = myDemo.sum //将sum的引用赋值给新变量sum (写法等同于 const { sum } = myDemo;)
sum() // 😎 5 function foo() {
console.log( this.a )
}
function doFoo(task, callback) {
console.log(task)
callback()
}
const obj = {
a: 2,
foo: () => foo.call(obj)
}
var a = "oops, global";
// 写法1
doFoo('show a', obj.foo ) // "oops, global"
// 写法2
const { foo: myFoo } = obj
doFoo('show a again', myFoo ) // "oops, global"