7.Object.md

Object

Overview

  1. this
  2. class {}
  3. Prototype
  4. Inheritance vs Behavior Delegation (继承 vs 代理)

this keyword

this 关键字最大的作用是, 提升了代码的复用性和赋予函数的多态性(通过使用this获取不同的context, 从而函数得到不同的返回)

implicitly && Explicit Binding

隐式绑定

1
2
3
4
5
6
7
8
9
var workspace = {
teacher: 'Kyle',
ask (quetion) {
// this显示的指定到了,调用的对象上, 也就是workspace
console.log(this.teacher, quetion);
}
}

workspace.ask('Why?');

代码复用:让同一个函数在不同的调用条件下得到不同的结果。但是他们引用的都是一个函数。节省了内存, 优化性能。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
function ask(que) {
console.log(this.teacher, que);
}

var workspace1 = {
teacher: 'Kyle',
ask,
}
var workspace2 = {
teacher: 'Suzy',
ask,
}

workspace1.ask('Why?');
workspace2.ask('Why?');

显式绑定: call/apply/bind: 第一个参数就是函数的this.

new keyword

new是第四种调用函数的方式。

问题: new关键字做了哪四件事?

  1. 创建一个新的空对象
  2. 链接这个对象到另一个对象
  3. 和this调用这个函数并且设置一个新的对象
  4. 如果这个函数没有返回一个对象,那么把this返回
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    function newOperator(ctor){
    if(typeof ctor !== 'function'){
    throw 'newOperator function the first param must be a function';
    }
    // ES6 new.target 是指向构造函数
    newOperator.target = ctor;
    // 1.创建一个全新的对象,
    // 2.并且执行[[Prototype]]链接
    // 4.通过`new`创建的每个对象将最终被`[[Prototype]]`链接到这个函数的`prototype`对象上。
    var newObj = Object.create(ctor.prototype);
    // ES5 arguments转成数组 当然也可以用ES6 [...arguments], Aarry.from(arguments);
    // 除去ctor构造函数的其余参数
    var argsArr = [].slice.call(arguments, 1);
    // 3.生成的新对象会绑定到函数调用的`this`。
    // 获取到ctor函数返回结果
    var ctorReturnResult = ctor.apply(newObj, argsArr);
    // 小结4 中这些类型中合并起来只有Object和Function两种类型 typeof null 也是'object'所以要不等于null,排除null
    var isObject = typeof ctorReturnResult === 'object' && ctorReturnResult !== null;
    var isFunction = typeof ctorReturnResult === 'function';
    if(isObject || isFunction){
    return ctorReturnResult;
    }
    // 5.如果函数没有返回对象类型`Object`(包含`Functoin`, `Array`, `Date`, `RegExg`, `Error`),那么`new`表达式中的函数调用会自动返回这个新的对象。
    return newObj;
    }

default binding

非严格模式下, this指向外部this。

严格模式下,this指向undefined.

尽量避免使用默认绑定。

binding precedence : this判定优先级

  1. Is the function called by new?
  2. Is the function called by call or apply?
  3. Is the function called by on a context object?
  4. Default: global object(strict this pointing undefined)

arrow function and lexical this

箭头函数没有自己的this, 此时, this会往外部找, 直到global object.

resolving this in arrow function

函数外部指的是在定义这个函数时的外部, 下面这个例子,定义函数的位置在workshop对象内,所以,this,并不指向workshop.而是workshop的外部, 也就是window.

1
2
3
4
5
6
7
8
9
10
var workshop = {
teacher: 'Kyle',
ask: (que) => {
console.log(this, que);
}
}

workspace.ask('What?');

workspace.ask.call(workshop, 'Still on this');

实际上, new关键字是一个语法糖: 我要调用这个函数, 在一个新的上下文调用。

class keyword

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
class Workshop {
constructor(teacher) {
this.teacher = teacher;
}
ask (que) {
console.log(this.teacher, que);
}
}

// extends方法, prototype
class AntherWorkshop extends Workshop {
speakUp (msg) {
this.ask(msg);
}

ask1 (msg) {
super.ask(msg); // 调用父级方法
}

ask (msg) {
console.log('children method');
}
}



var deepJs = new Workshop('Kyle');
var reactJs = new Workshop('Suzy');

deepJs.ask('what');
reactJs.ask('what');

fixing in Classes

1
2
3
4
5
6
7
8
9
10
11
12
13
class workshop {
constructor (teacher) {
this.teacher = teacher;
this.ask = que => {
console.log(this.teacher, que);
}
}
}


var deepJs = new workshop('Kyle');

setTimeout(deepJs.ask, 100, 'what?');