zoukankan      html  css  js  c++  java
  • JavaScript

    ### JavaScript - 基于原型的面向对象

    1. 引言

    JavaScript 是一种基于原型的面向对象语言,而不是基于类的!!!

    • 基于类的面向对象语言,比如 Java,是构建在两个不同实体的概念之上的:即类和对象。

    • 基于原型的语言(如 JavaScript)并不存在这种区别:它只有对象。基于原型的语言具有所谓原型对象(prototypical object)的概念。原型对象可以作为一个模板,新对象可以从中获得原始的属性。任何对象都可以指定其自身的属性,既可以是创建时也可以在运行时创建。而且,任何对象都可以作为另一个对象的原型(prototype),从而允许后者共享前者的属性。

    对象的产生

    • 基于类的面向对象语言: 依靠类产生
    • 基于原型的面向对象语言: 依靠 构造器利用原型构造出来的。

    例如工厂造一辆车,一方面,工人必须参照一张工程图纸,设计规定这辆车应该如何制造。这里的工程图纸就好比是语言中的 类 (class),而车就是按照这个 类(class)制造出来的;另一方面,工人和机器 ( 相当于 constructor) 利用各种零部件如发动机,轮胎,方向盘 ( 相当于 prototype 的各个属性 ) 将汽车构造出来。

    2.构造对象

    • 字面式对象声明

    例如:

    var test = {
        name : 'Test',
        email : '123@qq.com'
        website : 'http://www.test.com'
    }
    

    然后可以访问

    //以成员的方式
    test.name;
    test.email;
    //以hash_map的方式
    test["name"];
    test["website"];
    
    • 使用函数构造器构造对象

    每个构造器实际上是一个 函数(function) 对象, 该函数对象含有一个“prototype”属性用于实现 基于原型的继承(prototype-based inheritance)和 共享属性(shared properties)。

    对象可以由“new 关键字 + 构造器调用”的方式来创建

    // 构造器 Person 本身是一个函数对象 
    function Person() { // 此处可做一些初始化工作 }
    // 它有一个名叫 prototype 的属性
    Person.prototype = { 
    	name: "张三", 
    	age: 26, 
    	gender: "男",
    	eat: function(stuff){ 
    		alert("我在吃" + stuff); 
    	} 
    } // 使用 new 关键字构造对象 var p = new Person();
    

    3.理解原型链

    每个由构造器创建的对象拥有一个指向构造器 prototype 属性值的 隐式引用(implicit reference),这个引用称之为 原型(prototype)。进一步,每个原型可以拥有指向自己原型的 隐式引用(即该原型的原型),如此下去,这就是所谓的 原型链(prototype chain) 。

    在具体的语言实现中,每个对象都有一个 proto 属性来实现对原型的 隐式引用。

    function Person(name){
    	this.name = name; 
    } 
    var p = new Person(); 
    console.log(p.__proto__ === Person.prototype ); // 对象的隐式引用指向了构造器的 prototype 属性,所以此处打印 true 
    console.log(Person.prototype.__proto__ === Object.prototype ); //原型本身是一个 Object 对象,所以他的隐式引用指向了Object 构造器的 prototype 属性 , 故而打印 true 
    console.log(Person.__proto__ === Function.prototype );// 构造器 Person 本身是一个函数对象,所以此处打印 true
    

    有了 原型链,便可以定义一种所谓的 属性隐藏机制,并通过这种机制实现继承。当要给某个对象的属性赋值时,解释器会查找该对象原型链中第一个含有该属性的对象(注:原型本身就是一个对象,那么原型链即为一组对象的链。对象的原型链中的第一个对象是该对象本身)进行赋值。反之,如果要获取某个对象属性的值,解释器自然是返回该对象原型链中首先具有该属性的对象属性值。下图说名了这中隐藏机制:

    object1->prototype1->prototype2 构成了 对象 object1 的原型链,根据上述属性隐藏机制,可以清楚地看到 prototype1 对象中的 property4 属性和 prototype2 对象中的 property3 属性皆被隐藏。(因为解释器会查找该对象原型链中第一个含有该属性的对象

    4.继承

    • 利用原型链 Horse->Mammal->Animal 实现继承

        // 声明 Animal 对象构造器 
        function Animal(){}  // 将Animal 的 prototype 属性指向一个对象,亦可直接理解为指定 Animal 对象的原型 
        Animal.prototype = { 
        	name: "animal",
        	weight: 0, 
        	eat: function(){ 
        		alert( "Animal is eating!" ); 
        	} 
        } 
        
        // 声明 Mammal 对象构造器 function
        Mammal() { this.name = "mammal"; } // 指定 Mammal 对象的原型为一个 Animal 对象。 
        Mammal.prototype = new Animal(); // 实际上此处便是在创建 Mammal 对象和 Animal 对象之间的原型链 
        
        // 声明 Horse 对象构造器 
        function Horse(height,weight){ 
        	this.name = "horse"; 
        	this.height = height; 
        	this.weight = weight;
        } 
        // 将 Horse对象的原型指定为一个 Mamal 对象,继续构建 Horse 与 Mammal 之间的原型链 
        Horse.prototype = new Mammal(); // 重新指定 eat方法 , 此方法将覆盖从 Animal 原型继承过来的 eat 方法 
        Horse.prototype.eat = function() { 
        	alert( "Horse is eating grass!"); 
        } 
        
        // 验证并理解原型链 
        var horse = new Horse( 100, 300 ); 
        console.log(horse.__proto__ === Horse.prototype ); 
        console.log( Horse.prototype.__proto__ === Mammal.prototype ); 
        console.log( Mammal.prototype.__proto__ === Animal.prototype );
      
    • 类式继承

    基于原型的继承方式,虽然实现了代码复用,但其行文松散且不够流畅,可阅读性差,不利于实现扩展和对源代码进行有效地组织管理。

    所以,类式继承方式在语言实现上更具健壮性,且在构建可复用代码和组织架构程序方面具有明显的优势。这使得程序员们希望寻找到一种能够在 JavaScript 中以类式继承风格进行编码的方法途径。

    jQuery 之父 John Resig 在搏众家之长之后,用不到 30 行代码便实现了自己的 Simple Inheritance。使用其提供的 extend 方法声明类非常简单。

    4.JavaScript 私有成员实现

    JavaScript 的信息隐藏就是靠闭包实现的。

    // 声明 User 构造器 
     function User( pwd ) { 
     	var password = pwd; // 定义私有属性 
            // 定义私有方法 
        function getPassword() { // 返回了闭包中的 password   	
        	return password; 
        } // 特权函数声明,用于该对象其他公有方法能通过该特权方法访问到私有成员 
        this.passwordService = function() { 
        	return getPassword();
        } 
    } 
    // 公有成员声明 
    User.prototype.checkPassword = function( pwd ) { 
    	return this.passwordService() === pwd; 
    }; 
    // 验证隐藏性 
    var u = new User( "123456" ); 
    console.log( u.checkPassword("123456" )); // 打印 true 
    console.log( u.password ); // 打印 undefined 
    console.log( typeof u.getPassword === "undefined" );// 打印 true
    

    JavaScript的prototype 具体含义,或者继承机制的设计思想,良心推荐,讲的非常清楚。

    http://www.ruanyifeng.com/blog/2011/06/designing_ideas_of_inheritance_mechanism_in_javascript.html

  • 相关阅读:
    Atitit sql计划任务与查询优化器统计信息模块
    Atitit  数据库的事件机制触发器与定时任务attilax总结
    Atitit 图像处理知识点体系知识图谱 路线图attilax总结 v4 qcb.xlsx
    Atitit 图像处理 深刻理解梯度原理计算.v1 qc8
    Atiti 数据库系统原理 与数据库方面的书籍 attilax总结 v3 .docx
    Atitit Mysql查询优化器 存取类型 范围存取类型 索引存取类型 AND or的分析
    Atitit View事件分发机制
    Atitit 基于sql编程语言的oo面向对象大规模应用解决方案attilax总结
    Atitti 存储引擎支持的国内点与特性attilax总结
    Atitit 深入理解软件的本质 attilax总结 软件三原则"三次原则"是DRY原则和YAGNI原则的折
  • 原文地址:https://www.cnblogs.com/tina-smile/p/5712697.html
Copyright © 2011-2022 走看看