This 漫谈

by 小鱼二

2016年10月27日

参考:

  • <<你不知道的 JavaScript 上>>
  • http://www.cnblogs.com/xxcanghai/p/5189353.html

一道常被人轻视的前端JS面试题

为什么要使用 this

function say() {
    console.log('I am ' + this.name.toUpperCase());
}

function say2(person) {
    console.log('I am ' + person.name.toUpperCase());
}

var me = {
    name: 'Yanqi'
};

var you = {
    name: 'little fish'
};


say.call(me);
say.call(you);

say2(me);
say2(you);


this 提供了一种更好的方式来隐式'传递'一个对象引用.

使得 API 的设计更加简洁且易于复用

 

显示的传递上下文对象会随着项目的复杂变得混乱.

在介绍对象和原型的时候, 函数可以自动引用合适的上下文对象很重要 .

 

关于 this 的误解

1. 指向函数自身

2. 作用域指向函数的作用域

function foo() {
    this.count += 1;
}

foo.count = 2;
var count = 1;

foo();

console.log(foo.count);
console.log(count);
function foo() {
    var a = 1;
    bar();
}

function bar() {
    console.log(this.a);
}

bar();

This 是什么

  • this 的绑定和函数的声明位置没有关系, 只取决于函数的调用方式
  • this 即 函数的调用者

调用位置

函数的调用位置即被调用的位置, 而不是声明的位置

方法: 分析调用栈

 

function baz() {
    bar();
}

function bar() {
    foo();
}

function foo() {
    console.log('foo');
}

baz();

绑定规则

  • 默认绑定
  • 隐式绑定
  • 显示绑定
  • new 绑定
  • 优先级

隐式绑定: 独立函数调用

function foo() {
    console.log(this.a);
}

function foo2() {
    "use strict";

    console.log(this.a);
}

var a = 1;

foo();
foo2();

注意区分 严格模式

隐式绑定

var name = 'global name';

function foo() {
    console.log(this.name);
}

var obj = {
    name: 'Yanqi',
    foo: foo
};

var obj2 = {
    name: 'litte fish',
    foo: foo
}

obj.foo();
obj2.foo();


var bar = obj1.foo;

bar();

function doFoo(fn) {
    fn();
}

doFoo(obj.foo);

注意隐式丢失

显示绑定

call/apply/bind

function foo() {
    console.log(this.name);
}

var name = 'global name';

var obj = {
    name: 'Yanqi'
}

foo();
foo.call(obj);
foo.call();

var bar = foo.bind(obj);
bar();

new 绑定

使用 new 来调用函数, 都发生了什么

  • 创建一个全新的对象
  • 这个对象会被执行[[prototype]]链接
  • 这个全新的对象会绑定到函数调用的 this
  • 如果函数没有其他的返回值, 那么返回这个新对象
function foo(a) {
    this.a = a;
}

var bar = new foo(1);
console.log(bar.a);

优先级

function foo() {
    console.log(thi.a);
}
var a = 0;
var obj1 = {a: 1, foo: foo};
var obj2 = {a: 2, foo: foo};

obj1.foo();
obj1.foo.call(obj2);

function foo(a) {
    this.a = a;
}

var obj1 = {foo: foo};

var obj2 = {};

obj1.foo(2);
obj1.a;


obj1.foo.call(obj2, 3);
obj1.a;
obj2.a;

var bar = new obj1.foo(4);
obj1.a;
bar.a;

new 绑定

显示绑定

隐式绑定

默认绑定

箭头函数....

箭头函数不适用 this 的四种标准

根据外层的作用域来决定 this

function foo() {
    return (a) => {
        console.log(this.a);
    }
}

var obj1 = {a:2};
var obj2 = {a:3};

var bar = foo.call(obj1);
bar.call(obj2); 

总结

  • 找到函数的直接调用位置
  • 判断 this 的绑定对象
    • new?
    • call/apply/bind 显示绑定
    • 上下文对象调用
    • 默认: 区分严格模式

This 漫谈

By xy2

This 漫谈

  • 2,085