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 相关文章推荐
基于jquery的页面划词搜索JS
Sep 14 Javascript
字段太多jquey快速清空表单内容方法
Aug 21 Javascript
60行js代码实现俄罗斯方块
Mar 31 Javascript
移动端使用localStorage缓存Js和css文的方法(web开发)
Sep 20 Javascript
使用开源工具制作网页验证码的方法
Oct 17 Javascript
利用jquery获取select下拉框的值
Nov 23 Javascript
JS+HTML5 FileReader实现文件上传前本地预览功能
Mar 27 Javascript
Node.js中sequelize时区的配置方法
Dec 10 Javascript
微信小程序实现运动步数排行功能(可删除)
Jul 05 Javascript
jQuery事件绑定和解绑、事件冒泡与阻止事件冒泡及弹出应用示例
May 13 jQuery
vue-cli3使用mock数据的方法分析
Mar 16 Javascript
js不常见操作运算符总结
Nov 20 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函数代码
2010/04/22 PHP
php中文验证码实现示例分享
2014/01/12 PHP
PHP中构造函数和析构函数解析
2014/10/10 PHP
Laravel4中的Validator验证扩展用法详解
2016/07/26 PHP
js 关键词高亮(根据ID/tag高亮关键字)案例介绍
2013/01/21 Javascript
JavaScript中document对象使用详解
2015/01/06 Javascript
jQuery实现的图文高亮滚动切换特效实例
2015/08/10 Javascript
xmlplus组件设计系列之按钮(2)
2017/04/26 Javascript
基于hover的用法实例(推荐)
2017/07/04 Javascript
Angular项目中$scope.$apply()方法的使用详解
2017/07/26 Javascript
VueAwesomeSwiper在VUE中的使用以及遇到的一些问题
2018/01/11 Javascript
微信小程序onLaunch异步,首页onLoad先执行?
2018/09/20 Javascript
详解如何使用微信小程序云函数发送短信验证码
2019/03/13 Javascript
vue elementUI table表格数据 滚动懒加载的实现方法
2019/04/04 Javascript
vue中实现上传文件给后台实例详解
2019/08/22 Javascript
element-ui中el-upload多文件一次性上传的实现
2020/12/02 Javascript
vue使用echarts画组织结构图
2021/02/06 Vue.js
[01:09:50]VP vs Pain 2018国际邀请赛小组赛BO2 第二场
2018/08/20 DOTA
Python多进程通信Queue、Pipe、Value、Array实例
2014/11/21 Python
Python制作钉钉加密/解密工具
2016/12/07 Python
python 安装virtualenv和virtualenvwrapper的方法
2017/01/13 Python
Python通过调用mysql存储过程实现更新数据功能示例
2018/04/03 Python
python 删除字符串中连续多个空格并保留一个的方法
2018/12/22 Python
python 使用turtule绘制递归图形(螺旋、二叉树、谢尔宾斯基三角形)
2019/05/30 Python
详解使用django-mama-cas快速搭建CAS服务的实现
2019/10/30 Python
Python中zip()函数的解释和可视化(实例详解)
2020/02/16 Python
Python实现Kerberos用户的增删改查操作
2020/12/14 Python
一款纯css3实现的鼠标经过按钮特效教程
2014/11/09 HTML / CSS
英国领先的狗和宠物美容专家:Christies Direct
2017/04/03 全球购物
印尼购物网站:iLOTTE
2019/10/16 全球购物
应用数学专业求职信
2014/03/14 职场文书
劳资协议书范本
2014/04/23 职场文书
交通安全月活动总结
2015/05/08 职场文书
CSS3 实现的图片悬停的切换按钮
2021/04/13 HTML / CSS
深入浅析Django MTV模式
2021/09/04 Python
前端JavaScript大管家 package.json
2021/11/02 Javascript