javascript面向对象程序设计(一)


Posted in Javascript onJanuary 29, 2015

注释里讲解的十分细致了,这里就不多废话了,直接上代码:

<script type="text/javascript">
  //ECMA-262把对象定义为:“无序属性的 集合,其属性可以包含基本值、对象或者函数”
  //理解对象,最简单的方式就是通过创建一个Object的实例,然后为它添加属性和方法
  var person = new Object();
  person.name = "Xulei";
  person.age = "23";
  person.job = "前端工程师";
  person.sayName = function () {
   alert(this.name);
  }
  //还可以这样写
  var person = {
   name: "xulei",
   age: 23,
   job: "前端工程",
   sayName: function () {
    alert(this.name)
   }
  }
  //一、属性类型:数据属性和访问其属性
  //1、数据属性,有4个描述其行为的特性
  //[Configurable]:表示能否通过delete删除属性从而重新定义属性,能否修改属性的特性,或者能否把属性修改为访问器属性,默认值为true
  //[Enumerable]:表示能否通过for-in返回属性,默认值为true
  //[Writable]:表示能否修改属性,默认值为true
  //[Value]:包含这个属性的数据值。默认值为undefined
  var person = {
   name: "xulei"
  }
  //这里创建了一个person对象,value值就是“xulei”
  //要修改属性的默认特性,必须使用ECMAScript5的Object.defineProperty(属性所在的对象,属性的名字,描述符对象)
  //描述符对象必须是configurable、enumerable、writable、value
  var peron = {}
  Object.defineProperty(peron, "name", {
   writable: false,//属性不能被修改
   value: "徐磊-xulei"
  });
  alert(peron.name);//徐磊-xulei
  peron.name = "徐磊";
  alert(peron.name);//徐磊-xulei
  //以上操作在非严格模式下赋值操作会被忽略,如果在严格模式下会抛出异常
  //一旦把属性定义为不可配置的就不能把它变回可配置的了。
  //在多数情况下都没有必要利用Object.defineProperty()方法提供的这些高级功能。但是对理解javascript非常有用。
  //建议读者不要在ie8上使用此方法。
  //2、访问其属性,有4个特性
  //[Configurable]:表示能否通过delete删除属性从而重新定义属性,能否修改属性的特性,或者能否把属性修改为访问器属性,默认值为true
  //[Enumerable]:表示能否通过for-in返回属性,默认值为true
  //[Get]:在读取时调用的函数 默认值undefined
  //[Set]:在写入属性时调用的函数 默认值Undefined
  var book={
   _year:2004,
   edition:1
  }
  Object.defineProperty(book,"year",{
   get:function(){
    return this._year;
   },
   set:function(value){
    if(value>2004){
     this._year=value;
     this.edition +=value-2004;
    }
   }
  });
  book.year=2005;
  alert(book.edition);//2
  //创建对象
  //1、将构造函数当做函数
  function Person(name,age,job) {
   this.name=name;
   this.age=age;
   this.job=job;
   this.sayName=function(){
    alert(this.name);
   }
  }
  //当做构造函数使用
  var person=new Person("xulei",23,"software");
  person.sayName();
  //作为普通函数使用
  Person("xulei2",23,"job2");//添加到window中
  window.sayName();
  //在另一个对象的作用域中调用
  var o=new Object();
  Person.call(o,"xulei3",23,"job3");
  o.sayName();
 </script>

再来一段:

