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)//2
var baz=new bar(3);
console.log(obj1.a)//?2
console.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)//obj
this.test();//window
this.test2();//obj
// test()//window
// test2()//window
},
test4:function() {
console.log(this)//obj
var a=()=>{
console.log(this)
}
a()//obj
this.test()//window
return 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)//obj
var a=()=>{
console.log(this)
}
a()//obj
this.test()//window
return 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);//1
console.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:Global
console.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.name
obj1.fn2();//window 箭头函数,指向父作用域,父环境GO
obj1.fn2.call(obj2);//window 箭头函数所以调用规则全部无效,与父环境一样
obj1.fn3()();//window 返回函数再运行,相当于var a=function() { console.log(this.name) }函数,再运行a(),独立调用,指向window
obj1.fn3().call(obj2);//2 的this指向obj2,相当于obj2.name=2,再打印obj2.name为2
obj1.fn3.call(obj2)();//window 函数fn3的this指向obj2,再执行返回内部函数,但return的函数是新的函数,有新的作用域,返回函数再运行,独立调用,默认绑定,指向window
obj1.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();//2
getName();//4
Foo().getName();//1
getName();//1
new Foo.getName();//2
new Foo().getName();//3
new 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();//2
getName();//4
Foo().getName();//1
getName();//1
new Foo.getName();//2
new Foo().getName();//3
new new Foo().getName();//3
详解见 4-三目运算、对象克隆、浅拷贝、深拷贝的作业