zoukankan      html  css  js  c++  java
  • 原型和原型链

    对于js中原型的理解,我仅处在初级阶段。我的理解是,js的原型是为了实现“类”的概念,可以使得对象的方法可以通用,实现类的继承。虽然js中并没有类的概念,但是多数情况下,人们还是偏向于使用面向对象的概念在编程。

    Js所有的函数都有一个prototype属性,这个属性引用了一个对象,即原型对象,也简称原型。当我们用js来模拟类时就涉及到了原型链的概念。原型链和作用域链的作用很相似,都是用来定义查询变量的一种规则。当你在自身查找不到某个变量或者方法的时候,原型链会根据规则继续向上查找,直到顶端为止。

    比如,在定义一个“类”的时候,通常会先定义一个构造函数,里面包含了实例属性。

    function Person (name, age) {
         this.name = name;
         this.age = age;
    }

    他可能包含了一些通用的方法(类方法),比如读取姓名和年龄,安排班级等

    Person.prototype.getName = function () {
        return this.name;
    }
    Person.prototype.getAge = function () {
        return this.age;
    }

    当我们需要给一个类定义通用的方法的时候,我们需要在它的原型上定义属性,这样,所有通过构造函数生成的实例都可以调用该方法。

    继承的实现也是因为有原型的存在得以实现,通用的实现继承方法如下:

     
    function Person (name, age) {
         this.name = name;
         this.age = age;
    }
    Person.prototype.getName = function () {
        return this.name;
    }
    Person.prototype.getAge = function () {
        return this.age;
    }
    Person.prototype.setAge = function (age) {
        this.age = age;
    }
    function Teacher(name,age,no){
        //实现子类属性的继承,每个实例都有属于自己的属性,同时需要注意参数的顺序,call函数只看重顺序,不在乎参数名称     
        Person.call(this, name, age);     
        this.classNo = no;
    }
    Teacher.prototype = new Person();  //将父类的对象赋值给子类,原型对象,这样子类就继承了父类的方法

    // 在支持ES5的浏览器推荐下面的写法:(创建一个新的对象,内容是Person.prototype,将其赋值给Teacher.prototype,这样就将Person的原型和Teacher的原型相关联,并不会产生副作用)// Teacher.prototype = Object.new(Person.prototype);

    Teacher.prototype.getInfo = function () {
           console.log('name:' + this.name + 'age:' + this.age + 'classNo:' + this.classNo);
    }
    var teacherLi = new Teacher('Li', 30, 2);
    teacherLi.getInfo(); //name:Liage:30classNo:2
    teacherLi.setAge(28);
    teacherLi.getInfo(); //name:Liage:28classNo:2

    一. new操作符的含义

    当我们使用new操作符时,实际上就是创建一个对象。但在实际运行当中,new是创建了两个对象,并将其相互关联。例如上面的例子中var teacherLi = new Teacher('Li', 30, 2); 这句话,new操作符创建了一个对象并将它赋值给teacherLi,并将teacherLi和Teacher.prototype相联系,teacherLi.__proto__ === Teacher.prototype。

    在ES5规范里,针对new的操作的定义如下:

    image

    简单理解就是:

    1. 新建一个对象

    2. 将对象的内部__proto__属性和构造函数的prototype相关联

    3. 利用构造函数给实例对象属性赋值

    4. 如果构造函数没有显示返回对象,则返回步骤一创建的对象

    二.constructor

    Foo.prototype.constructor === Foo

    Foo.prototype的.constructor属性只是Foo函数在声明时的默认属性。如果prototype被重新赋值声明,那么constructor就不知道是指向谁了,它会根据原型链一直检索,直到检索到最上层Object对象。

    function Foo() { /* .. */ }
    Foo.prototype = { /* .. */ }; // 创建一个新原型对象
    var a1 = new Foo();
    a1.constructor === Foo; // false!
    a1.constructor === Object; // true!

    三.prototype&__proto__

    对象的__proto__属性指向它关联的prototype对象。可以简单的理解为实例的__proto__属性指向它的原型对象。

    function Foo(a) {
        this.a = a;
    }
    var foo = new Foo('foo');
    console.log(foo.__proto__ === Foo.prototype);
    console.log(Foo.__proto__ === Function.prototype);
    console.log(Function.__proto__ === Function.prototype);
    console.log(Function.prototype.__proto__ === Object.prototype);
    console.log(Object.prototype.__proto__ === null);

    以上的答案都是true,可以看到当你用new标识符来创建一个属性时它会默认应用建立原型链,一直关联到Object这个对象原型。

    在js的内置类型当中:

    Number.__proto__ === Function.prototype  // true
    Boolean.__proto__ === Function.prototype // true
    String.__proto__ === Function.prototype  // true
    Object.__proto__ === Function.prototype  // true
    Function.__proto__ === Function.prototype // true
    Array.__proto__ === Function.prototype   // true
    RegExp.__proto__ === Function.prototype  // true
    Error.__proto__ === Function.prototype   // true
    Date.__proto__ === Function.prototype    // true
    Math.__proto__ === Object.prototype  // true
    JSON.__proto__ === Object.prototype // true

    因为Function.prototype.__proto__ === Object.prototype得值是true,所以,函数也是对象。

    之前看到过一套测试题,放在这里以供思考:

    function Foo() {
        getName = function () { alert (1); };
        return this;
    }
    Foo.getName = function () { alert (2);};
    Foo.prototype.getName = function () { alert (3);};
    var getName = function () { alert (4);};
    function getName() { alert (5);}
     
    //请写出以下输出结果:
    Foo.getName();
    getName();
    Foo().getName();
    getName();
    new Foo.getName();
    new Foo().getName();
    new new Foo().getName();

    解释地址:http://web.jobbole.com/85122/

  • 相关阅读:
    详述@Responsebody和HTTP异步请求的关系
    利用synchronized解析死锁的一种形成方式
    初识Spring JdbcTemplate
    初识SpringIOC
    JasperReport框架使用教程(附带常见空白页问题说明)
    LeetCode~1033.移动石子直到连续
    LeetCode~941.有效的山脉数组
    LeetCode~344. 反转字符串
    Job for network.service failed because the control process exited with error code问题
    LeetCode~报数(简单)
  • 原文地址:https://www.cnblogs.com/Candybunny/p/5476244.html
Copyright © 2011-2022 走看看