<script type="text/javascript">
    //1、理解原型对象
    //2、原型与in操作符
    //3、更简单的原型语法
    //4、原型的动态性
    //5、原生对象原型
    //6、原型对象的问题

    //1、无论什么时候,只要创建了一个函数,就会根据一组特定的规则,为该函数创建一个prototype属性,该属性指向函数的原型对象
    //在默认情况下,所有的原型对象都会自动获得一个constructor(构造函数)属性,这个属性包含一个指向prototype属性所在函数的指针
    //如
    function Person(){

    }
    //Person.prototype.constructor 指向Person
    //创建了自定义的构造函数之后,其原型对象默认只会取得constructor属性,至于其他方法则都是从Object继承而来
    //当调用函数的创建一个新实例之后,该实例的内部包含一个指针(内部属性)指向构造函数的原型对象
    //在Firefox、safari、chrome在每个对象上都支持一个属性_proto_访问
    var p1=new Person();
    alert(Person.prototype.isPrototypeOf(p1))

    alert(Object.getPrototypeOf(p1)==Person.prototype)

    //虽然可以通过对象实例访问保存在原型中的值,但却不能通过对象实例重写原型中的值。如果我们在实例中添加了一个属性
    //而该属性的名称与原型的中的实例同名,那我们就在实例中创建该属性,该属性将会屏蔽原型中的那个属性。eg:
    function Person() {
    }
    Person.prototype.name="amber";
    Person.prototype.age=23;
    Person.prototype.job="software engineer";
    Person.prototype.sayName=function(){
      alert(this.name)
    }

    var person1=new Person();
    var person2=new Person();
    person1.name="amber.Xu";
    alert(person1.name);//amber.xu --来自实例
    alert(person2.name);//amber --来自原型

    delete person1.name;
    alert(person1.name);//amber --来自原型

    //使用hasOwnProperty()方法可以检测一个属性是存在于实例中还是存在于原型中,这个方法(从Object继承而来)
    //只在给定属性存在于对象实例中时,才会返回true
    function Person() {
    }
    Person.prototype.name="amber";
    Person.prototype.age=23;
    Person.prototype.job="software engineer";
    Person.prototype.sayName=function(){
      alert(this.name)
    }
    var person1=new Person();
    var person2=new Person();

    alert(person1.hasOwnProperty("name"));//false 来自实例

    alert(person2.hasOwnProperty("name"));//false 来自实例

    person1.name="amber.xu";
    alert(person1.name);
    alert(person1.hasOwnProperty("name"));//true 来自实例

    delete person1.name;
    alert(person1.name);
    alert(person1.hasOwnProperty("name"));//false 来自原型



    //2、原型与in操作符
    //in 有两种使用方式,一个是的单独使用和在for-in 中使用。在单独使用时,in操作符会在对象能够访问给定属性时返回true
    //无论该属性时来自原型还是实例
    function Person() {
    }
    Person.prototype.name="amber";
    Person.prototype.age=23;
    Person.prototype.job="software engineer";
    Person.prototype.sayName=function(){
      alert(this.name)
    }
    var person1=new Person();
    var person2=new Person();
    alert("name" in person1);//true 来自原型
    alert("name" in person2);//true 来自原型
    alert("height" in person1);//false


    //这样就可以封装一个函数(给定属性是否是来给定对象的原型)
    function hasPrototypeProperty(object,name){
      return !object.hasOwnProperty(name) && (name in object);
    }
    alert("----------------------------------");
    alert(hasPrototypeProperty(person1,"name"));//true

    person1.name="张三";
    alert(hasPrototypeProperty(person1,"name"));//false


    //使用for-in 返回的是所有能够通过对象访问、可枚举的属性,其中既包含原型属性也包含实例属性。
    //屏蔽了原型中不可枚举属性(将Enumerable标记为false的属性)的实例属性也会在for-in中返回
    //ie早期版本总中有一个bug:屏蔽了原型中不可枚举属性的实例属性也不会在for-in中返回
    //eg:
    var o={
      toString:function(){
        return "my object";
      }
    };

    for(var prop in o){
      if(prop=="toString"){
        alert("找到了");//在ie早期版本中不会显示
      }
    }

    //要取得对象上所有可枚举的属性,可以使用ECMAScript5的Object.keys()方法。接受一个对象作为参数,
    //包含所有可枚举属性的字符串数组
    function Person() {
    }
    Person.prototype.name="amber";
    Person.prototype.age=23;
    Person.prototype.job="software engineer";
    Person.prototype.sayName=function(){
      alert(this.name)
    }
    var person1=new Person();
    var person2=new Person();
    var keys=Object.keys(Person.prototype);
    alert(keys)

    person1.name="amber.Xu";
    person1.age=23;
    var keys=Object.keys(person1);
    alert(keys)

    alert("-----------------------------------------")
    //如果想要得到所有的实例属性不管他是否可以枚举,都可以使用
    alert(Object.getOwnPropertyNames(person1));
    alert(Object.getOwnPropertyNames(Person.prototype));

    alert("更简单的原型语法-----------------------------------------")
    //3、更简单的原型语法
    function Person() {

    }

    Person.prototype={
      name:"AMBER",
      age:23,
      job:"software",
      sayName:function(){
        alert(this.name)
      }
    }

    //这样写之后constructor属性不再指向Person函数,而是指向Object构造函数。
    //尽管通过instanceof操作符还能返回正确的结果,但是通过constructor已经无法确定对象的类型了,eg:
    var friend=new Person();
    alert(friend instanceof Person)//true
    alert(friend instanceof Object)//true
    alert(friend.constructor==Person);//false
    alert(friend.constructor==Object);//true
    //如果constructor对你真的很重要,可以向下面一样设置成适当的值

    function Person() {

    }

    Person.prototype={
      constructor:Person,
      name:"AMBER",
      age:23,
      job:"software",
      sayName:function(){
        alert(this.name)
      }
    }
    var friend=new Person();
    alert("手动设置constructor-----------------------------------------")
    alert(friend.constructor==Person);//true

    //这种手动的添加了constructor会使constructor变成可枚举的元(原生的constructor属性时不可枚举的)。
    //这种情况下就可以使用
    Object.defineProperty(Person.prototype,"constructor",{
      enumerable:false,
      value:Person
    });


    //原型的动态性
    var friend=new Person();
    Person.prototype.sayHi=function(){
      alert("Hi");
    }

    friend.sayHi();//Hi (正常执行)
    //因为实例和原型之间是松散的连接关系,实例与原型之间的连接只不过是一个指针,而非副本
    //当我们调用sayHi()方法时,首先会在实例中搜索名为sayHi的方法,在没找到的情况下会搜索原型。

    //但是,如果是重写整个原型对象,那么情况就不一样了。
    //我们知道,调用构造函数时会为实例添加一个指向最初原型的Prototype指针,而把原型修改为另一个对象就等于切断了构造函数与最初原型之间的联系。
    //请记住:实例中的指针仅指向原型,而不指向构造函数。eg:
    function A(){}
    var a1=new A();
    A.prototype={
      constructor:A,
      name:"AMBER",
      age:23,
      job:"software",
      sayName:function(){
        alert(this.name)
      }
    }
    alert("ERROR-------------------------------------");
    alert(a1.sayName());
    //我们创建了一个A的实例,然后又重写了其原型对象,然后在调用a1.sayName()发生了错误,因为a指向的原型中不包含以该名字命名的属性/方法

    //原生对象的原型
    //原型模式的重要性不仅体现在创建自定义类型方面。就连所有的原生的引用类型,都是采用这种模式创建的。所有的原生引用类型
    //都在其构造函数的原型上定义的方法 eg:
    alert(typeof Array.prototype.sort);//function
    alert(typeof String.prototype.substring);//function
    //不仅可以在原生对象的原型取得虽有默认方法的引用,而且可以定义新的方法
    //为String类型添加一个startsWith()的方法
    String.prototype.startsWith=function(text){
      return this.indexOf(text) == 0;
    };
    var msg="Hello";
    alert(msg.startsWith("H"));

    //我们并不建议这样做。

    alert("原型对象的问题");
    //6、原型对象的问题 实例
    function Ques() {
    }

    Ques.prototype={
      constructor:Ques,
      name:"amber",
      age:23,
      job:"IT",
      friends:["张三","李四"],//引用类型
      sayName:function(){
        alert(this.name)
      }
    };

    var q1=new Ques();
    var q2=new Ques();
    q1.friends.push("王五");
    alert(q1.friends);//
    alert(q2.friends);//
    alert(q1.friends===q2.friends);
  //相信大家已经看到了问题,当我创建了两个实例q1、q2,当我为q1的“朋友”添加了“王五”之后,q2的”朋友“也有了三个张三、李四、王五
  //那是因为数组存在于Ques.prototype上,而非q1上。所以出现了如上结果。

  //而正是这个问题,我们很少看到有人单独使用原型模式的原因所在。
  </script>

