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 相关文章推荐
非常有用的40款jQuery 插件推荐(系列二)
Dec 25 Javascript
Javascript中判断变量是数组还是对象(array还是object)
Aug 14 Javascript
request请求获取参数的实现方法(post和get两种方式)
Sep 27 Javascript
简单谈谈JS数组中的indexOf方法
Oct 13 Javascript
JS版微信6.0分享接口用法分析
Oct 13 Javascript
node.js平台下的mysql数据库配置及连接
Mar 31 Javascript
jquery replace方法去空格
May 08 jQuery
ionic 3.0+ 项目搭建运行环境的教程
Aug 09 Javascript
简述Angular 5 快速入门
Nov 04 Javascript
vue 中引用gojs绘制E-R图的方法示例
Aug 24 Javascript
Vue.js子组件向父组件通信的方法实例代码详解
Dec 10 Javascript
vue实现公共方法抽离
Jul 31 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/04/28 PHP
php使用ZipArchive提示Fatal error: Class ZipArchive not found in的解决方法
2014/11/04 PHP
Redis在Laravel项目中的应用实例详解
2017/08/11 PHP
PHP操作Redis数据库常用方法示例
2018/08/25 PHP
php利用ZipArchive类操作文件的实例
2020/01/21 PHP
通过Mootools 1.2来操纵HTML DOM元素
2009/09/15 Javascript
jQuery dialog 异步调用ashx,webservice数据的代码
2010/08/03 Javascript
初学js插入节点appendChild insertBefore使用方法
2011/07/04 Javascript
jquery实现固定顶部导航效果(仿蘑菇街)
2013/03/21 Javascript
js遍历、动态的添加数据的小例子
2013/06/22 Javascript
JavaScript常用脚本汇总(三)
2015/03/04 Javascript
jQuery实现冻结表格行和列
2015/04/29 Javascript
元素绑定click点击事件方法
2015/06/08 Javascript
简介JavaScript中的getSeconds()方法的使用
2015/06/10 Javascript
jQuery实现多级联动下拉列表查询框
2016/01/18 Javascript
全面解析JavaScript的Backbone.js框架中的Router路由
2016/05/05 Javascript
jQuery实现简单的tab标签页效果
2016/09/12 Javascript
Jquery Easyui验证组件ValidateBox使用详解(20)
2016/12/18 Javascript
详解js的异步编程技术的方法
2017/02/09 Javascript
layer.confirm()右边按钮实现href的例子
2019/09/27 Javascript
uni-app使用countdown插件实现倒计时
2020/11/01 Javascript
python 实现堆排序算法代码
2012/06/05 Python
跟老齐学Python之list和str比较
2014/09/20 Python
几个提升Python运行效率的方法之间的对比
2015/04/03 Python
numpy.ndarray 交换多维数组(矩阵)的行/列方法
2018/08/02 Python
Python实现的旋转数组功能算法示例
2019/02/23 Python
python实现简单图书管理系统
2019/11/22 Python
python 如何区分return和yield
2020/09/22 Python
Python脚本调试工具安装过程
2021/01/11 Python
canvas之自定义头像功能实现代码示例
2017/09/29 HTML / CSS
什么是数据抽象
2016/11/26 面试题
自愿离婚协议书范文2014
2014/10/12 职场文书
2014年残疾人工作总结
2014/12/06 职场文书
婚礼庆典答谢词
2015/01/20 职场文书
给老师的保证书怎么写
2015/05/09 职场文书
安全教育片观后感
2015/06/17 职场文书