来自 服务器&运维 2019-12-04 16:28 的文章
当前位置: 澳门威尼斯人平台 > 服务器&运维 > 正文

javascript面向对象程序设计_javascript技巧_脚本之家澳门威尼斯人平台

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

ECMA-262把对象定义为:“无序属性的 集合,其属性可以包含基本值、对象或者函数”

导语

本文实例讲述了javascript面向对象程序设计实践常用知识点。分享给大家供大家参考,具体如下:

 //ECMA-262把对象定义为:“无序属性的 集合,其属性可以包含基本值、对象或者函数” //理解对象,最简单的方式就是通过创建一个Object的实例,然后为它添加属性和方法 var person = new Object(); person.name = "Xulei"; person.age = "23"; person.job = "前端工程师"; person.sayName = function ; } //还可以这样写 var person = { name: "xulei", age: 23, job: "前端工程", sayName: function  } } //一、属性类型:数据属性和访问其属性 //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;//徐磊-xulei peron.name = "徐磊"; alert;//徐磊-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{ if{ this._year=value; this.edition +=value-2004; } } }); book.year=2005; alert;//2 //创建对象 //1、将构造函数当做函数 function Person { this.name=name; this.age=age; this.job=job; this.sayName=function; } } //当做构造函数使用 var person=new Person("xulei",23,"software"); person.sayName(); //作为普通函数使用 Person;//添加到window中 window.sayName(); //在另一个对象的作用域中调用 var o=new Object(); Person.call; o.sayName(); 

 //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 alert(Object.getPrototypeOf==Person.prototype) //虽然可以通过对象实例访问保存在原型中的值,但却不能通过对象实例重写原型中的值。如果我们在实例中添加了一个属性 //而该属性的名称与原型的中的实例同名,那我们就在实例中创建该属性,该属性将会屏蔽原型中的那个属性。eg: function Person() { } Person.prototype.name="amber"; Person.prototype.age=23; Person.prototype.job="software engineer"; Person.prototype.sayName=function } var person1=new Person(); var person2=new Person(); person1.name="amber.Xu"; alert;//amber.xu --来自实例 alert;//amber --来自原型 delete person1.name; alert;//amber --来自原型 //使用hasOwnProperty()方法可以检测一个属性是存在于实例中还是存在于原型中,这个方法 //只在给定属性存在于对象实例中时,才会返回true function Person() { } Person.prototype.name="amber"; Person.prototype.age=23; Person.prototype.job="software engineer"; Person.prototype.sayName=function } var person1=new Person(); var person2=new Person(); alert(person1.hasOwnProperty;//false 来自实例 alert(person2.hasOwnProperty;//false 来自实例 person1.name="amber.xu"; alert; alert(person1.hasOwnProperty;//true 来自实例 delete person1.name; alert; alert(person1.hasOwnProperty;//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 } var person1=new Person(); var person2=new Person(); alert;//true 来自原型 alert;//true 来自原型 alert;//false //这样就可以封装一个函数 function hasPrototypeProperty{ return !object.hasOwnProperty && ; } alert("----------------------------------"); alert(hasPrototypeProperty;//true person1.name="张三"; alert(hasPrototypeProperty;//false //使用for-in 返回的是所有能够通过对象访问、可枚举的属性,其中既包含原型属性也包含实例属性。 //屏蔽了原型中不可枚举属性(将Enumerable标记为false的属性)的实例属性也会在for-in中返回 //ie早期版本总中有一个bug:屏蔽了原型中不可枚举属性的实例属性也不会在for-in中返回 //eg: var o={ toString:function(){ return "my object"; } }; for{ if{ alert;//在ie早期版本中不会显示 } } //要取得对象上所有可枚举的属性,可以使用ECMAScript5的Object.keys()方法。接受一个对象作为参数, //包含所有可枚举属性的字符串数组 function Person() { } Person.prototype.name="amber"; Person.prototype.age=23; Person.prototype.job="software engineer"; Person.prototype.sayName=function } var person1=new Person(); var person2=new Person(); var keys=Object.keys; alert person1.name="amber.Xu"; person1.age=23; var keys=Object.keys alert("-----------------------------------------") //如果想要得到所有的实例属性不管他是否可以枚举,都可以使用 alert(Object.getOwnPropertyNames; alert(Object.getOwnPropertyNames; alert("更简单的原型语法-----------------------------------------") //3、更简单的原型语法 function Person() { } Person.prototype={ name:"AMBER", age:23, job:"software", sayName:function } } //这样写之后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 } } 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; } friend.sayHi //因为实例和原型之间是松散的连接关系,实例与原型之间的连接只不过是一个指针,而非副本 //当我们调用sayHi()方法时,首先会在实例中搜索名为sayHi的方法,在没找到的情况下会搜索原型。 //但是,如果是重写整个原型对象,那么情况就不一样了。 //我们知道,调用构造函数时会为实例添加一个指向最初原型的Prototype指针,而把原型修改为另一个对象就等于切断了构造函数与最初原型之间的联系。 //请记住:实例中的指针仅指向原型,而不指向构造函数。eg: function A; A.prototype={ constructor:A, name:"AMBER", age:23, job:"software", sayName:function } } alert("ERROR-------------------------------------"); alert; //我们创建了一个A的实例,然后又重写了其原型对象,然后在调用a1.sayName()发生了错误,因为a指向的原型中不包含以该名字命名的属性/方法 //原生对象的原型 //原型模式的重要性不仅体现在创建自定义类型方面。就连所有的原生的引用类型,都是采用这种模式创建的。所有的原生引用类型 //都在其构造函数的原型上定义的方法 eg: alert(typeof Array.prototype.sort);//function alert(typeof String.prototype.substring);//function //不仅可以在原生对象的原型取得虽有默认方法的引用,而且可以定义新的方法 //为String类型添加一个startsWith()的方法 String.prototype.startsWith=function{ return this.indexOf == 0; }; var msg="Hello"; alert; //我们并不建议这样做。 alert; //6、原型对象的问题 实例 function Ques() { } Ques.prototype={ constructor:Ques, name:"amber", age:23, job:"IT", friends:["张三","李四"],//引用类型 sayName:function } }; var q1=new Ques; q1.friends.push; alert;// alert;// alert(q1.friends===q2.friends); //相信大家已经看到了问题,当我创建了两个实例q1、q2,当我为q1的“朋友”添加了“王五”之后,q2的”朋友“也有了三个张三、李四、王五 //那是因为数组存在于Ques.prototype上,而非q1上。所以出现了如上结果。 //而正是这个问题,我们很少看到有人单独使用原型模式的原因所在。 

