This和箭头函数的使用 (均是在非严格模式下)
this的绑定规则
this到底指向什么呢?
- this的绑定规则:
- 默认绑定
- 隐式绑定
- 显式绑定
- new绑定
apply/call/bind
apply和call的区别
bind的规则
- bind函数会返回一个this总是绑定所绑定的函数
function foo() {
console.log("foo", this)
}
var obj = {
name: "zsy",
age: 18
}
foo() // this -> window
// 需求:调用foo时,总是绑定到obj对象身上(不希望obj对象身上有函数)
var bar = foo.bind(obj)
bar() // this -> obj
运行结果:
this的绑定优先级
-
默认绑定的优先级最低(隐式绑定优先级高于默认绑定)
function foo() { console.log("foo", this) // this -> obj } var obj = { foo: foo } obj.foo()运行结果:
-
显示绑定优先级高于隐式绑定(call、apply和bind)
function foo() { console.log("foo", this) // this -> String {"abc"} } var obj = { foo: foo } obj.foo.call("abc") // call和apply都可以运行结果:
-
new绑定优先级高于隐式绑定
function foo() { console.log("foo", this) // this -> {}(new关键字创建的对象) console.log(this === obj) // false } var obj = { foo: foo } new obj.foo()运行结果:
-
new绑定的优先级高于bind
function foo() { console.log("foo", this) // this -> {}(new关键字创建的对象) } var obj = { foo: foo } var bar = foo.bind("aaa") // 通过bind函数显示绑定string aaa new bar()运行结果:
- new绑定和call、apply是不允许同时使用的
- new绑定可以和bind一起使用,new绑定优先级更高
-
bind绑定的优先级高于call和apply
function foo() { console.log("foo", this) // this - > string {'aaa'} } var obj = { foo: foo } var bar = foo.bind("aaa") // 通过bind函数显示绑定string aaa bar.call("bbb") // 通过call函数显示绑定string bbb (call和apply函数用法可以说是一样的)运行结果:
绑定之外的情况
忽略显示绑定
function foo() {
console.log("foo", this) // this - > window对象
}
var obj = {
foo: foo
}
foo.call(null) // 显示绑定null和undefined作用是一样的
运行结果:
间接函数引用
var obj1 = {
name: "obj1",
foo: function() {
console.log("foo", this) // this -> window对象
}
}
var obj2 = {
name: "obj2"
}; // 这里一定要加分号(;)
(obj2.foo = obj1.foo)() // 相当于独立调用函数
运行结果:
箭头函数的使用(ES6)
-
箭头函数不会绑定this、arguments属性
-
箭头函数不能作为构造函数来使用(不能和new一起来使用,会抛出错误)
-
箭头函数的简写
var arrs = [1, 2, 3, 4, 5, 6, 7, 8, 9] var num = arrs.filter(element => element % 2 === 0) console.log(num)运行结果:
var obj = { name: "obj" } var resultFn = () => ({obj}) // 如果箭头函数简写,要返回对象时必须用()包起来。否则{}包起来的是执行体 console.log(resultFn())运行结果:
-
箭头函数实现nums的所有偶数平方之和 (练习箭头函数的简写以及高阶函数的使用)
var nums = [20, 30, 11, 15, 111] var result = nums.filter(item => item % 2 === 0) .map(item => item * item) .reduce((preItem, item) => preItem + item) console.log(result) // 1300 -
箭头函数中,压根没有this。即箭头函数不绑定this(this是从上层作用域中查询的)
var obj = { name: "obj", foo: function() { var bar = () => { console.log("bar", this) // this -> obj对象(此处的this是上层作用域foo函数的this) } return bar } } var fn = obj.foo() // foo函数是被obj对象,隐式调用的 fn.call("aaa")运行结果:
this面试题分析
面试题一
var name = "window"
var person = {
name: "person",
sayName: function () {
console.log(this.name)
}
}
function sayName() {
var sss = person.sayName;
sss(); // 默认绑定, this -> window
person.sayName(); // 隐式绑定, this -> person
(person.sayName)(); // 隐式绑定, this -> person
(b = person.sayName)(); // 默认绑定, this -> window (间接函数引用)
}
sayName()
面试题二
var name = "window"
var person1 = {
name: "person1",
foo1: function () {
console.log(this.name)
},
foo2: () => console.log(this.name),
foo3: function () {
return function () {
console.log(this.name)
}
},
foo4: function () {
return () => {
console.log(this.name)
}
}
}
var person2 = {
name: "person2"
}
person1.foo1() // 隐式绑定, person1
person1.foo1.call(person2) // 显式绑定优先级高于隐式绑定, person2
person1.foo2() // 箭头函数无this, this是从上层作用域查询到的(this -> window), window
// 不管隐式绑定还是显式绑定都是对foo2函数的, 但foo2函数是箭头函数, this是从上层作用域查询到的(this -> window)
person1.foo2.call(person2) // window
person1.foo3()() // 默认绑定, window
// 显式绑定优先级高于隐式绑定, foo3函数的this -> person2, 但foo3函数执行完返回一个新函数属于是独立调用函数this -> window
person1.foo3.call(person2)() // window
person1.foo3().call(person2) // 显示绑定, person2
// foo4函数被执行时,this -> person1, 返回箭头函数,而箭头函数的this是从上层作用域查询到的(this -> person1)
person1.foo4()() // person1
person1.foo4.call(person2)() // person2
person1.foo4().call(person2) // person1
运行结果:
面试题三
var name = "window"
function Person(name) {
this.name = name
this.foo1 = function () {
console.log(this.name)
},
this.foo2 = () => console.log(this.name),
this.foo3 = function () {
return function () {
console.log(this.name)
}
},
this.foo4 = function () {
return () => {
console.log(this.name)
}
}
}
var person1 = new Person("person1")
var person2 = new Person("person2")
person1.foo1() // person1
person1.foo1.call(person2) // person2
person1.foo2() // person1
person1.foo2.call(person2) // person1
person1.foo3()() // window
person1.foo3.call(person2)() // window
person1.foo3().call(person2) // person2
person1.foo4()() // person1
person1.foo4.call(person2)() // person2
person1.foo4().call(person2) // person1
运行结果:
面试题四
var name = "window"
function Person(name) {
this.name = name
this.obj = {
name: "obj",
foo1: function() {
return function() {
console.log(this.name)
}
},
foo2: function() {
return () => {
console.log(this.name)
}
}
}
}
var person1 = new Person("person1")
var person2 = new Person("person2")
person1.obj.foo1()() // window
person1.obj.foo1.call(person2)() // window
person1.obj.foo1().call(person2) // person2
person1.obj.foo2()() // obj
person1.obj.foo2.call(person2)() // person2
person1.obj.foo2().call(person2) // obj
运行结果: