this绑定方式
1.默认绑定:window;独立调用也指向window, test()
2.隐式绑定:对象调用 obj.foo() :谁调用就指向谁;(隐式丢失)
3.显式绑定:显示绑定调用 ,apply,bind obj.call(obj),that保存
4.new绑定规则;new foo();
5.箭头函数绑定()=> 父作用域
调用方式
独立调用、自调用、函数调用
对象调用
显示绑定调用:call调用
总结
this是个对象,指向对象,只在运行时产生,不运行不产生
this是为了把方法、属性挂载到对象上

function foo(){console.log(this.a)}var obj1={a:2,foo:foo}var obj2 = {a:3,foo:foo}obj1.foo();obj2.foo();obj1.foo.call(obj2);obj2.foo.call(obj1);

显示绑定优先级大于隐式绑定
new绑定

function foo(b){this.a=b;}var obj1={ };var bar=foo.bind(obj1);bar(2)console.log(obj1.a)//2var baz=new bar(3);console.log(obj1.a)//?2console.log(baz.a)//?3
new优先等级大于bind,new bar也隐式有一个绑定,大于bind绑定,从obj1到了baz
bar和foo不是同一个函数,this指向不一样
箭头函数
that保存
var a=0;function foo(){var that=this;console.log(this);function test(){console.log(that);}test();//obj that保存了this,虽然是独立调用,但这里是显式改变了this的指向}var obj = {a:1,foo:foo}obj.foo();


效果相当于test.call(this)
var a = 0;function foo() {// var that = this;console.log(this);function test() {console.log(this);}test.call(this);}var obj = {a: 1,foo: foo}obj.foo();
箭头函数()=>
箭头函数没有、不存在this,没有this指向,向父作用域寻找,用父作用域的this指向
箭头函数内部没有this指向,箭头函数是this指向是由外层函数的作用域来决定的
var a = 0;function foo() {console.log(this)// var that = this;// console.log(this);// function test() {// console.log(this);// }var test=()=>{console.log(this);}test();}var obj = {a: 1,foo: foo}obj.foo();//obj调用foo,foo的this是obj,箭头函数是由外层函数作用域链决定的

var test=()=>{console.log(this);}var test2=function() {console.log(this)}var obj={test:test,test2:test2,t:function() {console.log('4')},test3:function() {console.log(this)//objthis.test();//windowthis.test2();//obj// test()//window// test2()//window},test4:function() {console.log(this)//objvar a=()=>{console.log(this)}a()//objthis.test()//windowreturn this.test; //window// return test;//window 与this.test的结果一样}}obj.test3()obj.test4()();
箭头函数只与箭头函数声明时的作用域有关,与运行时的无关?
var test = () => {console.log(this);}var test2 = function () {console.log(this)}var obj = {test: test,test2: test2,t: function () {console.log('4')},test3: function () {console.log(this)//objvar a=()=>{console.log(this)}a()//objthis.test()//windowreturn this.test; //window}}obj.test3()();
显示、默认绑定无效

var a = 0;function foo() {// var that = this;console.log(this);// function test() {// console.log(this);// }var test = () => {console.log(this);}return test;}var obj1 = {a: 1,foo: foo}var obj2 = {a:2,foo:foo}obj1.foo()();//默认绑定规则(独立调用对箭头函数)无效;var bar=foo().call(obj2);//显式绑定规则 无效; 如果call生效,变成window与obj2,但call没有生效,箭头函数永远与父作用域有关,与别的无关foo.call(obj2)();//foo的this变成了obj2,所有test的this随之改变,箭头函数没有this,向父作用域上找this

隐式绑定无效

var obj1={a:1,foo:()=>{console.log(this);}}obj1.foo()//隐式绑定规则无效
只有函数有AO,对象object不能运行,没有AO,对象没有作用域,作用域链向上找是GO,this就是window
this,箭头函数AO里面没有this,箭头函数没有arguments
里面this,外面this完全一样
new不能实例箭头函数
var foo=()=>{console.log(this);}new foo();
箭头函数不允许当构造函数来使用,因为箭头函数没有this,返回不了this,并且new时也改变不了this,所以箭头函数不能用this
es6简化写法,两个写法等效,当键名、方法名一致时可以简写
总结
箭头函数:所有绑定规则全部不适用;
箭头函数的this: 取决于父亲环境中的this 指向;(=>不存在this指向);
obj没有this
var obj1={a:1,foo:()=>{console.log(this);}}obj1.foo()//隐式绑定规则无效
如果对象obj1有this,就打印obj1了,不会打印window
只有函数有AO,对象object不能运行,没有AO,对象没有作用域,作用域链向上找是GO,this就是window
var obj1={//obj1.a:1,a:1,foo:function(){console.log(this.a);}}obj1.foo()//1
foo函数的this.a,是函数foo的this,不是obj1的this,为什么this.a能调用obj1里的a?
对象字面量相当于
var obj1=new Object();obj1.a=1;obj1.foo=function() {console.log(this.a);//1console.log(obj1.a);//1}obj1.foo()//因为函数调用使得foo函数的this指向预编译阶段变成了obj1,再执行/*预编译:foo的this指向obj1执行:函数执行,this.a变成obj1.a*/
而不是
var obj1={this.a:1,this.foo:function(){console.log(this.a);}}obj1.foo()//隐式绑定规则无效
构造函数
function Car(){}var car=new Car();console.log(typeof car)console.log(typeof {})console.log(car)//Scopes:Globalconsole.log({})//Scopes:无属性

console.log(Car.prototype)

函数声明就有.scope,存有GO
var test=()=>{}console.log(test.prototype)
综合示例


var name = 'window';var obj1 = {name: '1',fn1: function () {console.log(this.name);},fn2: () => console.log(this.name),fn3: function () {return function () {console.log(this.name)}},fn4: function () {return () => console.log(this.name)}}var obj2 = {name: '2'}obj1.fn1();obj1.fn1.call(obj2);obj1.fn2();obj1.fn2.call(obj2);obj1.fn3()();obj1.fn3().call(obj2);obj1.fn3.call(obj2)();obj1.fn4()();obj1.fn4().call(obj2);obj1.fn4.call(obj2)();
var name='window';var obj1={name : '1',fn1:function(){console.log(this.name);},fn2:()=>console.log(this.name),fn3:function() {return function() {console.log(this.name)}},fn4: function() {return ()=>console.log(this.name)}}var obj2={name: '2'}obj1.fn1();//1 对象调用,隐式绑定,指向调用对象obj1.fn1.call(obj2);//2 call调用,显示绑定,预编译中this指向obj2,再执行,this.name相当于obj2.nameobj1.fn2();//window 箭头函数,指向父作用域,父环境GOobj1.fn2.call(obj2);//window 箭头函数所以调用规则全部无效,与父环境一样obj1.fn3()();//window 返回函数再运行,相当于var a=function() { console.log(this.name) }函数,再运行a(),独立调用,指向windowobj1.fn3().call(obj2);//2 的this指向obj2,相当于obj2.name=2,再打印obj2.name为2obj1.fn3.call(obj2)();//window 函数fn3的this指向obj2,再执行返回内部函数,但return的函数是新的函数,有新的作用域,返回函数再运行,独立调用,默认绑定,指向windowobj1.fn4()();//1 返回箭头函数再运行,箭头函数的父作用域,父环境,父函数是fn4,fn4是通过函数调用,this指向obj1,箭头函数改变不了this值指向,只能通过父函数this指向来改变/*1 obj1.fn4() fn4预编译this变成obj1,函数执行,执行结果返回箭头函数,箭头函数再执行,箭头函数的this就是父函数fn4的this如果不返回箭头函数,就是函数调用,与obj1.fn3()()结果一样*/obj1.fn4().call(obj2);//1 返回箭头函数再运行,call不改变箭头函数的this,与上面意思一样obj1.fn4.call(obj2)();//2 fn4函数的this指向obj2,再运行,返回箭头函数,再运行箭头函数,fn4的this指向obj2,所以内部箭头函数的this也是2
obj1.fn3()(); 返回函数再运行,相当于var a=function() { console.log(this.name) }函数,再运行a(),独立调用,指向window
obj1.fn3().call(obj2)的this指向obj2,相当于obj2.name=2,再打印obj2.name为2
obj1.fn3.call(obj2)(),函数fn3的this指向obj2,但return的函数是新的函数,有新的作用域,返回函数再运行,独立调用,默认绑定,指向window
obj1.fn4()(),返回箭头函数再运行,箭头函数的父作用域,父环境,父函数是fn4,fn4是通过函数调用,this指向obj1
obj1.fn4().call(obj2); 返回箭头函数再运行,call不改变箭头函数的this,与上面意思一样
obj1.fn4.call(obj2)(); fn4函数的this指向obj2,再运行,返回箭头函数,再运行箭头函数,fn4的this指向obj2,所以内部箭头函数的this也是2



构造函数题目


function Foo(){getName=function(){alert(1);};return this;}Foo.getName=function() {alert(2);};Foo.prototype.getName = function() {alert(3);};var getName=function() {alert(4);};function getName() {alert(5); }Foo.getName();//2getName();//4Foo().getName();//1getName();//1new Foo.getName();//2new Foo().getName();//3new new Foo().getName();//3
()优先级最高
function Foo() {getName = function () {console.log(1); };return this;}Foo.getName = function () { console.log(2) };Foo.prototype.getName = function () { console.log(3) };var getName = function () { console.log(4) };function getName() { console.log(5) }Foo.getName();//2getName();//4Foo().getName();//1getName();//1new Foo.getName();//2new Foo().getName();//3new new Foo().getName();//3
详解见 4-三目运算、对象克隆、浅拷贝、深拷贝的作业
