知识点杂记
for in 和 for of 的区别
- 首先,
for in
遍历的是对象的属性名(key),for of
遍历的是值 for of
只能用于遍历迭代对象,如数组、字符串、map
、set
等,因此不能用于遍历对象for in
用于遍历对象的所有可枚举属性,虽然也可以遍历数组,但是不推荐用来遍历数组,因为for in
还会遍历原型的方法和属性,且遍历顺序可能和预想的不一样for in
在遍历对象属性时可以使用obj.hasOwnProperty(key)
来判断是否是该对象的属性,而不是从原型继承而来的。
https://www.jianshu.com/p/c43f418d6bf0
null 和 undefined
在 JS 中,将一个变量赋值为 null
和 undefined
几乎没有什么区别,它们都是虚值(falsy),在判断语句中都会被转为 false
。
虽然它们非常类似,但是还是有一些区别的:
null
null
表示 没有对象,即该处没有值。典型的用法是:
-
作为函数的参数,表示该函数的参数不是对象。
-
作为对象原型链的终点
Object.getPrototype(Object.prototype); // null
undefined
undefined
表示 缺少值,即是此处可能会有一个值,但是还没有定义。典型语法是:
- 变量被声明了,但是没有赋值时,就等于
undefined
- 调用函数时,应该提供的参数没有提供,该参数就等于
undefined
- 对象没有赋值的属性,该属性的值为
undefined
- 函数没有返回值时,默认返回
undefined
var i;
i // undefined
function f(x){console.log(x)}
f() // undefined
var o = new Object();
o.p // undefined
var x = f();
x // undefined
综合讨论
综上,我们可以知道:
null
表示一个值被定义了,定义为 "空值"undefined
表示一个不存在的定义
因此设置一个值为 null
是合理的,如:obj.val = null;
但是设置一个值为 undefined
是不合理的,如 obj.val = undefined;
,因为在我们定义 obj.val
之前,我们调用 obj.val
同样能够得到 undefined
,这样做不是多此一举了吗。
因此,任何一个存在引用的变量值为 undefined
都是一件错误的事。
这样,判断一个值是否存在,就可以使用 obj.val === undefined
。
在一些使用广泛的库(比如jQuery)中的深度拷贝函数会忽略 undefined
而不会忽略 null
,也是针对这个语义的理解。
REF:阮一峰博客
this 指向
函数的调用方式决定了 this
的值(运行时绑定)。
ES5 引入了 bind
方法来设置函数的 this
的值,ES2015 引入了箭头函数,箭头函数不提供自身的 this
绑定,this
的值将保持为闭合词法上下文的值。
可以使用 globalThis
来获取全局对象,无论代码是否在当前上下文中运行。
函数上下文
在函数内部,this
的值取决于函数被调用的方式。
在严格模式下,如果进入执行环境时没有设置 this
的值,this
会保持为 undefined
,如:
function f2() {
"use strict";
return this;
}
f2() === undefined; // true
function f1() {
return this;
}
f1() === window; // 在浏览器中,全局对象是 window
f1() === globalThis; // 在 Node 中
类上下文
this
在 类 中的表现与在函数中类似,因为类本质上也是函数。
在类的构造器中, this
是一个常规对象。类中所有非静态的方法都会被添加到 this
的原型中:
class Example {
constructor() {
const proto = Object.getPrototypeOf(this);
console.log(Object.getOwnPropertyNames(proto));
}
first() {}
second() {}
static third() {}
}
new Example(); // ['constructor', 'first', 'second']
箭头函数
在箭头函数中,this
与封闭词法环境的 this
保持一致,且一旦设置,就不会被 call
、bind
、apply
等方法修改。
如:
function foo1() {
return this;
}
let foo2 = () => this;
let obj = {foo1: foo1, foo2: foo2};
//foo1 返回的 this 为 obj,foo2 返回的 this 为全局对象,因为函数是根据执行的对象来绑定 this 的,而箭头函数是创建的时候就绑定了上下文环境
console.log(obj.foo1(), obj.foo2());
// obj 对象中有一个 foo 方法,这个方法中使用了箭头函数返回了一个 this
// 因此箭头函数返回的这个 this 被绑定到了外层函数的 this
// 而 foo 的值可以在调用中设置,进而设置返回的 this
let obj = {
foo: function() {
let x = () => this;
return x;
}
}
// 作为 obj 对象的一个方法来调用,它的 this 会绑定到 obj 上
let fn = obj.foo(); // fn === obj
// 但是,若只是引用 obj 方法,没有调用它
let fn2 = obj.foo;
// 那么调用箭头函数后,this 指向 window,因为它从 foo 继承了this。
fn2() === window; // true
作为构造函数
当一个函数用作构造函数时(使用 new
关键字),它的 this
被绑定到正在构造的新对象。
作为一个 DOM 事件处理函数
当函数被用作事件处理函数时,它的 this
指向触发事件的元素。
作为一个内联事件处理函数
当代码被内联 on-event 处理函数 调用时,它的this
指向监听器所在的DOM元素:
<button onclick="alert(this.tagName.toLowerCase());">
Show this
</button>
上面的 alert 会显示 button
。
注意只有外层代码中的 this
是这样设置的:
<button onclick="alert((function(){return this})());">
Show inner this
</button>
在这种情况下,没有设置内部函数的 this
,所以它指向global/window
对象(即非严格模式下调用的函数未设置 this
时指向的默认对象)。
这种情况下,若想要正确设置 this
,可以使用 bind
:
<button onclick="alert((function(){return this}).bind(this)());">
Show inner this
</button>
REF: MDN
本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!