JS 原型和闭包 深入理解javascript原型和闭包(完结)

原文:深入理解javascript原型和闭包(完结)

JavaScript 中的难点和重要点,排除只是体系之外的 bug。本篇是学习笔记,记录个人理解。

一、一切皆对象:一切(引用类型)都是对象,对象是属性的集合

function show(x) {

            console.log(typeof x);    // undefined
            console.log(typeof 10);   // number
            console.log(typeof 'abc'); // string
            console.log(typeof true);  // boolean

            console.log(typeof function () {});  //function

            console.log(typeof [1, 'a', true]);  //object
            console.log(typeof { a: 10, b: 20 });  //object
            console.log(typeof null);  //object
            console.log(typeof new Number(10));  //object
}

show();

   (undefined, number, string, boolean)属于简单的值类型,不是对象。剩下的(函数、数组、对象、null、new Number(10))就是引用数据类型,属于对象。

  附:   typeof xxx:判断变量的数据类型;  xxx instanceof Array:精确判断变量是否属于某一类型。

var fn = function () { };
console.log(fn instanceof Object);  // true

  通常我们声明一个 js 对象通常写成类 json(键值对) 格式,但函数和数组也可以这样定义属性吗?——当然不行,但是它可以用另一种形式,总之函数/数组之流,只要是对象,它就是属性的集合。 以下例子:

var fn = function () {
    alert(100);
};

fn.a = 10;
fn.b = function () {
        alert(123);
};
fn.c = {
    name: "王福朋",
    year: 1988
};
fn(); // 100
fn.b; // function(){alert(123);}
fn.b(); // 123

  上段代码中,函数就作为对象被赋值了a、b、c三个属性——很明显,这就是属性的集合吗。

  其实,jquery 中的 “$” 就是一个函数。

函数是一种对象,但是:函数和对象间的关系不简单的是父子集的关系!

详见:函 - 对 关系

  (1)对象都是通过函数创建的。

        function Fn() {
            this.name = '王福朋';
            this.year = 1988;
        }
        var fn1 = new Fn();

    这是最基本的创建对象的写法。这也是 JS 底层中创建对象的方法。

  (2)访问一个对象的属性时,先在基本属性中查找,如果没有,再沿着__proto__这条链向上找,这就是原型链。__proto__ 在“函 - 对 关系”中有相关解释)。

function Foo () {};
var f1 = new Foo();

f1.a = 10;

Foo.prototype.a = 100;
Foo.prototype.b = 200;

console.log(f1.a); // 10
console.log(f1.b); // 200

   

二、原型及原型链

  在 “一切皆对象中” 的 “函 - 对 关系”中有相应介绍。

  补充:原型链的好处:

在Java和C#中,你可以简单的理解class是一个模子,对象就是被这个模子压出来的一批一批月饼(中秋节刚过完)。压个啥样,就得是个啥样,不能随便动,动一动就坏了。

而在javascript中,就没有模子了,月饼被换成了面团,你可以捏成自己想要的样子。

首先,对象属性可以随时改动。

对象或者函数,刚开始new出来之后,可能啥属性都没有。但是你可以这会儿加一个,过一会儿在加两个,非常灵活。

 三、执行上下文

  在一段js代码拿过来真正一句一句运行之前,浏览器已经做了一些“准备工作”,其中包括对变量的声明(而不是赋值。变量赋值是在赋值语句执行的时候进行的。)、this 的赋值、“函数表达式”或“函数声明”。

  • 变量、函数表达式。例如:
    console.log(a);  // undefinded
    var a = 10;
    
    
    console.log(f1)  // undefinded
    var f1 = function() { };
  • 函数的声明及赋值;
    console.log(f1);  // function f1() { }
    function f1() { };
    

     注意:“函数的声明”和“函数表达式”均发生在“准备工作”时,过程却不一样。

  以上的三种的数据准备情况称之为“执行上下文”。通俗来讲,在执行代码前,把简要用到的所有变量都事先拿出来,有的直接赋值,有的先用 undefined 占个坑。

  贴两个上下文环境的数据内容:

  • 全局代码的上下文环境:

  • 函数体中的上下文环境内容在上面的基础上多了如下内容:

  还有几点需要注意的是:

  1.函数每被调用一次,都会产生一个新的执行上下文环境。因为不同的调用可能就会有不同的参数。

  2.函数在定义的时候(不是调用的时候),就已经确定了函数体内部自由变量的作用域。比如:

var a = 10;
function fn() {
    console.log(a);
}

function bar(f) {
    var a = 20;
    f();                
    console.log(f);
}

bar(fn);


// a = 10
// function fn() { console.log(a); }

   3.关于函数的执行。上例中应该可以看出来,函数执行真正的符号是 “()” , 前面的基本等同于是个标识,所以真是 锱铢必较...

 

猜你喜欢

转载自www.cnblogs.com/cc-freiheit/p/9418491.html