this的绑定规则
绑定一:默认绑定;
绑定二:隐式绑定;
绑定三:显示绑定;
绑定四:new绑定;
绑定一:默认绑定;
独立函数调用
独立的函数调用我们可以理解成函数没有被绑定到某个对象上进行调用;
案例1:
function foo() {
console.log(this)//this指向window
}
foo()
案例2:
// 2.案例二:
function foo1() {
console.log(this)//window
}
function foo2() {
console.log(this)//window
foo1()
}
function foo3() {
console.log(this)//window
foo2()
}
foo3()
案例3:
var obj = {
name: "why",
foo: function() {
console.log(this)// window
}
}
var bar = obj.foo
bar() // 独立函数调用--与定义位置无关,跟调用方式和调用位置有关,bar是在全局调用的
案例4:
function foo() {
console.log(this)
}
var obj = {
name: "why",
foo: foo
}
var bar = obj.foo
bar() // window
案例5:
function foo() {
function bar() {
console.log(this)// window
}
return bar
}
var fn = foo()
fn()
闭包里的this不一定就指向window,只要独立调用就指向window
如:
function foo() {
function bar() {
console.log(this)
}
return bar
}
var fn = foo()
fn() // window
var obj = {
name: "why",
eating: fn
}
obj.eating() // obj 隐式绑定
绑定二:隐式绑定;
obj.fn():obj对象会被js引擎绑定到fn函数中的this里面(内部自动绑定)
通过某个对象进行调用的:
也就是它的调用位置中,是通过某个对象发起的函数调用
前提条件:
1.必须在调用的对象的内部有一个对函数的引用(比如一个属性);
2.如果没有这样的引用,在进行调用时,会报找不到该函数的错误;
3.正是通过这个引用,间接的将this绑定到了这个对象上.
案例一:
function foo() {
console.log(this)
}
// 独立函数调用
// foo()
// 1.案例一:
var obj = {
name: "why",
foo: foo
}
obj.foo() // obj对象
案例2:
var obj = {
name: "why",
eating: function() {
console.log(this.name + "在吃东西")
},
running: function() {
console.log(obj.name + "在跑步")
}
}
obj.eating()
obj.running()
var fn = obj.eating
fn()//独立函数调用了 name是空,取的是window里的name
案例3:
var obj1 = {
name: "obj1",
foo: function() {
console.log(this)
}
}
var obj2 = {
name: "obj2",
bar: obj1.foo
}
obj2.bar()//obj2 bar调用时boj2绑定到this
绑定三:显式绑定;
如果我们不希望在对象内部包含这个函数的引用,同时又希望在这个对象上进行强制调用,该怎么做呢?
1.javaScript所有的函数都可以使用call和apply方法(这个和prototype有关).
ps:call和apply区别:第一个参数是相同的,后面的参数,apply为数组,call为参数列表
2.这两个函数的第一个参数都要求是一个对象,这个对象的作用就是给this准备的.
3.在调用这个函数时,会将this绑定到这个传入的对象上.
案例:
function foo() {
console.log("函数被调用了", this)
}
// 1.foo直接调用和call/apply调用的不同在于this绑定的不同
// foo直接调用指向的是全局对象(window)
foo()
var obj = {
name: "obj"
}
// call/apply是可以指定this的绑定对象
foo.call(obj)
foo.apply(obj)
foo.apply("aaaa")
2.call和apply有什么区别?
function sum(num1, num2, num3) {
console.log(num1 + num2 + num3, this)
}
sum.call("call", 20, 30, 40)
sum.apply("apply", [20, 30, 40])
3.call和apply在执行函数时,是可以明确的绑定this, 这个绑定规则称之为显示绑定
bind:
function foo() {
console.log(this)
}
// 默认绑定和显示绑定bind冲突: 优先级(显示绑定)
var newFoo = foo.bind("aaa")//显示绑定了this为aaa
newFoo()
newFoo()
newFoo()//在被调用时,this永远是aaa 这是个新函数
绑定三:new绑定;
javaScript中的函数可以当做一个类的构造函数来使用,也就是使用new关键字.
使用new关键字来调用函数时,会执行如下操作:
1.创建一个全新的对象;
2.这个新对象会被执行prototype(原型)连接;
3.这个新对象会绑定到函数调用的this上(this的绑定在这个步骤完成);
4.如果函数没有返回其他对象,表达式会返回这个新对象;
function Person(name, age) {
this.name = name
this.age = age
}
//js中通过 new Person()调函数 会生成一个新{} 然后把生成的这个对象赋值给函数内部中的this,最后将这个对象也就是this返回
//之后就可以通过var a=new Person()拿到这个对象
//每次会创建一个新的对象重复以上步骤
var p1 = new Person("why", 18)
console.log(p1.name, p1.age)//所以p1可以拿到对象中属性
var p2 = new Person("kobe", 30)//每次会创建一个新的对象
console.log(p2.name, p2.age)
我们通过一个new关键字调用一个函数时(构造器),这个时候this是在调用这个构造器时创建出来的对象
this=创建出来的对象
这个绑定过程就是new绑定
var obj = {
foo: function() {
console.log(this)
}
}
new obj.foo();//这时候就是new绑定和obj绑定冲突了--这里就要考虑优先级的问题了 具体细节见下篇文章