跳到主要内容

作用域与变量

函数内定义 var

js 中变量的作用域链与定义时的环境有关,与执行时无关。执行环境只会改变 this、传递的参数、全局变量等

function f1() {
console.log(v1);
console.log(v2);
}

function f2() {
var v1 = 1;
var v2 = 2;
// f1定义域在全局,读不到这里面的v1和v2
f1();
}

// 只能读到这里的
var v1 = 0;
f2();

函数调用套括号,或括号内赋值

var name = "window";

var person = {
name: "person",
sayName: function () {
console.log(this.name);
},
};

function sayName() {
var sss = person.sayName;
sss(); // "window"
// this绑定
person.sayName(); // "person"
// 这与 person.sayName(); 本质上是相同的。括号不会改变上下文,因此 this 仍然指向 person,结果是 "person"。
// (person).sayName(); // "person"
//这里,b 被赋值为 person 对象的 sayName 方法,类似于第一种情况。当调用 (b)() 时,它作为一个独立的函数被调用,因此 this 默认指向全局对象,结果是 "window"。
(b = person.sayName)(); // "window"
}

sayName();

全局变量,立即执行函数,当前作用域有没有用 var

如果没有用 var,会直接报错

(function () {
var x = (y = 1);
})();
var z;

console.log(y); // 1
console.log(z); // undefined
console.log(x); // Uncaught ReferenceError: x is not defined

普通函数套箭头函数 call 在运行时能被改 this

全局只能访问到 var 声明,访问不到 let

let 声明的变量,不会挂在 window 上

let a = 0;
function f1() {
setTimeout(function () {
// 普通函数,setTimeout执行回调,在全局中执行
// 全局只能访问到var声明,访问不到let
console.log(this.a);
}, 200);
}
function f2() {
setTimeout(() => {
console.log(this.a);
}, 200);
}
f1.call({ a: 1 }); // undefined //
f2.call({ a: 2 }); // 2 // 在 f2 中,setTimeout 的回调是一个箭头函数。箭头函数不会创建自己的 this,它会捕获其所在上下文的 this 值。即f2; 因此也可以运行时改变this

普通函数套普通函数/普通函数套箭头函数 被 call

var name = "window";

function Person(name) {
this.name = name;
this.obj = {
name: "obj",
foo1: function () {
return function () {
console.log(this.name);
};
},
foo2: function () {
return () => {
console.log(this.name);
};
},
};
}

var person1 = new Person("person1");
var person2 = new Person("person2");

// 闭包返回普通函数,this为window;
person1.obj.foo1()(); // 'window'
// 普通函数call后再执行返回函数,相当于全局执行函数
person1.obj.foo1.call(person2)(); // 'window'
// 返回完普通函数再call,能修改
person1.obj.foo1().call(person2); // 'person2'

// 闭包返回箭头函数,this为上下文obj;
person1.obj.foo2()(); // 'obj'
// foo2被call,this上下为被改为person2
person1.obj.foo2.call(person2)(); // person2
// 箭头函数被call,this上下文无法被修改为person2
person1.obj.foo2().call(person2); // obj

非函数内变量提升和函数提升

var a = 2;
function a() {}

相当于

function a() {} // 函数提升优先级更高
var a; // ***
a = 2;

a 从 not defined 变为函数 变为 undefined 变为 2

函数内变量提升和函数提升

function fn(a) {
console.log(a); // f a()
var a = 2;
function a() {}
console.log(a); // 2
}
fn(1);

相当于

function fn(a) {
var a;
a = 1;
function a() {}
// 函数作用域中,var优先级更高,全局作用域,function优先级更高
console.log(a); // f a()
a = 2;

console.log(a); // 2
}
fn(1);

作用域-obj 内部不能引用 obj

var obj = {
name: "1",
fn: (function (x) {
return x + 10;
})(obj.name),
};
console.log(obj.fn); // 报错

第七行,去 obj 里面找 fn 函数,fn 为立即执行函数,先看参数,fn 立即执行函数的作用域为 obj 对象里面,obj 对象里面没有 obj,所有也没有 obj.name

爆栈

var length = 5;
function a() {
console.log(this.length);
function b(fn) {
fn();
arguments[0]();
}
b(a, 1);
}
a();


5
5
5一直爆栈