理解对象,最简单的方式就是通过创建一个Object的实例,然后为它添加属性和方法

前面的系列文章,基本把JavaScript的核心知识点的基本语法、标准库等章节讲解完;本章开始进入JavaScript核心知识点的高级部分——面向对象的程序设计,这一部分的内容将会对对象这一数据类型做进一步的深化理解,并且讲述几种创建对象的设计模式以及JavaScript独特的继承机制;

实践一:原型中的引用类型的属性是共享的

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

复制代码 代码如下: var person = new Object(); person.name = "Xulei"; person.age = "23"; person.job = "前端工程师"; person.sayName = function ; }

1.理解对象和面向对象的程序设计1.1 面向对象的程序设计

var Person = function(){};Person.prototype = { info:{ "name":"Tom" }}var p1 = new Person();var p2 = new Person();p1.info.name = '我是p1';p2.info.name = '我是p2';console.log; // 我是p2console.log; // 我是p2

复制代码 代码如下: var person = { name: "xulei", age: 23, job: "前端工程", sayName: function } }

"面向对象编程"(Object Oriented Programming,缩写为OOP)本身是一种编程的思维模式,它把世界的一切看作是对象的集合,世界的运转就是靠一个个对象分工、合作的结果,体现一切皆“对象”思想;而在程序设计当中,面向对象编程就可以看做编写各个具有特定功能的对象并将它们进行有机的分工合作,即目前的模块化编程就是面向对象的程序设计的实际应用;

分析:p1,p2都是实例化出来的对象,p1.info 和p2.info 都是指向同一块堆内存,给p1.info.name赋值,和给p2.info.name赋值修改的都是同一个地方,由于代码从上到下依次执行,那么在console的时候自然都是打印出 '我是p2'。总结:由此可以看出原型内的引用类型的属性是共享的。

一、属性类型:数据属性和访问其属性

1.2 理解对象

