美文网首页
javascript 函数,构造函数,原型

javascript 函数,构造函数,原型

作者: goodl | 来源:发表于2017-12-16 20:57 被阅读0次

    函数的声明

    javascript 中函数有两种声明方式:

    // 声明方式
    function doSometh() {
        ...
    } 
    
    // 表达式方式
    var doSometh = function () {
        ...
    } 
    

    区别:声明方式定义的函数可以在函数调用之前也可以在函数调用之后,而表达式方式定义的函数只能在函数调用之前。

    例如:

    test();
    var test = function () {
        console.log('this is test method');
    };
    

    结果:


    QQ20171216-183413@2x.png

    函数返回值

    函数除显示 return 外,默认返回 undefined。

    function test () {
    }
    
    console.log(test()); // 输出:undefined
    

    立即执行函数

    (function() { ... })();
    ((function() { ... })());
    

    立即执行函数的作用:

    • 保存上下文环境
    • 作为命名空间

    举个例子:

    var data = [];
    for(var i=0; i<3; i++) {
        data[i] = function () {
            console.log(i);
        }
    }
    
    data[0]();
    data[1]();
    data[2](); 
    // 输出全部为3
    

    我们修改一下代码再执行:

    var data = [];
    for(var i=0; i<3; i++) {
        data[i] = (function (x) {
            return function () {
                console.log(x);
            }
        })(i);
    }
    
    data[0]();
    data[1]();
    data[2]();
    // 输出0,1,2
    

    构造函数

    和普通函数不同,构造函数使用 new 关键字调用。
    当构造函数没有形参时,可省略括号:

    var o1 = new Object();
    var o2 = new Object;
    

    简单来说,构造函数做了这么几件事情:

    1. 创建一个空对象,作为将要返回的实例。
    2. 将空对象的 __proto__ 指向构造函数的 prototype 属性
    3. 将构造函数内部的 this指向创建的新对象
    4. 执行构造函数内部的代码

    构造函数内部通常不使用 return,它返回构造出的新对象。

    原型到原型链

    每一个 js 对象都是一个属性集合。
    每一个函数都有一个 prototype 属性。

    举个例子,使用构造函数创建一个对象:

    function Person() {
    }
    var p = new Person();
    person.name = 'Tom';
    console.log(person.name); // Tom
    

    这个例子中,Person 就是一个构造函数,我们使用 new 关键字,创建了一个实例对象 person。

    再看一个例子:

    function Person() {
    }
    Person.prototype.name = 'Tom';
    var person1 = new Person();
    var person2 = new Person();
    console.log(person1.name); // Tom
    console.log(person2.name); // Tom
    
    prototype

    函数 Person 的 prototype 属性指向了一个对象,这个对象正是调用该构造函数而创建的实例的原型,也就是上面代码中的 person1 和 person2 的原型对象。

    每一个JavaScript对象(null除外)在创建的时候就会与之关联另一个对象,这个对象就是我们所说的原型,每一个对象都会从原型"继承"属性。

    constructor

    默认情况下,所有原型对象都有 constructor(构造器)属性,这个属性指向所在的函数,即:Person.prototype.constructor 指向 Person

    function Person() {
    }
    var person = new Person();
    console.log(Person.prototype.constructor === Person); // true
    

    用一张图表示构造函数和实例原型之间的关系:


    proto_1.png



    在 ECMA 中,并没有规定直接访问对象原型的方法,但绝大部分浏览器都支持一个 __proto__ 用来访问对象的原型。

    function Person() {
    }
    var person = new Person();
    console.log(person.__proto__ === Person.prototype); // true
    

    更新下关系图:


    proto_2.png



    综上得出:

    function Person() {
    }
    var person = new Person();
    console.log(person.__proto__ === Person.prototype); // true
    console.log(Person.prototype.constructor === Person); // true
    console.log(Object.getPrototypeOf(person) === Person.prototype); // true
    

    当获取某个对象的某个属性时,首先从实例本身开始,如果找到了该属性,则返回该属性的值。如果没有找到,则搜索__proto__指向的原型对象,如果找到,则返回值,如果没有则继续向上寻找,直到找到 Obejct。

    Person 有自己的原型,即 Person.prototype,同样 Person.prototype 也有自己的原型,即 Person.prototype.__proto__ 属性:

    proto_3.png

    那 Object.prototype 的原型呢?
    我们可以尝试打印:

    console.log(Object.prototype.__proto__ === null); // true
    

    所以 Object.prototype.__proto__ 的值为 null ,也就是说 Object.prototype 没有原型。

    所以查找属性的时候查到 Object.prototype 就停止查找了。

    最后一张关系图:


    proto_4.png

    图中由相互关联的原型组成的链状结构就是原型链,也就是蓝色的这条线。

    相关文章

      网友评论

          本文标题:javascript 函数,构造函数,原型

          本文链接:https://www.haomeiwen.com/subject/rcfewxtx.html