一张图说明:
再一步说明:
- 对象的隐式原型 === 构造函数的显示原型
- 构造函数的显示原型 prototype ,是一个对象,包括属性 constructor 和
__proto__
。__proto__
指向 Object.prototype。 - 构造函数的隐式原型
__proto__
指向 Function.prototype。
You do not know what you do not know.
__proto__
。__proto__
指向 Object.prototype。__proto__
指向 Function.prototype。作为对象属性的普通函数,this 绑定为该对象。
作为回调函数的普通函数,this 绑定为被触发对象。
除了 call、apply、bind 以外能指定 this 参数,其余调用普通函数的地方,this 都绑定为全局对象。
箭头函数没有自己的 this,也就是说没有自己的定义域。进一步说,就是会绑定定义时上层代码块的 this。
function Timer() {
this.s1 = 0;
this.s2 = 0;
// 箭头函数
setInterval(() => this.s1++, 1000);
// 普通函数
setInterval(function () {
this.s2++;
}, 1000);
}
假如 var timer = new Timer();
此时 timer.s1 可以正常绑定,.s2 被绑定到了全局对象。
再假如,直接调用函数 Timer(),此时 s1 也被绑定到了全局对象。
var x = 10;
let foo = {
x: 20,
// Dynamic `this`.
bar() {
return this.x;
},
// Lexical `this`.
baz: () => this.x,
qux() {
// Lexical this within the invocation.
let arrow = () => this.x;
return arrow();
},
};
console.log(
foo.bar(), // 20, from `foo`
foo.baz(), // 10, from global
foo.qux(), // 20, from `foo` and arrow
);
看到一道题有点意思:
function sum(...lastArgs) {
var callback = function(...args) {
return sum(...[ ...lastArgs, ...args ]);
};
callback.sumof = function() {
return lastArgs.reduce((aggregated, number) => aggregated + number, 0);
};
return callback;
}
promise 用来执行异步任务。
通过链式调用可以一步接一步的执行任务,那么为什么还要结合生成器呢?
比如这样的:
new promise(...).then(val1 => {resolve(val2)}).then(val2 => resolve()).catch();
变成这样的:
function* xx() {
const val1 = yield new promise(...);
const val2 = yield new promise(...);
}
最终产生了 async?
变成这样:
async function xx() {
const val1 = await new promise(...);
const val2 = await new promise(...);
return
}
答案是用【同步写法】执行【异步任务】,这样看代码看的更清楚。而且使用了 async,还包括了自动执行,可以直接调用xx()来得到结果。
函数调用共有4种类型
方法调用模式【作为对象属性], this 绑定为动态执行时的对象。因为方法可以被单独应用,所以this随着变化会变化。
值得注意的是箭头函数,作为方法时 this 绑定到了 window 对象上了。
因为内部箭头函数方法会在起初声明时就绑定不再变化。
函数调用模式,this 绑定为 Window 对象或 undefined,取决于是否 “use strict”。
构造器(构造函数)调用模式,this 绑定为动态运行时实际创建的对象。
值得注意的是箭头函数,此时 this 绑定到了 新创建的这个对象上。
this,arguments 可被指定、每个函数都有的的 apply /call 调用模式,2者区别在于参数传递,前者传递一个参数数组,后者可传递多个参数,作为参数列表。