2025-02-04 日报 Day87

2025-02-04 日报 Day87

Yuyang 前端小白🥬

今日的鸡汤

在这个世上,一个人想要成功,就一定要去做难一点的事。比如不断地学习,不断地成长,不断地进步。

今日学习内容

1、JS 红皮书 P300-303 第十章:函数

今日笔记

1、this: 另一个特殊的对象是 this,它在标准函数和箭头函数中有不同的行为。
在标准函数中,this 引用的是把函数当成方法调用的上下文对象,这时候通常称其为 this 值(在网页的全局上下文中调用函数时,this 指向 windows)。在箭头函数中,this引用的是定义箭头函数的上下文。下来看下面的例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
window.color = 'red'; 
let o = {
color: 'blue'
};
function sayColor() {
console.log(this.color);
}
sayColor(); // 'red'
o.sayColor = sayColor;
o.sayColor(); // 'blue'

window.color = 'red';
let o = {
color: 'blue'
};
let sayColor = () => console.log(this.color);
sayColor(); // 'red'
o.sayColor = sayColor;
o.sayColor(); // 'red'

有读者知道,在事件回调或定时回调中调用某个函数时,this 值指向的并非想要的对象。此时将回调函数写成箭头函数就可以解决问题。这是因为箭头函数中的 this 会保留定义该函数时的上下文:

1
2
3
4
5
6
7
8
9
10
11
12
function King() { 
this.royaltyName = 'Henry';
// this 引用 King 的实例
setTimeout(() => console.log(this.royaltyName), 1000);
}
function Queen() {
this.royaltyName = 'Elizabeth';
// this 引用 window 对象
setTimeout(function() { console.log(this.royaltyName); }, 1000);
}
new King(); // Henry
new Queen(); // undefined

2、caller: ECMAScript 5 也会给函数对象上添加一个属性:caller。虽然 ECMAScript 3 中并没有定义,但所有浏览器除了早期版本的 Opera 都支持这个属性。这个属性引用的是调用当前函数的函数,或者如果是在全局作用域中调用的则为 null。比如:

1
2
3
4
5
6
7
function outer() { 
inner();
}
function inner() {
console.log(inner.caller);
}
outer();

以上代码会显示 outer()函数的源代码。这是因为 ourter()调用了 inner(),inner.caller指向 outer()。如果要降低耦合度,则可以通过 arguments.callee.caller 来引用同样的值:

1
2
3
4
5
6
7
function outer() { 
inner();
}
function inner() {
console.log(arguments.callee.caller);
}
outer();

3、new.target: ECMAScript 中的函数始终可以作为构造函数实例化一个新对象,也可以作为普通函数被调用。ECMAScript 6 新增了检测函数是否使用 new 关键字调用的 new.target 属性。如果函数是正常调用的,则 new.target 的值是 undefined;如果是使用 new 关键字调用的,则 new.target 将引用被调用的构造函数。

1
2
3
4
5
6
7
8
function King() { 
if (!new.target) {
throw 'King must be instantiated using "new"'
}
console.log('King instantiated using "new"');
}
new King(); // King instantiated using "new"
King(); // Error: King must be instantiated using "new"

4、函数属性与方法: ECMAScript 中的函数是对象,因此有属性和方法。每个函数都有两个属性:length 和 prototype。其中,length 属性保存函数定义的命名参数的个数,如下例所示:

1
2
3
4
5
6
7
8
9
10
11
12
function sayName(name) { 
console.log(name);
}
function sum(num1, num2) {
return num1 + num2;
}
function sayHi() {
console.log("hi");
}
console.log(sayName.length); // 1
console.log(sum.length); // 2
console.log(sayHi.length); // 0

prototype 属性也许是 ECMAScript 核心中最有趣的部分。prototype 是保存引用类型所有实例方法的地方,这意味着 toString()、valueOf()等方法实际上都保存在 prototype 上,进而由所有实例共享。这个属性在自定义类型时特别重要。(相关内容已经在第 8 章详细介绍过了。)在 ECMAScript 5中,prototype 属性是不可枚举的,因此使用 for-in 循环不会返回这个属性。
函数还有两个方法:apply()和 call()。这两个方法都会以指定的 this 值来调用函数,即会设置调用函数时函数体内 this 对象的值。apply()方法接收两个参数:函数内 this 的值和一个参数数组。第二个参数可以是 Array 的实例,但也可以是 arguments 对象。来看下面的例子:

1
2
3
4
5
6
7
8
9
10
11
function sum(num1, num2) { 
return num1 + num2;
}
function callSum1(num1, num2) {
return sum.apply(this, arguments); // 传入 arguments 对象
}
function callSum2(num1, num2) {
return sum.apply(this, [num1, num2]); // 传入数组
}
console.log(callSum1(10, 10)); // 20
console.log(callSum2(10, 10)); // 20

到底是使用 apply()还是 call(),完全取决于怎么给要调用的函数传参更方便。如果想直接传 arguments对象或者一个数组,那就用 apply();否则,就用 call()。
apply()和 call()真正强大的地方并不是给函数传参,而是控制函数调用上下文即函数体内 this值的能力。考虑下面的例子:

1
2
3
4
5
6
7
8
9
10
11
window.color = 'red'; 
let o = {
color: 'blue'
};
function sayColor() {
console.log(this.color);
}
sayColor(); // red
sayColor.call(this); // red
sayColor.call(window); // red
sayColor.call(o); // blue

使用 call()或 apply()的好处是可以将任意对象设置为任意函数的作用域,这样对象可以不用关心方法。
ECMAScript 5 出于同样的目的定义了一个新方法:bind()。bind()方法会创建一个新的函数实例,其 this 值会被绑定到传给 bind()的对象。比如:

1
2
3
4
5
6
7
8
9
window.color = 'red'; 
var o = {
color: 'blue'
};
function sayColor() {
console.log(this.color);
}
let objectSayColor = sayColor.bind(o);
objectSayColor(); // blue
此页目录
2025-02-04 日报 Day87