变量提升/作用域/函数执行 练习1

211 阅读3分钟

知识点总结:

  1. 带 var 在变量提升阶段只声明不定义; 带 function 声明且定义
  2. 如果函数执行没有返回结果,则返回 undefined
console.log(a, b, c); // undefined*3
var a = 12,
    b = 13,
    c = 14;
function fn(a) {
    console.log(a, b, c);  // 10 13 14
    a = 100;  // =>  此处修改的是私有变量(形参赋值下的a)
    c = 200;
    console.log(a, b, c);  // 100 13 200
}
b = fn(10);
console.log(a, b, c);   // 12 undefined 200

知识点总结:函数作用域是创建时候的执行上下文

var i = 0;
function A() {
    var i = 10;
    function x() {
        console.log(i);  
    }
    return x;
}
var y = A();
y();     // 10
function B() {
    var i = 20;
    y();
}
B();   // 10
var a=1;
var obj ={
   "name":"tom"
}
function fn(){
   var a2 = a;
   obj2 = obj;
   a2 =a;
   obj2.name =”jack”;
}
fn();
console.log(a);  // 1 
console.log(obj);  // {"name":"jack"}
var a = 1;
function fn(a){
    console.log(a)
    var a = 2;
    function a(){}
}
fn(a);   // ƒ a(){}

console.log(a); // undefined
var a=12; 
function fn(){
    console.log(a); // undefined
    var a=13;   
}
fn();   
console.log(a);//12
console.log(a);   // undefined
var a=12;  
function fn(){
    console.log(a);  // 12
    a=13;
}
fn();
console.log(a);   // 13
console.log(a);   // 报错: a is not defined
a=12;
function fn(){
    console.log(a);
    a=13;   
}
fn();
console.log(a);
    1. 自执行函数:创建(堆)+执行(私有上下文)一并完成
    1. 逻辑或和逻辑与表达式
    • A||B:验证A是真还是假(只有 0/NaN/null/undefined/空字符串 是假),如果A是真,返回的A的值,如果A是假,返回B的值(不论B的值是啥)
    • A&&B:A是真返回B的值,A是假返回A的值
    • 同时出现的时候,&&优先级高于 ||
var foo='hello'; 
(function(foo){
   console.log(foo);
   var foo=foo||'world';
   console.log(foo);
})(foo);
console.log(foo);

延伸 ES6中默认传参的另外一种表达

function func(x, y, z = 0) {
	 //  z = 0  ES6设置默认值的方式(不传递值,赋值默认值)
}

function func(x, y, z) {
	/* if (typeof z === "undefined") {
		z = 0;
	} */
	z = z || 0; 
	//这样也可以,只不过不如上面的准确,上面都是不传递赋值默认值,这样写是不传或者传递的值是假,都会赋值默认值【不严谨,但是很多人都在这样用】
}
func(10, 20);


 function func(callback) {
	/* if (typeof callback === "function") {
		callback();
	} */

	callback && callback();  //【依然不严谨,一般我们默认要不就不传,传递一定是函数】
}
func(function anonymous() {}); 

自执行函数本身应该是匿名函数(还有函数表达式或者回调函数等都是匿名函数),只不过为了保证良好编码习惯,我们经常给本应是匿名的函数 “具名化”(起个名字)

  • 1.这个名字只能在函数内部被调用,函数外面用不了(可以理解为是私有变量)
  • 2.这个名字的变量,在函数内部,值也是不能被修改的(改了也没用,还是代表函数)
var b = 10;
(function b() {
    b = 20;
    console.log(b);  // 函数本身
})();
console.log(b);   // 10

延伸1:取代严格模式下不支持的arguments.callee

(function AAA() {
	// console.log(AAA); //=>函数本身(这样后期在递归调用的时候,可以直接基于AAA执行即可,无需再使用arguments.callee了【arguments.callee在严格模式下不支持】)
	AAA = 1000;
	console.log(AAA); //=>函数本身
})();
console.log(AAA); //=>Uncaught ReferenceError: AAA is not defined 

延伸2: 如果是基于VAR/LET/FUNCTION等操作单独处理,会把这个具名化的名字改为正常的私有变量,也就是名字不再代表函数了

 (function AAA() {
	/*
	 * 如果是基于VAR/LET/FUNCTION等操作单独处理,会把这个具名化的名字改为正常的私有变量,也就是名字不再代表函数了 
	 */
	// console.log(AAA); //=>Uncaught ReferenceError: Cannot access 'AAA' before initialization
	let AAA = 100;
	console.log(AAA); //=>100
})(); 

(function AAA() {
	console.log(AAA); //=>函数(输出1的)
	function AAA(){console.log(1)}
	console.log(AAA); //=>函数(输出1的)
})(); 

(function AAA() {
	console.log(AAA); //=>undefined
	var AAA = 200;
	console.log(AAA); //=>200
})();