1. This 的指向问题
默认绑定规则
console.log(this) // window, strict模式下返回undefined function test() { console.log(this); // window } test(); // 纯粹的调用 (Simple call) ==> window.test() 指向window
隐式绑定规则 (谁呼叫就指向谁)
let a = 0; let obj = { a:2, foo: function(){ console.log(this); // obj => obj 呼叫了 foo, 因此 foo 里的 this 指向为 obj } } obj.foo()
let a = 0; let obj = { a:2, foo: function(){ console.log(this); // 返回obj function test(){ console.log(this) // window } test() // obj 呼叫了 foo, 但 test 并不是由 obj呼叫的, 而是纯粹调用, 因此 this 指向 window } } obj.foo()
IIFE
let a = 0; let obj = { a:2, foo: function(){ (function(){ console.log(this); // window })(); // 立即函式(IIFE)都属于纯粹调用, 所以 this 的指向都是 window } } obj.foo()
闭包
let a = 0; let obj = { a: 2, foo: function () { function test() { console.log(this) // window } return test } } obj.foo()() // obj.foo() 的返回值为 test, 因此该表达式 == test() 属于纯粹调用, 因此 this 指向 window
变数赋值的情况
let a = 0; function foo(){ console.log(this); } let obj = { a:2, foo // ES6简写 } obj.foo() // obj let bar = obj.foo // obj.foo == foo, 该表达式的结果是把 foo 的引用地址赋值给了 bar bar() // 因此 bar == foo , 属于纯粹调用, this 的指向为 window
参数赋值的情况
let a = 0; function foo(){ console.log(this); } function bar(fn){ // 将传进来的 obj.foo == foo 赋值给形参 fn fn() // == foo() 属于纯粹调用, 因此 this 的指向为 window // 因此 this 的指向只需要关注函式最终是如何执行的即可 } let obj = { a:2, foo } bar(obj.foo) // obj.foo == foo 作为实参
阿里巴巴面试题
var name = 222; var a = { name: 111, say: function () { console.log(this.name); }, }; var fun = a.say; fun(); // ? a.say(); // ? var b = { name: 333, say: function (fun) { fun(); }, }; b.say(a.say); // ? b.say = a.say; b.say(); // ?
答案:
var name = 222; var a = { name: 111, say: function () { console.log(this.name); }, }; var fun = a.say; fun(); // 222 a.say(); // 111 var b = { name: 333, say: function (fun) { fun(); // 在这里执行了 (a.say)(), 因此是纯粹调用, this 的指向为 window }, }; b.say(a.say); // 222 b.say = a.say; b.say(); // 333
forEach 内的 this 指向
let arr = [1,2,3,4,5] let obj = { name : "obj" } // 在对应的api接口文档中指明 arr.forEach(function(item, index, arr){ console.log(this); // 每次都输出 obj }, obj) // 这里的 obj 就是 arr.forEach 遍历时的 this 指向
arr.forEach(function callback(currentValue[, index[, array]]) { //your iterator}[, thisArg]);参数: callback这个 callback 函式将会把 Array 中的每一个元素作为参数,带进本 callback 函式里,每个元素各执行一次,接收三个参数:currentValue代表目前被处理中的 Array 之中的那个元素。index (选择性)代表目前被处理中的 Array 之中的那个元素的 index.array (选择性)呼叫 forEach() 方法的那个 Array 本身,也就是上面语法中的 arr。thisArg (选择性)执行 callback 回呼函式的 this(即参考之 Object)值。source: https://developer.mozilla.org/zh-TW/docs/Web/JavaScript/Reference/Global_Objects/Array/forEach
显式绑定: call, apply, bind
function foo() { console.log(this); // 打印 } let obj = { a: 2, foo } let bar = obj.foo obj.foo() // obj 以下三种方式都能改变 this 的指向, 将 bar函式 的 this 指向改为 obj bar.call(obj) // obj bar.apply(obj) // obj bar.bind(obj)() // obj
补充
function foo(){ console.log(this)}foo.call(1) // Number {1}foo.call(null) // this 指向 windowfoo.apply(undefined) // this 指向 window
建构式的显式绑定实例
function Product(name, price) { this.name = name; this.price = price; if (price < 0) throw RangeError('Cannot create product "' + name + '" with a negative price'); return this; } function Food(name, price) { // new后this的指向就是这个实例物件 console.log(this); Product.call(this, name, price); this.category = 'food'; } Food.prototype = new Product(); function Toy(name, price) { Product.call(this, name, price); this.category = 'toy'; } Toy.prototype = new Product(); let cheese = new Food('feta', 5); console.log(cheese); // Food {name: 'feta', price: 5, category: 'food'} let fun = new Toy('robot', 40); console.log(fun); // Toy {name: 'robot', price: 40, category: 'toy'}
new 绑定
function Person(name='haewon', age=6){ this.name = name this.age = age console.log(this) // 这里会打印 this}let me = new Person('pupu', 12) // 打印 Person {name: 'pupu', age: 12}, this 的指向为实例化的物件Person() // 打印 window; 同时 window.name 的值为 'haewon'; window.age 的值为 6
总结
1. 默认绑定: console.log(this=== window) ==> true 2. 隐式绑定: (谁呼叫就指向谁) :3. 显式绑定: call, apply, bind4. new 绑定规则;
优先级
1. 显式绑定 > 隐式绑定
function foo(){ console.log(this.a); } let obj1 ={ a:'obj1', foo } let obj2 ={ a:'obj2', foo } obj1.foo() // obj1 obj2.foo() // obj2 obj1.foo.call(obj2) // obj2 obj2.foo.call(obj1) // obj1
2. new 绑定 > 显式绑定
function foo(b){ this.a = b } let obj1 = {} let bar = foo.bind(obj1) bar(2) console.log(obj1.a) // 2 let bar_child = new bar(99) // new 将 this 的指向更改为 bar_child console.log(obj1.a); // 2 console.log(bar_child.a); // {a:99}
以上是我整理好的资料,希望有帮助到大家