js 作用域

博客分类: 江河计划

js 作用域

算法

背包问题递归解法

var selectMap = {};
const knapsack = (weights:number[], values:number[], total:number, w?:number) => {
    if(w === undefined){
        w = weights.length - 1;
    }
    if(total === 0 || w < 0){
        return 0
    }
    var lastData = knapsack(weights, values, total, w - 1);
    if(total < weights[w]){
        return lastData;
    }
    var newData = knapsack(weights, values, total - weights[w], w - 1) + values[w];
    if(lastData < newData){
        selectMap[w] = true;
        return newData;
    }else{
        selectMap[w] = false;
        return lastData;
    }
}
var ws = [2,2,6,5,4];
var vs = [6,3,5,4,6];
var ts = 16;
var totalWeight = 0;
var a = knapsack(ws,vs,ts);
console.log(selectMap)
Object.keys(selectMap).map(i => {
    if(selectMap[i]){
        totalWeight += ws[i];
        console.log(`选择物品:${i};重量为:${ws[i]};价值为:${vs[i]}`);
    }
});
console.log(`背包最大承重:${ts};实际重量:${totalWeight};最大价值:${a}`)

作用域

词法作用域 or 动态作用域

js 是词法作用域,就是说解释器引擎在解释 js 的时候,就已经确定作用域了,从下面的例子可以看出来:

function foo(){
    // js 会输出 2
    // 如果输出的是 3 就是动态作用域如 bash
    console.log(a);
}

function bar(){
    let a = 3;
    foo();
}

let a = 2;

bar()

什么是作用域

作用域一般在前端指的是当前代码执行的上下文环境,这句话比较抽象,下面介绍几个概念。

  1. VO:变量对象
  2. AO:活动对象
  3. this:当前环境的 this 指向
  4. scope:指向父级作用域

变量对象可以理解为当函数还没有执行的时候,由于 js 有声明提前的概念,所以会有 VO 对象的概念,申请内存的时候先方进去,AO 是当代码执行的时候,就会将属于当前作用域的 VO 变为 AO。

this 是在函数执行的时候确定的。下周详细说一下 this

作用域类型

作用域大致分为:函数作用,全局作用域,块级作用域。

函数作用域:也称局部作用域,在函数大括号之间的内容就是该函数的作用域。

全局作用域:js 会有根对象,这个根对象提供一些除了语法之外的 API 让 js 的代码来调用,这个对象所处的环境就是全局作用域,比如 window。

块级作用域:js 是没有块级作用域的,并且有声明提前的概念,所以没有办法在 if 内声明一个变量。

作用域链

当函数内部想要使用一个变量时,这个时候会从当前作用域中寻到变量,如果不存在该变量,会到上一个作用域中寻找,所以变量间是有关系的,这个关系类似于 js 的原型链。子指向父的关系。小的作用域中的 scope 指向父级执行上下文。

这样作用域一层一层的关系就形成了作用域链,也就形成了变量逐级向上查找的关系,如果没有找到就会报一个错 变量is not defined

实例

var x = 10;
 
function foo() {
    var y = 20;
 
    function bar() {
        var z = 30;
        alert(x +  y + z);
    }
 
    bar();
}

foo(); // 60

// 全局上下文的变量对象是
globalContext.VO === Global = {
    x: 10
    foo: <reference to function>
};

// 在“foo”创建时,“foo”的[[scope]]属性是
foo.[[Scope]] = [
    globalContext.VO
];

// 在“foo”激活时(进入上下文),“foo”上下文的活动对象是
fooContext.AO = {
    y: 20,
    bar: <reference to function>
};

// “foo”上下文的作用域链为:
fooContext.Scope = fooContext.AO + foo.[[Scope]] // i.e.:
 
fooContext.Scope = [
    fooContext.AO,
    globalContext.VO
];

// 内部函数“bar”创建时,其[[scope]]为:
bar.[[Scope]] = [
    fooContext.AO,
    globalContext.VO
];

// 在“bar”激活时,“bar”上下文的活动对象为:
barContext.AO = {
    z: 30
};

// “bar”上下文的作用域链为:
barContext.Scope = barContext.AO + bar.[[Scope]] // i.e.:
 
barContext.Scope = [
    barContext.AO,
    fooContext.AO,
    globalContext.VO
];

// 对“x”、“y”、“z”的标识符解析如下:
- "x"
-- barContext.AO // not found
-- fooContext.AO // not found
-- globalContext.VO // found - 10

- "y"
-- barContext.AO // not found
-- fooContext.AO // found - 20

- "z"
-- barContext.AO // found - 30