• prototype和__proto__


    首首先,要明白三个概念,构造函数,原型对象,实例对象

    • 每创建一个函数,该函数都会自动带有一个prototype属性。该属性是一个指针,指向一个对象,该对象称之为原型对象(后期我们可以使用这个原型对象帮助我们在js中实现继承).
    • 原型对象上默认有一个属性constructor,该属性也是一个指针,指向其相关联的构造函数。
    • 通过调用构造函数产生的实例对象,都拥有一个内部属性,指向了原型对象。其实例对象能够访问原型对象上的所有属性和方法。
    • 三者的关系是,每个构造函数都有一个原型对象,原型对象上包含着一个指向构造函数的指针,而实例都包含着一个指向原型对象的内部指针。通俗的说,实例可以通过内部指针访问到原型对象,原型对象可以通过constructor找到构造函数。

    首先,明确一点,prototype是构造函数属性,__proto__是构造函数实例即对象的属性,即:

    • __proto__是每个对象都具有的属性
    • prototypeFunction独有的属性

    构造函数的prototype和相应实例的__proto__指向同一个对象。

    当然以上定义不是特别准确,但是这么理解问题不大。

    原型对象在对象中是不可见. 使用 Object.getPrototypeOf(obj) 方法来访问实例的原型对象,即__proto__。如下:

    obj.__proto__ === Object.getPrototypeOf(obj)  //true

    详解:

    JavaScript是一门动态语言, 你可以在任何时候向对象上添加属性,如下


    function Student() {
    this.name = 'LeBron James';
    this.gender = 'Male';
    }

    var studObj1 = new Student();
    studObj1.age = 15;
    alert(studObj1.age); // 15

    var studObj2 = new Student();
    alert(studObj2.age); // undefined

    正如上面的实例, age 属性附加在 studObj1 实例上. 然而 studObj2 实例没有这个属性, 因为 age 属性只在 studObj1 实例上定义了.

    那么, 如果想在后期添加一个属性且能被所有的实例所共享, 该怎么办? 答案这就今天主角 Prototype.

    Prototype 是一个对象, 默认情况下与JavaScript中的任何一个函数或对象有关, 只是唯一区别在于函数的prototype 属性是可访问可修改的,而对象prototype属性是不可见的.

    默认情况下任何一个函数包含 Prototype 对象, 如下图:

    prototype 对象是一种特殊类型的可枚举对象, 可以将需要附加属添加到其上,这些属性将在其构造函数的所有实例之间共享。

    因此, 把上面的示例中使用函数的 prototype 来添加属性,以便于所有对象中都可以访问到, 如下:


    function Student() {
    this.name = 'LeBron James';
    this.gender = 'M';
    }

    Student.prototype.age = 15;

    var studObj1 = new Student();
    alert(studObj1.age); // 15

    var studObj2 = new Student();
    alert(studObj2.age); // 15

    使用 字面量 或 通过 new关键字和构造函数 的方式创建的每一个对象都包含 __proto__ 属性, 该属性指向创建此对象的函数的 原型对象.

    你可以在谷歌和火狐开发者调试工具中查看该属性(__proto__) , 根据下面的示例:


    function Student() {
    this.name = 'LeBron James';
    this.gender = 'M';
    }

    var studObj = new Student();

    console.log(Student.prototype); // object
    console.log(studObj.prototype); // undefined
    console.log(studObj.__proto__); // object

    console.log(typeof Student.prototype); // object
    console.log(typeof studObj.__proto__); // object

    console.log(Student.prototype === studObj.__proto__ ); // true

    正如上面例子看到, 函数通过 [[函数名称]].prototype 方式访问到原型对象. 但是, 对象(实例)并没有暴露出 prototype 属性,而是使用 __proto__ 来访问它.

    Object 对象的原型

    前面提及到, 原型对象在对象中是不可见. 使用 Object.getPrototypeOf(obj) 方法来访问实例的原型对象. (这也是推荐方式, __proto__ 并不是标准属性, 在IE11以下其它浏览器中没有实现).


    function Student() {
    this.name = 'LeBron James';
    this.gender = 'M';
    }

    var studObj = new Student();

    Student.prototype.sayHi= function(){
    alert("Hi");
    };

    var studObj1 = new Student();
    var proto = Object.getPrototypeOf(studObj1);
    // returns Student's prototype object

    alert(proto.constructor);
    // returns Student function

    Object 原型对象包含如下 属性 和 方法

    属性描述
    constructor 返回创建该实例的构造函数
    __proto__ 指向创建该实例的构造函数的原型对象.
    方法描述
    hasOwnProperty() 返回一个布尔值,指示对象是否包含指定的属性作为该对象的直接属性,而不是通过原型链继承。
    isPrototypeOf() 返回一个布尔值,指示指定的对象是否位于调用此方法的对象的原型链中。
    propertyIsEnumerable() 返回一个布尔值,该布尔值指示指定的属性是否可枚举。
    toLocaleString() 返回本地格式的字符串.
    toString() 返回对象字符串形式.
    valueOf() 返回指定对象的原始值.

    Chrome 和 Firfox 将对象的原型表示为 __proto__, 而内部引用为 [[Prototype]]. IE不支持,只有IE11包含它.

    修改原型

    如上所述, 每个对象都能链接到函数的原型对象. 如果您更改了函数的原型, 则只有新对象将链接到更改后的原型. 所有其他现有对象仍然链接到旧的函数原型. 下面实例来演示这个场景:


    function Student() {
    this.name = 'LeBron James';
    this.gender = 'M';
    }

    Student.prototype.age = 15;

    var studObj1 = new Student();
    alert('studObj1.age = ' + studObj1.age); // 15

    var studObj2 = new Student();
    alert('studObj2.age = ' + studObj2.age); // 15

    Student.prototype = { age : 20 };

    var studObj3 = new Student();
    alert('studObj3.age = ' + studObj3.age); // 20

    alert('studObj1.age = ' + studObj1.age); // 15
    alert('studObj2.age = ' + studObj2.age); // 15

    使用原型

    原型对象被JavaScript引擎用来做两件事:

    • 查找对象的属性和方法

    • 在JavaScript中实现继承


    function Student() {
    this.name = 'LeBron James';
    this.gender = 'M';
    }

    Student.prototype.sayHi = function(){
    alert("Hi");
    };

    var studObj = new Student();
    studObj.toString();

    在上面的示例, toString() 方法在 Student 中没有定义, 那么它是如何以及从哪里找到 toString() 的呢?

    在这里,原型出现了. 首先, JavaScript 引擎检查 studObj 是否存在 toString 方法?. 如果没有找到,那么它使用 studObj 的 __proto__ 链接指向 Student函数 的 原型对象. 如果它仍然无法找到它那么它会在往上层并检查 Object 函数的原型对象,因为所有对象都是从 JavaScript 中的 Object 派生的,并查找 toString() 方法. 因此, 它在Object函数的原型对象中找到 toString() 方法,因此我们可以调用 studObj.toString().

    查找方式,如下图所示

    上述就是原型基本知识点以及应用.

  • 相关阅读:
    Java 的JDBC 数据库连接池实现方法
    在tomcat下context.xml中配置各种数据库连接池
    Eclipse大括号换行显示
    编写.reg文件 导入注册表
    servlet中使用session
    IIS7整合Tomcat6
    TOMCAT数据库连接池的配置方法总结(待续)
    windows2003下iis6.0+tomcat6.0的整合配置
    TransactSQL处理小数
    专案同时使用两种数据库
  • 原文地址:https://www.cnblogs.com/wangtong111/p/11227334.html
Copyright © 2020-2023  润新知