本文就先到这里了,后续我们再继续讨论javascript面向对象程序设计,希望大家能够喜欢。

Javascript 相关文章推荐
javascript 写类方式之七
Jul 05 Javascript
jquery lazyload延迟加载技术的实现原理分析
Jan 24 Javascript
js 剪切板的用法(clipboardData.setData)与js match函数介绍
Nov 19 Javascript
jQuery检测某个元素是否存在代码分享
Jul 09 Javascript
基于javascript实现listbox左右移动
Jan 29 Javascript
jquery点击改变class并toggle的实现代码
May 15 Javascript
通用无限极下拉菜单的实现代码
May 31 Javascript
seajs学习之模块的依赖加载及模块API的导出
Oct 20 Javascript
JavaScript之排序函数_动力节点Java学院整理
Jun 30 Javascript
vue实现点击当前标签高亮效果【推荐】
Jun 22 Javascript
微信小程序登录时如何获取input框中的内容
Dec 04 Javascript
javascript中的with语句学习笔记及用法
Feb 17 Javascript
jquery调取json数据实现省市级联的方法
Jan 29 #Javascript
JavaScript中实现单体模式分享
Jan 29 #Javascript
angular简介和其特点介绍
Jan 29 #Javascript
javascript实现获取浏览器版本、操作系统类型
Jan 29 #Javascript
浅谈javascript中自定义模版
Jan 29 #Javascript
jQuery和AngularJS的区别浅析
Jan 29 #Javascript
node.js中的forEach()是同步还是异步呢
Jan 29 #Javascript
You might like
根据中文裁减字符串函数的php代码
2013/12/03 PHP
php5.3提示Function ereg() is deprecated Error问题解决方法
2014/11/12 PHP
Zend Framework入门教程之Zend_Db数据库操作详解
2016/12/08 PHP
Django 中 cookie的使用
2017/08/17 PHP
Jquery Ajax.ashx 高效分页实现代码
2009/10/20 Javascript
javascript showModalDialog 内跳转页面的问题
2010/11/25 Javascript
jQuery修改CSS伪元素属性的方法
2014/07/30 Javascript
jQuery找出网页上最高元素的方法
2015/03/20 Javascript
JavaScript实现为input与textarea自定义hover,focus效果的方法
2015/08/21 Javascript
javascript HTML+CSS实现经典橙色导航菜单
2016/02/16 Javascript
JS异步文件分片断点上传的实现思路
2016/12/25 Javascript
Vue键盘事件用法总结
2017/04/18 Javascript
详解Node.js中exports和module.exports的区别
2017/04/19 Javascript
详解vue-router 2.0 常用基础知识点之导航钩子
2017/05/10 Javascript
AngularJS 购物车全选/取消全选功能的实现方法
2017/08/14 Javascript
9种使用Chrome Firefox 自带调试工具调试javascript技巧
2017/12/22 Javascript
解决vue-cli项目打包出现空白页和路径错误的问题
2018/09/04 Javascript
如何自动化部署项目?折腾服务器之旅~
2019/04/16 Javascript
vue-cli随机生成port源码的方法
2019/09/02 Javascript
解决LayUI数据表格复选框不居中显示的问题
2019/09/25 Javascript
基于vue与element实现创建试卷相关功能(实例代码)
2020/12/07 Vue.js
[04:52]2015国际邀请赛LGD战队晋级之路
2015/08/14 DOTA
从零学python系列之数据处理编程实例(一)
2014/05/22 Python
TensorFlow模型保存和提取的方法
2018/03/08 Python
python实现生成Word、docx文件的方法分析
2019/08/30 Python
Python 生成VOC格式的标签实例
2020/03/10 Python
python re.match()用法相关示例
2021/01/27 Python
html5播放视频且动态截图实现步骤与代码(支持safari其他未测试)
2013/01/06 HTML / CSS
美国标志性加大尺码时装品牌:Ashley Stewart
2016/12/15 全球购物
Bibloo匈牙利:女装、男装、童装及鞋子和配饰
2019/04/14 全球购物
天猫活动策划方案
2014/08/21 职场文书
意外伤害赔偿协议书范本
2014/09/28 职场文书
计算机实训报告总结
2014/11/05 职场文书
《田忌赛马》教学反思
2016/02/19 职场文书
JDBC连接的六步实例代码(与mysql连接)
2021/05/12 MySQL
Django+Nginx+uWSGI 定时任务的实现方法
2022/01/22 Python