js学习笔记之自调用函数、闭包、原型链

 自调用函数
var name = 'world!';
    // console.log(typeof name)
    (function () {
        console.log(this.name, name, typeof name, typeof name === undefined)
        if(typeof name === undefined){
            var name = 'a!'
            console.log('hello ' + name)
        } else{
            var name = 'b!'
            console.log('hello ' + name)
        }
    })();

运行结果是
"world!" undefined "undefined" false
hello b!

这里有两个陷阱
第一个是变量提升后 name 值为 undefined
第二个是 typeof name 为字符串 "undefined" 
 
闭包
闭包就是能读取其他函数内部变量的函数。
 
优点:
保护函数内的变量安全,加强了封装性
在内存中维持一个变量(用的太多就变成了缺点,占内存)
 
缺点:
闭包有一个非常严重的问题,那就是内存浪费问题,这个内存浪费不仅仅因为它常驻内存,更重要的是,对闭包的使用不当会造成无效内存的产生
var counter = 2
var add = (function () {
    console.log(this.counter, counter, 'bbb') // 2, undefined, 'bbb'
    var counter = 3;
    return function () {
        counter += 1;
        console.log(counter)
    }
})();
add(); // 4
add(); // 5
add(); // 6
console.log(counter, 'aaa') // 2, 'aaa'
 

原型链
所有对象的 __proto__ 都指向其构造器的 prototype
所有函数对象的 __proto__ 都指向 Function.prototype,它是一个空函数(Empty function)
Object.prototype.__proto__ === null

function fn() {
        this.a = 10
        this.b = function () {
           console.log(this.a)
        }
    }
    fn.prototype = {
        b: function () {
            this.a = 20
            console.log(this.a)
        },
        c: function () {
            this.a = 30
            console.log(this.a)
        }
    }
    var myfn = new fn();
    console.log(myfn) //对象属性有a,b;原型链继承属性有b,c
console.log(myfn.__proto__ === fn.prototype) // true
console.log(myfn.__proto__ === myfn.constructor.prototype) // false
myfn.b() //10 
myfn.c() //30
myfn.b() //30
解析
myfn对象第一次调用b方法,由于原型链上的b方法被覆盖,所以始终调用自身的b方法,所以就输出初始值10
myfn调用c方法等于是调用继承的c方法,所以a属性被重新赋值,于是输出30
myfn第二次调用b方法,由于a属性已经被c方法重新赋值,所以继续输出30

myfn.__proto__始终指向构造器fn的prototype属性
但是myfn.__proto__不再指向myfn.constructor.prototype

myfn本身没有constructor属性,于是指向fn.prototype.constructor属性,
而fn.prototype.constructor本来应该指向其自身,但是因为重新赋值fn.prototype对象,所以fn.prototype的构造函数变成了Object

引用指针

var a = {n:1}; 
var b = a;  
a.x = a = {n:2}; 
console.log(a.x); // undefined 
console.log(b.x); // {n:2} 

解释
这里的连续赋值运算顺序是先进行'.'运算符赋值,这时将a.x还是指向对象A的,
接下来开始从右向左赋值,改变a的指向为对象B
接下来开始a.x的赋值为对象B,这时候'.'运算符已经最先赋值了,所以还是给对象A的x属性赋值
原文地址:https://www.cnblogs.com/nightstarsky/p/9182756.html