// 定义一个对象 let xm = { getThis (){ // 定义一个函数 return this; // 这个函数返回自己的 this 指向 } } let thisOfFunc = xm.getThis(); // 通过对象调用函数得到函数的 this 指向 console.log(thisOfFunc === xm); // true, 函数的this指向调用它的对象本身
因为这个原因, 对象的属性可以通过this来访问, 如果给 xm 加上一个 name 属性, 则通过 xm.name可以得到这个属性值, 也可以在函数中通过 this.name 得到属性值, 即 this.name 就是 vm.name, 进一步, this===xm。 实验如下:
let xm = { name: '小明', // 给 xm 加一个属性, 可以通过 xm.name 访问到 getName (){ return this.name; // 返回 this 的指向的 name 属性 } } console.log(xm.name, xm.getName()); // 小明 小明
2.3 被作为构造函数来调用时
2.3.1 不要像使用普通函数一样使用构造函数
构造函数本质上是函数, 只是在被 new 操作符调用时一个函数才被称为构造函数。然而话虽如此, 但是由于写出一个构造函数的目的是用他来创建一个对象, 所以还要有一些约定俗成的东西来限制这个概念, 避免把构造函数当成普通函数来使用。例如, 构造函数虽然能被直接调用, 但是不要这样做,因为这是一个普通函数就可以做到的事情,例如:
function Person(name){ this.name = name; return 1; // 不要这样对待构造函数 } let n = Person(); // 不要这样使用构造函数
2.3.2 使用构造函数创建对象时发生了什么
当使用 new 关键字来调用构造函数的最终结果是产生了一个新对象, 而产生新对象的过程如下:
创建一个空对象 {}
将该对象的prototype链接到构造函数的prototype上
将这个新对象作为 this 的指向
如果这个构造函数没有返回一个引用类型的值, 则将上面构造的新对象返回
上面的内容如果需要完全理解, 还需要了解原型相关的内容。这里只需要关注第3、4步就可以了,即:将this绑定到生成到的新对象上,并将这个新对象返回, 进一步下结论为:使用构造函数时, this 指向生成的对象, 实验结果如下:
function Person(){ this.getThis = function(){ // 这个函数返回 this return this; } } let p1 = new Person(); // 调用了构造函数并返回了一个新的对象 console.log(p1.getThis() === p1); // true let p2 = new Person(); console.log(p2.getThis() === p2); // true
2.3.3 结论
从上面的内容可以得到如下的结论: 当函数作为构造函数使用时, this 指向返回的新对象
2.4 通过 call() 或者 apply() 调用时
使用函数 call 和 apply 可以在调用一个函数时指定这个函数的 this 的指向, 语法是:
fn.call(targetThis, arg1, arg2,..., argN) fn.apply(targetThis, [arg1, arg2,.., argN]) fn: 要调用的函数 targetThis: 要把 fn 的 this 设置到的目标 argument: 要给 fn 传的实参
例如定义一个对象如下:
let xm = { name: '小明', sayName(){ console.log(this.name); } }; xm.sayName(); // 对象调用函数输出 '小明'
上面定义了一个对象, 对象的 name 属性为'小明'; sayName 属性是个函数, 功能是输出对象的 name 属性的值。根据2.2部分可知 sayName 这个函数的 this 指向 xm 对象, this.name 就是 xm.name。下面定义一个新对象, 并把 xm.sayName 这个函数的 this 指向新定义的对象。
新定义一个对象 xh:
let xh = { name: '小红' };
对象 xh 只有 name 属性, 没有 sayName 属性, 如果想让 xh 也使用 sayName 函数来输出自己的名字, 那么就要在调用 sayName 时让它的 this 指向小红, 以达到 this.name 等于 xh.name 的目的。 这个目的就可以通过 call 和 apply 两个函数来实现。 以call 函数为例来实现这个需求, 只需要这样写就可以了:
xm.sayName.call(xh); // 小红 xm.sayName.apply(xh); // 小红
其中fn为xm.sayName; targetThis为xh, 这是因为targetThis的指向就是xh, 此结论可以由 2.2部分 的内容得到。
2.4.1 call 和 apply 的区别