this 的取值是执行上下文环境的一部分,每次调用函数,都会产生一个新的执行上下文环境。当你在代码中使用了 this,这个 this 的值就直接从执行的上下文中获取了,而不会从做用域链中搜寻vue
this
指向window
this
永远指向window
;console.log(this===window)//true
this
也是指向window
(注意严格模式下为undefined
)var x = 10; //window.x function foo(){ console.log(this); //window console.log(this.x); //10 } foo(); //foo.call(window),window.foo()
this
指向调用它的该对象注意这里声明用的不是let
,因此obj
没有本身的块级做用域;闭包
var obj = { x: 10, foo: function () { console.log(this); //{x: 10, foo: ƒ} console.log(this.x); //10 } }; obj.foo();
this
是会指向window
var obj = { x: 10, foo: function () { console.log(this) //{x: 10, foo: ƒ} function f(){ console.log(this); //Window console.log(this.x); //10 console.log(obj.x===window.x) //true,obj===window.obj }f(); } } obj.foo();
函数虽然是在obj.foo
中定义的,但它仍然只是个普通函数。做用域的特性,本身内部没有就会向父函数里找,父函数没有,就会向更上级找,直到最终找到或找不到为止。
若是foo
方法不做为对象被调用,那么就指向调用它的那个app
var obj = { x: 10, foo: function () { console.log(this); //Window console.log(this.x); //10 } }; var fn = obj.foo; //window.fn fn();
构造函数就是由一个函数 new
出来的对象,通常构造函数的函数名首字母大写,例如像 Object
,Function
,Array
这些都属于构造函数函数
this
就表明它即将 new
出来的对象。function Foo(){ this.x = 10; console.log(this); //Foo {x:10} } var foo = new Foo(); console.log(foo.x); //10
Foo
函数,而不是 new Foo()
,这时候 Foo()
就变成普通函数。function Foo(){ this.x = 10; console.log(this); //Window } var foo = Foo(); console.log(foo.x);//Uncaught TypeError: Cannot read property 'x' of undefined
prototype
属性构造函数的prototype
属性也就是原型对象oop
function Foo(){ this.x = 10; this.xx=function(){ console.log(this) //Foo {x: 10, xx: ƒ} } } Foo.prototype.getX = function () { console.log(this); //Foo {x: 10, xx: ƒ} console.log(this.x); //10 } var foo = new Foo(); foo.getX();
在整个原型链中,this
表明的也是当前对象的值,指向构造函数。this
call,bind,apply
调用var obj = { x: 10 } function foo(){ console.log(this); //{x: 10} console.log(this.x); //10 } //foo.call(obj)=obj.foo;f.foo.call(obj)=obj.foo。 //call和apply改变了函数的this上下文后便执行该函数, 而bind则是返回改变了上下文的一个函数 foo.call(obj); //call(obj,arg1,arg2) foo.apply(obj); //apply(obj,[arg1,arg2]) foo.bind(obj)(); //还要再调用一下,多用于绑定回调函数
call,bind,apply
能够改变this
的指向,this
的值就取传入的对象的值。第一个参数若是为undefined,null
或空就至关因而window
。prototype
函数体内的this
对象,就是定义时所在的对象,而不是使用时所在的对象code
var obj = { x: 10, foo: function() { var fn = () => { return () => { return () => { console.log(this); //Object {x: 10, foo: ƒ} console.log(this.x); //10 } } } fn()()(); } } obj.foo();
vue
的this
注意,不该该使用箭头函数来定义 method
函数 (例如 plus: () => this.a++
)。理由是箭头函数绑定了父级做用域的上下文,因此 this
将不会按照指望指向 Vue
实例,this.a
将是 undefined
。
为了弄清楚这个,咱们先来弄懂这些:
咱们在使用vue
的时候总会先new vue({})
,那么就是说vue
实际上是一个构造函数。component
function A(){ this.a=3; this.aa={ aaa:function(){ console.log(this,'this') //指向aaa它本身这个函数 } } } function A(){ this.a=3; this.aa={ aaa:()=>{ console.log(this,'this')//箭头函数指向A这个函数,非箭头函数指向aaa这个函数 } } } var b=new A() b.aa.aaa()//箭头函数一开始就被定义指向了A,因此即便b是A的实例,this也不会指向b,而仍是指向一开始生成被定义的A
function add(){ //正常不是箭头函数的 console.log(this===a) // true } var a = {}; a['add'] = function(args){ add.apply(a,[args]); //a.add();add的this就指向调用者a }; a.add() //有箭头函数的,用`bind,call,apply`无效 var bind=function(fn,vm){ return function(){ return fn.apply(vm,arguments) } } var a={'_a':3}; var add=()=>{ console.log(this===a)//false } a['add']=bind(add,a) a.add()
那么下面咱们来看它源码:对象
export function bind (fn: Function, ctx: Object): Function { //兼容重写bind方法 function boundFn (a) { const l: number = arguments.length return l ? l > 1 ? fn.apply(ctx, arguments) : fn.call(ctx, a) : fn.call(ctx) } boundFn._length = fn.length return boundFn } function initMethods (vm: Component) { const methods = vm.$options.methods if (methods) { for (const key in methods) { vm[key] = methods[key] == null ? noop : bind(methods[key], vm) //若是是箭头函数此处用不了bind,改不了this指向,(fn,vm)/vm.fn,this就指向vm if (process.env.NODE_ENV !== 'production' && methods[key] == null) { warn( `method "${key}" has an undefined value in the component definition. ` + `Did you reference the function correctly?`, vm ) } } } }