实践二:原型的引用类型,当实例化后并重新给引用类型属性赋值,地址发生变化。

1、数据属性,有4个描述其行为的特性 [Configurable]:表示能否通过delete删除属性从而重新定义属性,能否修改属性的特性,或者能否把属性修改为访问器属性,默认值为true [Enumerable]:表示能否通过for-in返回属性,默认值为true [Writable]:表示能否修改属性,默认值为true [Value]:包含这个属性的数据值。默认值为undefined

对象在前面的系列文章中曾经提到,从数据特征上看,对象是无序属性的集合;我们可以使用字面量和构造函数的方式去创建一个最为简单的对象:

var Person = function(){};Person.prototype = { info:{ "name":"Tom" }}var p1 = new Person();var p2 = new Person();p1.info = {"name":"哈哈"};;console.log; // 哈哈console.log; // Tom

复制代码 代码如下: var person = { name: "xulei" }

var person = new Object();person.name = "teren";person.age = 18;person.greet = function(){ console.log;}var teren = { name:"teren", age:18, greet:function(){ console.log; }}

分析:上面代码当执行到 p1.info = {"name":"哈哈"}的时候,p1的info这个引用类型的属性,指向了新的地址。而p2.info 没有做出任何修改,还是指向对象原型中的那个地址。

这里创建了一个person对象,value值就是“xulei”

通常创建一个简单的对象,都是采用字面量的方式;上面的对象就是对现实对象的一种抽象表达;

实践三:对象中值类型的属性不共享

要修改属性的默认特性,必须使用ECMAScript5的Object.defineProperty描述符对象必须是configurable、enumerable、writable、value

1.3 对象的属性类型

var Person = function{ this.name = name; this.age = age;};var p1 = new Person;var p2 = new Person;console.log; // Tomconsole.log; // Lucy

