JavaScript:杂谈 动态性/高阶函数/类方法/箭头函数/console.log

225 阅读3分钟

数组下标的动态性

用数组下标方式表示的对象属性名是动态的,用.表示的对象属性名是静态的。
用下面例子说明

var obj = {
greet: 'hello',
}
console.log(obj.greet);//hello
console.log(obj['greet']);//hello
console.log(obj[greet]);//undefine
    var name = greet;
console.log(obj[name]);//hello

高阶函数

因为js中函数是一个特殊的对象(object),所以它可以像一个普通的变量一样被传递

var arr = [];
arr.push(function(){
    console.log('hello 1');
});
arr.push(function(){
    console.log('hello 2');
});
arr.push(function(){
    console.log('hello 3');
});
arr.forEach(function(item){
    item();
})

类方法

构造函数里面写的方法是实例专属的,一个实例有一个方法,有几个实例就占几块内存
原型上的方法是所有实例共有的,只占一块内存
类上的方式只能通过类调用,实例对象没有办法调用

//构造函数里面
function Promise(){
    this.insFunForOne = function(){
        console.log('instance method for One')
    } 
}
//原型上的方法
Promise.prototype.insFunForAll = function(){
    console.log('instance method for All');
}
// 类上的方法
Promise.consFun = function(){
    console.log('constructer property');
}
var demo = new Promise();
demo.insFunForOne();
demo.insFunForAll();
// demo.consFun();
// Promise.insFunForOne();
// Promise.insFunForAll();
Promise.consFun();
console.log(demo);
console.log(Promise);

箭头函数

箭头函数在它的执行环境被创建时没有创建相应的this(函数表达式和函数声明式都有this被创建的过程),所以在箭头函数中调用this会沿作用连域向上找。
所以下面两种写法this的指代不相同。

function Observer() {
    this.state = 'UNHAPPY';
    this.arr = [];
}
//将被观察者跟观察者联系起来
Observer.prototype.attach = function(s) {
    this.arr.push(s);
}
Observer.prototype.setState = function(newState) {
    this.state = newState;
    this.arr.forEach((s)=>{
        // 被观察者通知观察者变化情况
        s.update(this.state);
    })
}
function Subject(name,target) {
    this.name = name;
    this.target = target;
}
Subject.prototype.update = function(newState) {
    console.log(this.name+'观察到了被观察者的'+newState+'变化');
}
let o = new Observer();
let s1 = new Subject('Brynn', o);
let s2 = new Subject('Boolean', o);
o.attach(s1);
o.attach(s2);
o.setState('HAPPY');
o.setState('INDIFFERENT');

//运行结果

Brynn观察到了被观察者的HAPPY变化
Boolean观察到了被观察者的HAPPY变化  
Brynn观察到了被观察者的INDIFFERENT变化
Boolean观察到了被观察者的INDIFFERENT变化

//使用函数表达式,this指向的是window

    this.arr.forEach(function(s){
        console.log("打印this");
        console.log(this);//window
        s.update(this.state);//undefine
    })
    //因为这里的forEach可以实际看成
    (function(s){
        console.log("打印this");
        console.log(this);//window
        s.update(this.state);//undefine
    })('Brynn');
    (function(s){
        console.log("打印this");
        console.log(this);//window
        s.update(this.state);//undefine
    })('Boolean');
    //这是一个匿名函数的IIFE,没有找到调用它对象,this指向的是window

    //使用箭头函数,this指向构造函数的实例化对象
    this.arr.forEach((s)=>{
        console.log("打印this");
        console.log(this);//o
        s.update(this.state);//HAPPY
    })
    forEach可以实际看成
    ((s)=>{
        console.log("打印this");
        console.log(this);//o
        s.update(this.state);//HAPPY
    })('Brynn');
    ((s)=>{
        console.log("打印this");
        console.log(this);//o
        s.update(this.state);//HAPPY
    })('Boolean')
    //在这里就是setState()这个函数执行环境中的this,setState()被调用时的形式是o.setState(),所以this指向o这个对象

console.log不合预期

在《你不知道的JavaScript》中有提到,console.log并不属于ECMAScript规范内,所以不同的环境(不同的浏览器,Node)对控制台输出有自己的实现。
而I/O操作是耗时的,所以在有的浏览器会将console.log作为异步方法,导致console.log()不合预期(感觉打印结果满了一拍)。

var obj = {a:1};
console.log(obj);
console.log(JSON.stringify(obj));
obj = {b:2} 
console.log(obj);
console.log(JSON.stringify(obj));
obj.a = 3; 
console.log(obj);
console.log(JSON.stringify(obj));

在Node环境下,运行结果正常:

但在chrome控制台,输出结果有误:

这种情况通常出现在:打印变动的对象时。可以用JSON.stringify(obj)将对象转换为字符串,强制只执行一次快照,获得实时结果。