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 相关文章推荐
js 动态文字滚动的例子
Jan 17 Javascript
禁止选中文字兼容IE、Chrome、FF等
Sep 04 Javascript
jQuery 属性选择器element[herf*='value']使用示例
Oct 20 Javascript
JavaScript中的条件判断语句使用详解
Jun 03 Javascript
Bootstrap Modal遮罩弹出层代码分享
Nov 21 Javascript
vue.js默认路由不加载linkActiveClass问题的解决方法
Dec 11 Javascript
JavaScript反射与依赖注入实例详解
May 29 Javascript
可能被忽略的一些JavaScript数组方法细节
Feb 28 Javascript
JQuery常见节点操作实例分析
May 15 jQuery
判断js数据类型的函数实例详解
May 23 Javascript
JS面试题中深拷贝的实现讲解
May 07 Javascript
微信小程序实现底部弹出模态框
Nov 18 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编写PDF文档生成器
2006/10/09 PHP
将OICQ数据转成MYSQL数据
2006/10/09 PHP
PHP EOT定界符的使用详解
2008/09/30 PHP
PHP iconv 函数转gb2312的bug解决方法
2009/10/11 PHP
关于Sphinx创建全文检索的索引介绍
2013/06/25 PHP
php中最简单的字符串匹配算法
2014/12/16 PHP
PHP实现即时输出、实时输出内容方法
2015/05/27 PHP
php封装好的人民币数值转中文大写类
2015/12/20 PHP
PHP解析url并得到url参数方法总结
2018/10/11 PHP
JavaScript 模仿vbs中的 DateAdd() 函数的代码
2007/08/13 Javascript
jQuery 学习第七课 扩展jQuery的功能 插件开发
2010/05/17 Javascript
当jQuery1.7遇上focus方法的问题
2014/01/26 Javascript
采用call方式实现js继承
2014/05/20 Javascript
微信小程序 增、删、改、查操作实例详解
2017/01/13 Javascript
Vue项目中如何引入icon图标
2018/03/28 Javascript
vue项目中,main.js,App.vue,index.html的调用方法
2018/09/20 Javascript
关于引入vue.js 文件的知识点总结
2020/01/28 Javascript
vue中渲染对象中属性时显示未定义的解决
2020/07/31 Javascript
解决vuex改变了state的值,但是页面没有更新的问题
2020/11/12 Javascript
javascript实现左右缓动动画函数
2020/11/25 Javascript
[40:55]DOTA2上海特级锦标赛主赛事日 - 2 败者组第二轮#4Newbee VS Fnatic
2016/03/03 DOTA
用Python中的__slots__缓存资源以节省内存开销的方法
2015/04/02 Python
python的else子句使用指南
2016/02/27 Python
Python使用剪切板的方法
2017/06/06 Python
通过python+selenium3实现浏览器刷简书文章阅读量
2017/12/26 Python
PyCharm中代码字体大小调整方法
2019/07/29 Python
python hmac模块验证客户端的合法性
2020/11/07 Python
Html5游戏开发之乒乓Ping Pong游戏示例(二)
2013/01/21 HTML / CSS
HTML5 Blob 实现文件下载功能的示例代码
2019/11/29 HTML / CSS
自考生毕业自我鉴定
2013/10/10 职场文书
《中国的气候》教学反思
2014/02/23 职场文书
2014年教研活动总结范文
2014/04/26 职场文书
创业培训计划书
2014/05/03 职场文书
幼儿园教师演讲稿
2014/05/06 职场文书
学校班班通实施方案
2014/06/11 职场文书
剧场版《转生恶役只好拔除破灭旗标》公开最新视觉图 2023年上映
2022/04/02 日漫