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 ) } } } }