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 相关文章推荐
关于document.cookie的使用javascript
Oct 29 Javascript
js播放wav文件(源码)
Apr 22 Javascript
Jquery实现Div上下移动示例
Apr 23 Javascript
Vuejs入门教程之Vue生命周期,数据,手动挂载,指令,过滤器
Apr 19 Javascript
JS全角与半角转化实例(分享)
Jul 04 Javascript
使用JS获取页面上的所有标签
Oct 18 Javascript
深入浅析Vue 中 ref 的使用
Apr 29 Javascript
Node.js实现一个HTTP服务器的方法示例
May 13 Javascript
js实现随机点名器精简版
Jun 29 Javascript
JS call()及apply()方法使用实例汇总
Jul 11 Javascript
Vue切换div显示隐藏,多选,单选代码解析
Jul 14 Javascript
javascript条件式访问属性和箭头函数介绍
Nov 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 过滤页面中的BOM(实现代码)
2013/06/29 PHP
PHP下获取上个月、下个月、本月的日期(strtotime,date)
2014/02/02 PHP
php实现多维数组中每个单元值(数字)翻倍的方法
2015/02/16 PHP
CI配置多数据库访问的方法
2016/03/28 PHP
javascript:void(0)的真正含义实例分析
2008/08/20 Javascript
jQuery取得设置清空select选择的文本与值
2014/07/08 Javascript
js使用DOM操作实现简单留言板的方法
2015/04/10 Javascript
jQuery中extend函数详解
2015/07/13 Javascript
js获取对象、数组的实际长度,元素实际个数的实现代码
2016/06/08 Javascript
bootstrap datepicker限定可选时间范围实现方法
2016/09/28 Javascript
微信小程序开发实战教程之手势解锁
2016/11/18 Javascript
jsp 自动编译机制详细介绍
2016/12/01 Javascript
jQuery模拟下拉框选择对应菜单的内容
2017/03/07 Javascript
深入理解Vue transition源码分析
2017/07/30 Javascript
浅析vue.js数组的变异方法
2018/06/30 Javascript
JavaScript错误处理操作实例详解
2019/01/04 Javascript
JavaScript实现浏览器网页自动滚动并点击的示例代码
2020/12/05 Javascript
[03:24]CDEC.Y赛前采访 努力备战2016国际邀请赛中国区预选赛
2016/06/25 DOTA
简单讲解Python编程中namedtuple类的用法
2016/06/21 Python
windows下ipython的安装与使用详解
2016/10/20 Python
python基础之入门必看操作
2017/07/26 Python
python+pillow绘制矩阵盖尔圆简单实例
2018/01/16 Python
python opencv 图像尺寸变换方法
2018/04/02 Python
Python 机器学习库 NumPy入门教程
2018/04/19 Python
Python第三方库face_recognition在windows上的安装过程
2019/05/03 Python
Django如何使用第三方服务发送电子邮件
2019/08/14 Python
Python如何把十进制数转换成ip地址
2020/05/25 Python
Internet主要有哪些网络群组成
2015/12/24 面试题
致短跑运动员广播稿
2014/01/09 职场文书
大宝sod蜜广告词
2014/03/21 职场文书
医院信息公开实施方案
2014/05/09 职场文书
企业安全生产检查制度
2015/08/06 职场文书
2016入党积极分子党课学习心得体会
2015/10/09 职场文书
使用Redis实现秒杀功能的简单方法
2021/05/08 Redis
详解Alibaba Java诊断工具Arthas查看Dubbo动态代理类
2022/04/08 Java/Android
Android开发之底部导航栏的快速实现
2022/04/28 Java/Android