function sayLocation() {
console.log(this.atWhere)
}
var atWhere = "I am in global"
sayLocation() // 默认绑定,this绑定在全局对象,输出 “I am in global”
var name = "global"
function person() {
console.log(this.name) // (1) "global"
person.name = 'inside'
function sayName() {
console.log(this.name) // (2) "global" 不是 "inside"
}
sayName() // 在person函数内部执行sayName函数,this指向的同样是全局的对象
}
person()
'use strict'
function sayLocation() {
console.log(this.atWhere)
}
var atWhere = "I am in global"
sayLocation()
// Uncaught TypeError: Cannot read property 'atWhere' of undefined
function say() {
console.log(this.name)
}
var obj1 = {
name: "zxt",
say: say
}
var obj2 = {
name: "zxt1",
say: say
}
obj1.say() // zxt
obj2.say() // zxt1
function say() {
console.log(this.name)
}
var name = "global"
var obj = {
name: "inside",
say: say
}
var alias = obj.say // 设置一个简写 (1)
alias() // 函数调用 输出"global" (2)
apply(obj,[arg1,arg2,arg3,...] 被调用函数的参数以数组的形式给出
call(obj,arg1,arg2,arg3,...) 被调用函数的参数依次给出
// 不带参数
function speak() {
console.log(this.name)
}
var name = "global"
var obj1 = {
name: 'obj1'
}
var obj2 = {
name: 'obj2'
}
speak() // global 等价于speak.call(window)
speak.call(window)
speak.call(obj1) // obj1
speak.call(obj2) // obj2
// 带参数
function count(num1, num2) {
console.log(this.a * num1 + num2)
}
var obj1 = {
a: 2
}
var obj2 = {
a: 3
}
count.call(obj1, 1, 2) // 4
count.apply(obj1, [1, 2]) // 4
count.call(obj2, 1, 2) // 5
count.apply(obj2, [1, 2]) // 5
// 带参数
function count(num1, num2) {
console.log(this.a * num1 + num2)
}
var obj1 = {
a: 2
}
var bound1 = count.bind(obj1) // 未指定参数
bound1(1, 2) // 4
var bound2 = count.bind(obj1, 1) // 指定了一个参数
bound2(2) // 4
var bound3 = count.bind(obj1, 1, 2) // 指定了两个参数
bound3() //4
var bound4 = count.bind(obj1, 1, 2, 3) // 指定了多余的参数,多余的参数会被忽略
bound4() // 4
function Person(name,age) {
this.name = name
this.age = age
console.log("我也只不过是个普通函数")
}
Person("zxt",22) // "我也只不过是个普通函数"
console.log(name) // "zxt"
console.log(age) // 22
var zxt = new Person("zxt",22) // "我也只不过是个普通函数"
console.log(zxt.name) // "zxt"
console.log(zxt.age) // 22
<1>创建一个全新的对象
<2>这个新对象会被执行原型连接
<3>这个新对象会绑定到函数调用的this
<4>如果函数没有返回其他对象,那么new表达式中的函数调用会自动返回这个新对象
function speak() {
console.log(this.name)
}
var obj1 = {
name: 'obj1',
speak: speak
}
var obj2 = {
name: 'obj2'
}
obj1.speak() // obj1 (1)
obj1.speak.call(obj2) // obj2 (2)
function foo(something) {
this.a = something
}
var obj1 = {}
var bar = foo.bind(obj1) // 返回一个新函数bar,这个新函数内的this指向了obj1 (1)
bar(2) // this绑定在了Obj1上,所以obj1.a === 2
console.log(obj1.a)
var baz = new bar(3) // 调用new 操作符后,bar函数的this指向了返回的新实例baz (2)
console.log(obj1.a)
console.log(baz.a)
new 绑定 > 显式绑定 > 隐式绑定 > 默认绑定
var a = 1
var foo = () => {
console.log(this.a) // 定义在全局对象中,因此this绑定在全局作用域
}
var obj = {
a: 2
}
foo() // 1 ,在全局对象中调用
foo.call(obj) // 1,显示绑定,由obj对象来调用,但根本不影响结果
// 定义一个构造函数
function Person(name,age) {
this.name = name
this.age = age
this.speak = function (){
console.log(this.name)
// 普通函数(非箭头函数),this绑定在调用时的作用域
}
this.bornYear = () => {
// 本文写于2016年,因此new Date().getFullYear()得到的是2016
// 箭头函数,this绑定在实例内部
console.log(new Date().getFullYear() - this.age)
}
}
}
var zxt = new Person("zxt",22)
zxt.speak() // "zxt"
zxt.bornYear() // 1994
// 到这里应该大家应该都没什么问题
var xiaoMing = {
name: "xiaoming",
age: 18 // 小明永远18岁
}
zxt.speak.call(xiaoMing)
// "xiaoming" this绑定的是xiaoMing这个对象
zxt.bornYear.call(xiaoMing)
// 1994 而不是 1998,这是因为this永远绑定的是zxt这个实例
以上就是javascript中所有this绑定的情况,在es6之前,前面所说的四种绑定规则可以涵盖任何的函数调用情况,es6标准实施以后,对于函数的扩展新增了箭头函数,与之前不同的是,箭头函数的作用域位于箭头函数定义时所在的作用域。
而对于之前的四种绑定规则来说,掌握每种规则的调用条件就能很好的理解this到底是绑定在了哪个作用域。