知识点杂记

for in 和 for of 的区别

  • 首先,for in 遍历的是对象的属性名(key),for of 遍历的是值
  • for of 只能用于遍历迭代对象,如数组、字符串、mapset等,因此不能用于遍历对象
  • for in 用于遍历对象的所有可枚举属性,虽然也可以遍历数组,但是不推荐用来遍历数组,因为 for in 还会遍历原型的方法和属性,且遍历顺序可能和预想的不一样
  • for in 在遍历对象属性时可以使用 obj.hasOwnProperty(key) 来判断是否是该对象的属性,而不是从原型继承而来的。

https://www.jianshu.com/p/c43f418d6bf0

null 和 undefined

在 JS 中,将一个变量赋值为 nullundefined 几乎没有什么区别,它们都是虚值(falsy),在判断语句中都会被转为 false

虽然它们非常类似,但是还是有一些区别的:

null

null 表示 没有对象,即该处没有值。典型的用法是:

  1. 作为函数的参数,表示该函数的参数不是对象。

  2. 作为对象原型链的终点

    Object.getPrototype(Object.prototype); // null

undefined

undefined 表示 缺少值,即是此处可能会有一个值,但是还没有定义。典型语法是:

  1. 变量被声明了,但是没有赋值时,就等于 undefined
  2. 调用函数时,应该提供的参数没有提供,该参数就等于 undefined
  3. 对象没有赋值的属性,该属性的值为 undefined
  4. 函数没有返回值时,默认返回 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 保持一致,且一旦设置,就不会被 callbindapply 等方法修改。

如:

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 协议 ,转载请注明出处!

 目录