es5-原型链-构造函数

构造函数和原型

  • 利用构造函数创建对象
    function Star(uname,age){
        this.uname = uname;
        this.age = age;
        this.sing = function(){
            console.log('我会唱歌');
        }
    }
    
    var lmk = new Star('两门课',18);
    // 构造函数用于创建某一类对象,其首字母要大写
    // 构造函数要和new一起使用才有意义
  • new在执行时所作的事情
    1. 在内存中创建一个新的空对象
    2. 让this指向这个新的对象
    3. 执行构造函数里面的代码,给这个对象添加属性和方法
    4. 返回这个新对象

静态成员和实例成员

  • 在构造函数内添加的成员称为静态成员,只能由构造函数本身来访问
  • 在构造函数内部通过this创建的对象成员称为实例成员,只能由实例化的对象来访问
    function Star(uname,age){
        this.uname = uname; 
        this.age = age;
        this.sing = function(){
            console.log('我会唱歌');
        }
        // 上面这些都是实例成员
    }
    
    var lmk = new Star('两门课',18);
    Star.sex = '男'; // 这个为静态成员
    console.log(Star.sex) 结果是 男
    // 但是lmk不能访问这个sex属性

原型对象-prototype

  • 作用是实现了方法的共享
  • 每一个构造函数都有一个prototype属性,指向一个对象,这个prototype就是一个对象,这个对象的所有的属性和方法构造函数都可以调用和拥有
  • 实例
    function Star(uname,age){
        this.uname = uname; 
        this.age = age;
        // 上面这些都是实例成员
    }
    Star.prototype.sing = function(){
            console.log('我会唱歌');
        }
    var lmk = new Star('两门课',18); 
    var kml = new Star('kml',18); 
    // lmk和kml在调用sing方法是会找prototype这个原型对象
    console.log(lmk.sing === kml.sing) 返回 true
    
    // 一般情况下我们的公共属性定义到构造函数里面,公共的方法放在原型对象身上

对象原型 proto

  • 对象原型指向构造函数的prototype原型对象
  • 因为有了原型对象,所以对象就可以访问prototype对象原型的属性和方法了
function Star(uname,age){
    this.uname = uname; 
    this.age = age;
    // 上面这些都是实例成员
}
Star.prototype.sing = function(){
        console.log('我会唱歌');
    }
var lmk = new Star('两门课',18);
console.log(lmk);
// lmk的__proto__指向Star这个构造函数的prototype 
console.log(lmk.__proto__ === Star.prototype); // 返回true

// 方法的查找规则
// 先看lmk对象身上是否有sing方法,有就执行,没有就通过__proto__对象原型找构造函数的prototype这个原型对象的sing方法

面向对象

constructor函数

  • 在prototype和__proto__中都有一个constructor构造函数,并且该函数指回构造函数本身
  • 记录该对象引用了那个构造函数,可以让原型对象重新指向原来的构造函数
    // 很多情况下需要用constructor来指挥原来的构造函数
    
    function Star(uname,age){
        this.uname = uname; 
        this.age = age;
        // 上面这些都是实例成员
    }
    
    Star.prototype = {
        // 如果我们修改了原来的原型对象,给原型对象是赋值的而不是添加的,则必须利用constructor手动指回原来的构造函数
        constructor: Star,
        sing: function(){console.log('我会唱歌');},
        movie: function(){console.log('我会演电影');}
    }
    // 这里把prototype这个原型对象覆盖了,那么就没有constructor这个属性了
    // 需要重新指定一下原来的构造函数

构造函数,实例,原型对象三者之间的关系

  • 构造函数内有一个原型对象,通过prototype来指向原型对象prototype的
  • 原型对象prototype有一个constructor属性指回构造函数
  • 构造函数有可以实例化对象
  • 实例对象有一个__proto__对象原型,并指定到原型对象prototype
    关系

原型链

  • Star的ldh实例的__proto__对象原型指向prototype原型对象
  • Star的prototype原型对象中的constructor属性指回Star构造函数
  • Star的原型对象中也有一个__proto__对象原型指向的是Object的原型对象prototype
  • Object的原型对象中的constructor属性有只回Object构造函数
  • Object的Prototype也有一个__proto__对象原型指向的是一个 null(到顶了)
    原型链

原型对象的this指向

function Star(uname,age){
    this.uname = uname;  // 这里的this指向的是ldh这个实例
    this.age = age;
    // 上面这些都是实例成员
}
Star.prototype.sing = function(){
    console.log('我会唱歌')
}
var ldh = new Star('刘德华',18)
// 在构造函数中里面的this指向的是对象实例
// 原型对象里的this指向的是实例对象ldh 

利用原型对象扩展内置方法

// 通过这种方式扩展内置方法
Array.prototype.sum = function() {
    var sum = 0;
    for (var i = 0; i <= this.length; i++) {
        sum += i;
    }
    return sum;
}

var arr = [1, 2, 3, 4, 5]
console.log(arr.sum()); // 输出 15

继承

  • es6之前是通过 构造函数+原型对象来实现继承 称为组合继承

call()方法

  • 调用函数并修改这个函数运行时的this指向
    // 方法
    fun.call(thisArg,arg1)
    // thisArg: 当前调用函数的this指向
    // arg1: 是函数要传递的参数(有就写没就空)
  • 使用
    // call方法
    function fn(){
        console.log('我想喝手磨咖啡');
        console.log(this) // this是指向的window
    }
    
    // 定义一个函数
    var o = {
        name: 'nady'
    }
    fn(); // 调用函数
    fn.call(); // 用call调用
    
    // call()可以改变函数的this指向
    fn.call(o); // fn这个函数就指向了o这个对象

借用构造函数继承父类型的属性

  • 核心原理:通过call()把父类的this指向子类型的this这样可以实现子类继承父类属性
    // 父构造函数
    function F(uname,age){
        this.uname = uname;
        this.age = age;
    }
    // 子构造函数
    function S(uname,age){
        F.call(this,uname,age)
    }
    var son = new S('刘德华',18) // 这里是new的子构造函数
    // 子构造函数继承了父构造函数的属性
    console.log(son)

借用原型对象继承父类型的方法

function F(uname,age){
    this.uname = uname;
    this.age = age;
}
// 定义父构造函数方法
F.prototype.money = function(){
    console.log(1000000);   
} 
// 子构造函数
function S(uname,age){
    F.call(this,uname,age)
}

// 子构造函数通过指定父构造函数创建的实例对象来继承父构造函数的方法
S.prototype = new F();

// 由于自构造函数的prototype原型对象被覆盖了,所以要重新指定一下constructor指回原来的构造函数
S.prototype.constructor = S;

// 子构造函数添加自己的方法不回影响到父构造函数内的原型对象prototype
S.prototype.exam = function(){
    console.log('孩子要考试');
}
var son = new S('刘德华',18) // 这里是new的子构造函数
// 子构造函数继承了父构造函数的属性
console.log(son)

构造函数的特点

  • 构造函数有原型对象prototype
  • 构造函数原型对象prototype里面有constructor指向构造函数本身
  • 构造函数可以通过原型对象prototype来添加方法
  • 构造函数的实例对象有__proto__对象原型指向构造函数的prototype原型对象

本博客所有文章是以学习为目的,如果有不对的地方可以一起交流沟通共同学习 邮箱:1248287831@qq.com!