目录
例3:声明一个值为函数的变量clear,在一个对象tom里的某个属性c赋值为该变量clear,然后通过该对象tom调用这个变量c
例2:函数里面返回构造函数,可以访问实例本身属性,也可访问实例构造方法prototype中的属性
在`ES6之前`,函数内部的this是由该函数的调用方式决定的
函数内部的this跟大小写、书写位置无关
1 函数调用方式
函数内部的this指向window
var age=18; var p={ age:15, say:function(){ console.log(this.age); } } var f1=p.say; //f1是函数 f1(); //函数调用-->this:window -->this.age=18
将一个对象的方法赋值给一个变量,则这个变量是一个函数
f1()调用该函数,结果为18,表明函数内部的this指向window
2 方法调用方式
函数内部的this指向调用该方法的对象
例1:声明一个对象,调用对象原型里的方法
function Person(){ this.age=20; } Person.prototype.run=function(){ console.log(this.age); } var p1=new Person(); p1.run(); //打印结果:20
例2:直接调用对象里的方法
var p2={ height:180, travel:function(){ console.log(this.height); } } p2.travel() //打印结果:180
例3:声明一个值为函数的变量clear,在一个对象tom里的某个属性c赋值为该变量clear,然后通过该对象tom调用这个变量c
var clear=function(){ console.log(this.length); } var length=50; var tom={ c:clear,length:100 }; tom.c(); //这里是方法调用的方式
打印this.length 是50 还是100?
-->相当于问:this是指向window还是指向tom呢?
-->结果为:100
-->this:tom结论:由于clear函数被当成tom.c()这种方法的形式来进行调用,所以函数内部的this指向调用该方法的对象:tom
3 构造函数调用方式
通过new关键字来调用的,那么这种方式就是构造函数的构造函数的调用方式,那么函数内部的this就是该构造函数的实例
例1:有一个函数,用new 来赋值,则是赋值的构造函数
function fn(name){ this.name=name; } var _n=new fn("小明"); //_n有个name属性,值为:小明
例2:函数里面返回构造函数,可以访问实例本身属性,也可访问实例构造方法prototype中的属性
function jQuery(){ var _init=jQuery.prototype.init; //_init就是一个构造函数 return new _init(); } jQuery.prototype={ constructor:jQuery, length:100, init:function(){ //this可以访问到实例本身的属性,也可以访问到init.prototype中的属性 //这里的init.prototype并不是jQuery.prototype console.log(this.length); //正确答案:undefined //100? 错误的 } }
补充说明:
1.变量声明了未赋值是undefined
2.属性不存在也是undefined
例3:修改函数的默认原型,指向新原型
对象的属性查找规则
1、首先查看本身有没有length属性
2、如果本身没有该属性,那么去它的原型对象中查找
3、如果原型对象中没有,那么就去原型对象的原型对象中查找,最终一直找到根对象(Object.prototype)
4、最终都没有找到的话,我们认为该对象并没有该属性,如果获取该属性的值:undefinedfunction jQuery(){ var _init=jQuery.prototype.init; //_init就是一个构造函数 return new _init(); } jQuery.prototype={ constructor:jQuery, length:100, init:function(){ //this指向init构造函数的实例 console.log(this.length); //100 } } var $init=jQuery.prototype.init; //修改了init函数的默认原型,指向新原型 $init.prototype=jQuery.prototype; jQuery();//打印出:100
4 上下文调用方式
上下文调用方式,有3种,call、apply、bind
1.call和apply是立刻执行这个函数,并且在执行过程中绑定了this这个值
2.bind并没有立即执行这个函数,而是创建了一个新函数,新函数绑定了this这个值
例1:上下文调用call
function f1(){ console.log(this); } //call方法的第一个参数决定了函数内部的this的值 f1.call([1,3,5]) f1.call({age:20,height:1000}) f1.call(1) f1.call("abc") f1.call(true); f1.call(null) f1.call(undefined);
上述代码可以用apply完全替换
总结:
call方法的第一个参数:
1、如果是一个对象类型,那么函数内部的this指向该对象
2、如果是undefined、null,那么函数内部的this指向window
3、如果是数字-->this:对应的Number构造函数的实例。如果输入1 输出 new Number(1)
如果是字符串-->this:String构造函数的实例。如果输入 "abc" --> new String("abc")
如果是布尔值-->this:Boolean构造函数的实例。如果输入false --> new Boolean(false)
例2:call和apply异同
同:call和apply都可以改变函数内部的this的值
异:传参的形式不同
function toString(a,b,c){ console.log(a+" "+b+" "+c); } toString.call(null,1,3,5) //"1 3 5" toString.apply(null,[1,3,5])//"1 3 5"
例3 :上下文调用bind
1) 调用了
setTimeout
函数,它会在指定的延迟(这里是50毫秒)后执行提供的函数。但是,请注意,在JavaScript中,setTimeout
的回调函数中的this
并不指向调用setTimeout
的对象(这里是obj
),而是指向全局对象(在浏览器中通常是window
)var obj = { age: 18, run: function () { console.log(this); //this:obj var _that = this; setTimeout(function () { //this指向window console.log(this.age);//undefined console.log(_that.age);//18 }, 50); } } obj.run();
2)通过执行了bind方法,匿名函数本身并没有执行,只是改变了该函数内部的this的值,指向obj5
var obj5 = { age: 18, run: function () { console.log(this); //this:obj5 setTimeout((function () { console.log(this.age); //18 }).bind(this), 50); //this:obj5 } } obj5.run();
3)bind基本用法
执行了bind方法之后,产生了一个新函数,这个新函数里面的逻辑和原来还是一样的,唯一的不同是this指向{ seconds:100 }
function speed(){ console.log(this.seconds); } var speedBind = speed.bind({ seconds:100 }); speedBind(); //100
匿名函数.调用bind方法执行
xxx.bind()() 一般采用这种方法
(function eat(){ console.log(this.seconds); }).bind({ seconds:360 })() //360
4)
var obj={ name:"西瓜", drink:(function(){ //this指向了:{ name:"橙汁" } console.log(this.name); }).bind({ name:"橙汁" }) } obj.drink(); //"橙汁" var p10={ height:88, run:function(){ //this setInterval((function(){ console.log(this.height); //88 }).bind(this),100) } } p10.run();