JavaScript函数this指向
全局this指向window
一般函数 this/严格模式this
function f1(){
return this;
};
f1() === window//true
//严格模式
function f2(){
'use strict'
return this;
};
f2() === undefined;
作为对象方法函数的this
//示例1:
var o = {
prop:37,
f:function(){
console.log( this);
}
};
o.f();//{prop: 37, f: ?} this是o;
//示例2:
var o = {
prop:37
};
function indeprndent(){
console.log(this);
}
indeprndent();//this 是 window
o.f = indeprndent;
o.f();//this是o;
window.o.f();//this是o;
对象原型链上的this
var o = {
f:function(){
return this.a+this.b;
}
};
var p = Object.create(o);
p.a =1;
p.b = 2;
p.f();//3
get set的this
function modulus(){
console.log('modulus',this)
}
var o ={
re:1,
im:-1,
get phase(){
console.log('phase',this.re,this.im)
}
}
Object.defineProperty(o,'modulus',{
get:modulus,emumerable:true,configurable:true
})
console.log(o.phase,o.modulus);
//phase 1 -1
//modulus {re: 1, im: -1}
构造器中this
function c2(){
this.a = 37;
return {a:38};
};
var o = new c2();
console.log(o.a);//38 如果return 是对象,就返回return 的对象。(return 基本类型没关系)
function c2(){
this.a = 37;
this.b=99;
return {a:38};
};
var o = new c2();
console.log(o.b);//undefined 如果return 是对象,就返回return 的对象。(return 基本类型没关系)
function c2(){
this.a = 37;
this.b=99;
return 12;
};
var o = new c2();
console.log(o.b)// 99(return 基本类型没关系)
this指向总结
最近是谁调用,this就是谁。
更改this指向
call与apply都属于Function.prototype的一个方法,所以每个function实例都有call、apply、bind属性;
call()方法和apply(),bind()方法的作用相同:改变this指向。
call/apply
//示例1
function add(c,d){
return this.a+this.b+c+d;
};
var o = {a:1,b:3};
add.call(o,5,7);//16
add.apply(o,[10,20]) //34
//示例2
function bar(){
console.log(Object.prototype.toString.call(this));
};
bar.call('5');//[object String]
apply / call严格模式
非严格模式
第一个参数:对象(不是对象会转)
如果传入是null 或者 undefinde 就是window;
但是在严格模式下:
如果传入是null 或者 undefinde 就是null 或者 undefinde ;
call 和 apply区别
call 传参扁平
apply 用数组
bind
使用:ie9+
改变this
//示例1
function f(){
return this.a;
};
var g = f.bind({a:'text'});
var o = {a:37,f:f,g:g}
console.log(o.f(),o.g())//37 "text"
//示例2
this.x = 9; //window.x
var module = {
x:81,
getX:function(){return this.x;}
}
module.getX(); //81
var getX = module.getX;//没有运行
getX(); //9 因为是window调用的,this指向window
var getX = module.getX(); //调用的是module 并且运行获得返回值
getX;//81
var boundGetX = getX.bind(module);//更换this
boundGetX(); //81
科里化
function add(a,b,c){
return a+b+c;
}
var func = add.bind(null,100);
func(1,2);//103;100+1+2;
var func2 = func.bind(null,100);//调用之前的func
func2(10);//210;100+100+10
bind 与 new
function foo(){
this.b = 100;
return this.a;
}
var func = foo.bind({a:1});
func();//1
var c = new func();
c//foo?{b: 100} //return 不是对象 就用this 作为返回值。忽略return
bind方法模拟
//是否存在bind,不存在就执行以下方法;
if(!Function.prototype.bind){
//oThis bind的第一个参数
Function.prototype.bind = function(oThis){
//判断当前调用对象 是不是函数
if(typeof this !== 'function'){
//不是函数就报错
throw new TypeError("不是函数啊!")
};
//将bind除了第一个参数外的参数转为数组(浅拷贝)
var aArgs = Array.prototype.slice.call(arguments,1);
fToBind = this;//指的调用的函数
fNOP = function(){};//空函数,后期用来
fBound = function(){
return fToBind.apply(this instanceof fNOP?this:oThis,
aArgs.concat(Array.prototype.slice.call(arguments))//把oThis对象参数加入到aArgs
)
};
fNOP.prototype = this.prototype;//fNOP.prototype 换为调用对象prototype
fBound.prototype = new fNOP();//fBound 原型归fNOP
return fBound;
}
}
arguments
foo.length//返回参数数量
arguments.length//返回实际传参数数量
arguments //类数组
arguments.callee //callee属性是一个指针,指向拥有这个 arguments 对象的函数
//示例
function foo(x,y,z){
console.log('arguments',arguments.length);
arguments[0] = 10;
//返回实际传参数数量
console.log('x',x);
arguments[2]=11;
//参数z没传所以,没有[2]对应z,所以对z不造成影响
console.log('arguments[2]',arguments[2]);
console.log('z',z);
console.log(x,y,z);
arguments.callee === foo;
};
foo(1,2);
//arguments 2
//x 10
//z undefined
//10 2 undefined
arguments严格模式下:
arguments[0] 变成了一个参数,不会改变x的值
arguments.callee 也无法使用。
Object.prototype.toString.call()常见问题
为什么Array、String、Number、Boolean等不能直接调用toString()去判断数据类型?
因为Array、String、Number、Boolean、RegExp、Date等类型都重写了toString(),
如果直接调用则因为自身的原型对象上已有toString()方法,
就不会调用到Object原型对象上的toString()方法了。
为什么不能用Array.prototype.toString.call([1,3,4])去判断数据类型?
因为Array,Function,Date虽然是基于Object进行创建的,
但是他们继承的是Object.toString(),而不是Object.prototype.toString()。
这样子调用的就是Object.toString()。
可以直接Object.prototype.toString,不用call()?
通过call将Array的this上下文切换到Object,从而调用了Object.prototype.toString(),因此返回[object Function]。