this和对象原型

this是一个很特别的关键字,被自动定义在所有函数的作用域中

// foo.count 是0,字面理解是错误的

function foo(num) {

console.log("foo:"+ num);

this.count++;

}

foo.count = 0;

var i;

for(i=0;i<10;i++){

if(i>5){

foo(i)

}

}

console.log(foo.count)  //0

          

// 使用词法作用域解决问题

function foo(num) {

console.log("foo:"+ num);

data.count++;

}

var data = {

count:0

};

var i;

for(i=0;i<10;i++){

if(i>5){

foo(i)

}

}

console.log(data.count);  // 4

// 用foo标识符来替代this来引用函数对象,回避了this 的问题,完全依赖于变量foo的词法作用域。

function foo(num) {

console.log("foo:"+ num);

foo.count++;

}

foo.count = 0

var i;

for(i=0;i<10;i++){

if(i>5){

foo(i)

}

}

console.log(foo.count) //4

    //强制this 指向foo函数对象

function foo(num) {

console.log("foo:"+num);

this.count++

}

foo.count = 0;

var i;

for(i=0; i< 10; i++){

if(i>5){

foo.call(foo,i);

}

}

console.log(foo.count)  //4

this是在运行是 绑定的,并不是在编写时绑定的,它的上下文取决于函数调用时的各种条件,this的绑定和和函数声明的位置没有任何关系,只取决于函数调用的方式。

this全面解析

调用栈与调用位置

function baz(){

//当前调用栈是:baz

// 因此,当前的调用中位置是全局作用域

console.log("baz");

bar(); // <--bar的调用位置

}

function bar(){

//当前的调用栈是: baz-> bar

// 因此,当前调用位置在baz

console.log("bar);

foo(); // <-- foo 的调用位置

}

function foo(){

//当前的调用栈是: baz-> bar->foo

// 因此,当前调用位置在bar

console.log("foo");

}

baz(); // <-- baz 的调用位置

只有运行在非strict mode 下,默认绑定才能绑定到全局对象。

对象属性引用链中只有最顶层或者说最后一层灰影响调用位置。

function foo() {

console.log(this.a);

}

var obj2 = {

a: 42,

foo:foo

};

var obj1 = {

a:2,

obj2: obj2

};

obj1.obj2.foo(); // 42

硬绑定的典型应用场景就是创建一个包裹函数,传入所有的函数并返回接收到的所有的值。

function foo(something){

console.log(this.a,something);

return this.a + something;

};

var obj = {

a:2

};

var bar = function() {

return foo.apply(obj,arguments);

};

var b = bar(3) ; // 2 3

console.log(b)  // 5

另一种方法是创建一个i可以重复使用的辅助函数

function foo(something){

console.log(this.a, something);

return this.a + something;

}

// 简单的辅助绑定函数

function bind(fn,obj){

return function(){

return fn.apply(obj,arguments);

};

}

var obj = {

a:2

}

var bar = bind(foo,obj);

var b = bar(3); // 2 3

console.log(b) // 5

ES5 中提供了内置的方法 Function.prototype.bind,  bind(..) 会返回一个硬编码的新函数,它会

把参数设置为this的上下文并调用原始函数。

function foo(something){

console.log(this.a, something);

return this.a + something;

}

var obj = {

a:2

}

var bar = foo.bind(obj);

var b = bar(3); // 3 5

console.log(b) // 5

API 调用的 上下文

function foo(el){

console.log(el,this.id);

}

var obj = {

id: "awesome'

}

// 调用 foo(..)时把this 绑定到obj

[1,2,3].forEach(foo,obj);

// 1 awesome 2 awesome 3 awesome

new可以影响函数调用时this 绑定行为的方法。

function foo(a){

this.a = a;

}

var  bar = new foo(2);

console.log(bar.a); // 2

判断this

1.函数是否在new 中调用(new 绑定)? 如果是的话this 绑定的是新创建的对象。

var bar = new foo();

2.函数是否通过call , apply (显示绑定) 或者硬绑定调用? 如果是的话,this的绑定时指定的对象。

va bar = foo.call(obj2)

3.函数是否在某个上下文对象中调用(隐式绑定) ? 如果是的话,this 的绑定时在那个上下文。

var bar = obj1.foo()

4.如果都不是的话,使用默认绑定。如果在严格模式下,就绑定到undefined,否则绑定到全局对象上。

var bar = foo();

软绑定

function foo(){

console.log("name:" + this.name);

}

var obj = {name: "obj"},

obj2 = {name: "obj2"},

obj3 = {name: "obj3"},

obj3 = {name: "obj3"};

var foo0BJ = foo.softBind(obj);

foo0BJ();  // name:obj

obj2.foo = foo.softBind(obj);

obj2.foo(); // name:obj3 <--看!

setTimeout(obj2.foo,10);

// name:obj <--- 应用了软绑定

05-26 22:37