复制代码 代码如下: var peron = {} Object.defineProperty(peron, "name", { writable: false,//属性不能被修改 value: "徐磊-xulei" });

前面章节中我们使用delete命令可以删除一些对象的属性,有一些又不可以,使用Object.keys()方法只能遍历可枚举属性,那么对象的属性是否有一些特性是我们尚未了解的呢?ES5提供了一种只有内部才用的特性去描述对象的属性的各种特性,使用[[attribute]]表示,在JavaScript中不能直接访问它们;一个我们非常熟悉的栗子就是Number构造函数构造出来的实例对象;

实践四:属性屏蔽理论

alert;//徐磊-xulei peron.name = "徐磊"; alert;//徐磊-xulei

我们无法直接访问num.[[PrimitiveValue]],这一属性,只能通过num.valueOf()访问该值;

var Person = function () { this.name = '小明', this.buy = function () { console.log; }};Person.prototype = { name:"原型中的小明", buy:function() { console.log; }, age:10}var p = new Person();// 正常情况下我们去访问p里的属性和方法。// 可以看出原型中的属性和方法的优先级没有构造函数中的高,如果构造函数中没有,会去原型中查找console.log;// 控制台输出 去买面包console.log; // 10// 如果我们要访问原型中的属性和方法可以这样delete p.name; // 此处会删除构造函数中的属性console.log;// 原型中的小明Person.prototype.buy(); // 控制台输出 去买汽水

以上操作在非严格模式下赋值操作会被忽略,如果在严格模式下会抛出异常 一旦把属性定义为不可配置的就不能把它变回可配置的了。 在多数情况下都没有必要利用Object.defineProperty()方法提供的这些高级功能。但是对理解javascript非常有用。 建议读者不要在ie8上使用此方法。

ES5中定义对象属性的两种特性,数据特性和访问器特性,对象属性可以兼备这两种特性;

实践五:对象中的 hasOwnProperty 方法

2、访问其属性,有4个特性 [Configurable]:表示能否通过delete删除属性从而重新定义属性,能否修改属性的特性,或者能否把属性修改为访问器属性,默认值为true [Enumerable]:表示能否通过for-in返回属性,默认值为true [Get]:在读取时调用的函数 [Set]:在写入属性时调用的函数

数据特性定义对象的属性值的特性,一个属性值可以包括以下四个数据特性:

var Person = function () { this.name = 'Tom';}Person.prototype = { age:30}var p = new Person();console.log(Person.hasOwnProperty; // trueconsole.log(p.hasOwnProperty; // trueconsole.log(Person.hasOwnProperty; // falseconsole.log(p.hasOwnProperty; // falsevar ClassRoom = { contain:100, leader:'小明', teacher:'王老师'}console.log(ClassRoom.hasOwnProperty; // trueconsole.log( p.hasOwnProperty === Object.prototype.hasOwnProperty ); //trueconsole.log( Person.hasOwnProperty === Object.prototype.hasOwnProperty ); //trueconsole.log( ClassRoom.hasOwnProperty === Object.prototype.hasOwnProperty ); //true
[[Value]]:存放属性值;[[Writable]]:是否可写属性;[[Enumerable]]:是否为可枚举属性;[[Configurable]]:是否可用delete命令删除;

分析:上面说明了一个问题,hasOwnProperty 这个方法是看是不是对象自身下面的属性,可以用对象和实例对象访问,并且只会去找构造函数和字面量中的属性并且 hasOwnProperty 继承自 Object

访问器特性定义对象的属性在访问属性和设置属性时调用的两个函数getter和setter;

实践六:自定义对象中的 constructor 和 __proto__

[[Get]]:访问属性时调用的函数;[[Set]]:设置属性时调用的函数;

/* 每个实例对象都会默认生成一个constructor 和 __proto__ 属性 这一条不管是内置对象还是自定义对象都是一样的 */function A;console.log; // true 默认情况下实例的constructor指向实例的构造函数console.log(a.__proto__ === A.prototype); // true 默认情况下,实例的__proto__属性指向类的prototype/* 当我们修改 constructor 和 __proto__ 属性时候 */function B() {};// 手动修改原型链B.prototype = { __proto__:String.prototype}var b = new B();// instanceof 用来判断obj1是否是obj2的一个实例,可见用 instanceof 来判断数据类型也是不准确的。// 这里涉及到继承,而js面向对象中的继承就是通过原型链来实现的。console.log; // trueconsole.log; // trueconsole.log; // trueconsole.log; // false 此处b的构造函数不是B了,因为原型链指到String上去了。console.log(b.constructor === String); //true// 手动修改b的constructor ,如果自己不设置,那么就会去寻找原型链,如上//b.constructor = B; 或者 B.prototype.constructor = B;// 手动设置后,就会按照设置的来走,如下:b.constructor = B;console.log; // trueconsole.log(b.__proto__=== B.prototype); // trueconsole.log(B.prototype.__proto__=== String.prototype); // true;// 下面这两个也是原型链的内容// B是函数,函数的constructor 是 Function,函数的__proto__ 是Function.prototypeconsole.log(B.constructor === Function); // trueconsole.log(B.__proto__ === Function.prototype); // true

下面以一个实例对象直接讲解这两个特性:

感兴趣的朋友可以使用在线HTML/CSS/JavaScript代码运行工具

//数据特性;var teren = {};Object.defineProperty(teren,{ value:"teren", writable:false, enumerable:true, configurable:true})//访问器特性;//html//jsvar obj = Object.defineProperty({},"name",{set:function{ document.getElementById.innerHTML=name},get:function(){ console.log( document.getElementById },})obj.name = "hello world"obj.name

更多关于JavaScript相关内容感兴趣的读者可查看本站专题:《javascript面向对象入门教程》、《JavaScript错误与调试技巧总结》、《JavaScript数据结构与算法技巧总结》、《JavaScript遍历算法与技巧总结》及《JavaScript数学运算用法总结》

Object.defineProperties可以一次性配置对象的多个属性;

希望本文所述对大家JavaScript程序设计有所帮助。

  1. 创建对象的方式

上一节我们对面向对象的程序设计思想和对象有了初步理解,这一节我们深入探讨一下对象的创建方式及其优缺点;

创建对象的不同方式也可以简单的称作设计模式,不同的设计模式在实际编程应用中起到不同的作用;

2.1 单例模式

单例模式就是产生一个类的唯一实例对象,它能够确保您只有一个对象实例能够实际派上用场;

单例模式下,创建对象方式如下:

本文由澳门威尼斯人平台发布于服务器&运维,转载请注明出处:javascript面向对象程序设计_javascript技巧_脚本之家澳门威尼斯人平台

关键词: