JS面向对象编程

创建对象

JavaScript对每个创建的对象都会设置一个原型(__proto__),指向它的原型对象。

当我们用obj.xxx访问一个对象的属性时,JavaScript引擎先在当前对象上查找该属性,如果没有找到,就到其原型对象上找,如果还没有找到,就一直上溯到Object.prototype对象,最后,如果还没有找到,就只能返回undefined。

  • eg: 创建一个Array对象: var arr = [1, 2, 3];
    其原型链是:
    arr ----> Array.prototype ----> Object.prototype ----> null
    Array.prototype定义了indexOf()shift()等方法,因此你可以在所有的Array对象上直接调用这些方法。
  • eg: 创建一个函数时:
    function foo() { return 0; }函数也是一个对象,它的原型链是:
    foo ----> Function.prototype ----> Object.prototype ----> null
    由于Function.prototype定义了apply()等方法,因此,所有函数都可以调用apply()方法。

JS原型和原型链简介

1. 构造函数

构造函数是一种特殊的方法。主要用来在创建对象时初始化对象。每个构造函数都有prototype(原型)属性

  • 传统创建对象实例的方法
var person={
      name:'张女士',
      age:'80',
      gender:'女'
  };
console.log(person)

注:这个方法如果用于创建大量相同属性和方法的对象时,会产生大量重复代码

  • 构造函数的方法
function Student(name) {
    this.name = name;
    this.hello = function () {
        alert('Hello, ' + this.name + '!');
    }
}
var xiaoming = new Student('小明');

注意:如果不写new,这就是一个普通函数,它返回undefined。但是,如果写了new,它就变成了一个构造函数,它绑定的this指向新创建的对象,并默认返回this,也就是说,不需要在最后写return this;
xiaoming的原型链是: xiaoming ----> Student.prototype ----> Object.prototype ---->null

  • 每个( 原型对象 )都有一个constructor属性,指向prototype属性所在的函数
    eg:
    xiaoming.constructor == Student; //constructor指向构造函数
    xiaoming.constructor == Student.prototype.constructor == Student

2.原型模式

每个函数都有原型属性(__proto__),这个属性是一个指针,指向一个对象,这个对象(prototype)的用途是包含特定类型的所有实例共享的属性和方法,即这个原型对象是用来给实例共享属性和方法的。而每个实例内部都有一个指向原型对象的指针

如果我们通过new Student()创建了很多对象,这些对象的hello函数实际上只需要共享同一个函数就可以了,这样可以节省很多内存。
要让创建的对象共享一个hello函数,根据对象的属性查找原则,我们只要把hello函数移动到xiaoming、xiaohong这些对象共同的原型上就可以了,也就是Student.prototype

function Student(name) {
    this.name = name;
}
Student.prototype.hello = function () {
    alert('Hello, ' + this.name + '!');
};
  • 还可以编写一个createStudent()函数,在内部封装所有的new操作
function Student(props){
     this.name = props.name || '匿名'; //默认值为匿名
     this.grade = props.grade || 1;
}
Student.prototype.hello = function(){
    alert('Hello, '+this.name+'!');
}
function creatStudent(props){
    return new Student(props || {});
}

这个createStudent()函数有几个巨大的优点:一是不需要new来调用,二是参数非常灵活,可以不传,也可以这么传:
var xiaoming = createStudent({name: '小明'});
xiaoming.grade; // 1
如果创建的对象有很多属性,我们只需要传递需要的某些属性,剩下的属性可以用默认值。由于参数是一个Object,我们无需记忆参数的顺序。如果恰好从JSON拿到了一个对象,就可以直接创建出xiaoming。

3. 原型链

每个构造函数都有原型对象,每个构造函数实例都包含一个指向原型对象的内部指针(__proto__)(即:实例.__proto__ === 构造函数.prototype),如果我们让第一个构造函数的原型对象等于第二个构造函数的实例,结果第一个构造函数的原型对象将包含一个指向第二个原型对象的指针,再然第三个原型对象等于第一个构造函数的实例,这样第三个原型对象也将包含指向第一个原型对象的指针,以此类推,就够成了实例于原型的链条,这就是原型链的基本概念

function One(){
}
function Two(){
}
function Three(){
}
Two.prototype=new One();
            
Three.prototype=new Two();
            
var three=new Three();

console.log(three);
console.log(three.__proto__===Three.prototype) //true
console.log(three.__proto__.__proto__===Two.prototype) //true
console.log(three.__proto__.__proto__.__proto__===One.prototype)  //true
console.log(three.__proto__.__proto__.__proto__.__proto__===Object.prototype)  //true

在对象实例中,访问对象原型的方法
1)使用proto属性:此属性是浏览器支持的一个属性,并不是ECMAScript里的属性
2)Object.getPrototypeOf
3)使用constructor.prototype的方法:对于不支持proto的浏览器,可以使用constructor,访问到对象的构造函数,在用prototype访问到原型

  • 自我理解
function One(){
}
function Two(){
}
function Three(){}

let one = new One();
one.__proto__ == One.prototype;
one.__proto__.__proto__ == One.prototype.__proto__ == Two.prototype;
one.__proto__.__proto__.__proto__ == Two.prototype.__proto__ == Three.prototype;

如果第一个构造函数的原型对象等于第二个构造函数的实例 ==> 第一个构造函数的原型对象包含指向第二个构造函数原型对象的指针
One.prototype = new Two(); One.prototype.__proto__ == Two.prototype;
如果第二个构造函数的原型对象等于第三个构造函数的实例 ==> 第二个构造函数的原型对象包含指向第三个构造函数运行对象的指针
Two.prototype = new Three(); Two.prototype.__proto__ == Three.prototype
第一个构造函数的实例的原型指向第一个构造函数的原型对象,第一个构造函数的原型对象的原型指向第二个构造函数的原型对象,第二个构造函数的原型对象的原型指向第三个构造函数的原型对象

  • 总结
    __proto__为函数(实际上__proto__是所有对象(包括函数)都有的,原型链是靠它形成的)的原型属性
    prototype 为原型对象(准确的来说只有构造函数才有的,它跟原型链没有关系)
    每个object的原型属性(__proto__)指向指向他的原型(prototype

原型继承

  • 把继承这个动作用一个inherits()函数封装起来
function inherits(Child, Parent) {
    var F = function () {}; //注意,函数F仅用于桥接,我们仅创建了一个new F()实例,而且,没有改变原有的Student定义的原型链。
    F.prototype = Parent.prototype;
    Child.prototype = new F();
    Child.prototype.constructor = Child;
}

你可能感兴趣的:(JS面向对象编程)