web前端开发中关于面向对象(三)
2017-10-25 19:35
369 查看
在面向对象前篇中提到过原型的概念,说到原型,便又延伸出了关于原型的一个知识点——原型链。也许作为一名专业的前端开发人员来说,明白原型链的含义以及用法,但对于前端的爱好者和在校大学生而言,对于原型链的概念可能是第一次听说,所以,今天就和大家学习一下原型链。
一、含义
实例对象和原型对象组成的一条链式结构,链式结构之间通过proto链接起来,这条链就成为原型链。
例:
通过几次的实验和验证可以发现,原型链的末端都是Object.prototype,所有的对象都直接或间接的继承Object。
二、精确判断数据类型的方法
判断数据类型不仅仅有typeof一种方式,且typeof方法只能判断一般的数据类型,得到的结果较为模糊,不够精准。若想要精确的判断数据类型,需用到Object.prototype上的toString方法。使用Object.prototype.toString方法判断数据类型需要改变this的指向,因而需要配合call一起使用。typeof与Object.prototype.toString的区别:
三、函数和Function的关系
函数,在上篇已经提到过,在不同的情况下所担任的角色就各不相同,可作为构造函数、普通函数等。而普通函数在使用字面量声明时就是构造函数,
四、关于defineProperty
Object中具有一个方法:defineProperty,该方法是定义特性。该方法具有三个参数。
(1)第一个参数:目标对象
(2)第二个参数:需要定义属性和方法的名字
(3)第三个参数:目标属性所拥有的特性,必须是对象
例:
以上例子的意思是:为对象a定义了一个属性,该属性为b,且为b赋值为1。defineProperty中第三个参数,对象中各个属性的含义:
(1)value:属性的值
(2)writable:属性值是否可以被重写,默认为false,若为true,则可以被重写
(3)configurable:总开关,默认为false。总开关一旦为false,value、writeable、configurable就不可被重设
(4)enumerable:是否可以在for/in中循环遍历,默认为false
defineProperty方法的第三个参数对象中还有两个属性,get和set,若使用get和set者两个属性,则就不需要再同时使用以上四个属性。
(1)get:获取值
(2)set:赋值
例:
我们可以通过defineProperty中的set和get者两个属性来实现数据的双向绑定。
例:
五、实例判断
如何判断对象是否是构造函数的实例?instanceof:判断对象是否是构造函数的实例。如果构造函数的原型在原型链上,那么原型链开始的那个实例是所有原型所属的构造函数的实例。
例:
六、属性判断
(1)hasOwnProperty():判断对象中是否有某个属性,该方法只能判断实例对象上的属性,不能判断原型对象上的属性。
(2)in:既可以判断实例对象上的属性,又可以判断原型对象上的属性
例:
七、原型继承
在其他语言中,面向对象中也存在继承和封装。在前端开发中面向对象也存在着继承,前端将继承分为几种,今天先看一看原型继承。其实,在以上提到的知识中已经涉及到也使用到了原型继承。
例:
以上代码块执行的结果只会输出12。老虎是动物的一种,按照常理而言,老虎应该具有动物的特性,那么执行以上代码块,老虎应该具有姓名和年龄两个属性才是合理的,而如今只输出了年龄,那么怎样才可以在不再Tiger构造函数中添加属性而获得Animal构造函数中的name属性?这里便涉及到–继承的知识点。若想要继承Animal,则代码块为:
如此,老虎便可继承Animal中的属性和方法,且它自身的方法和属性也不会被共享。这便是原型继承。但原型继承存在几个问题:
(1)无法在不影响所有实例的情况下,给要继承的构造函数传参
(2)继承的构造函数中的引用类型对于所有的实例是共享的
那么,又该如何解决原型继承存在的这些问题呢?请阅读下一篇。
一、含义
实例对象和原型对象组成的一条链式结构,链式结构之间通过proto链接起来,这条链就成为原型链。
例:
function Person(name){ this.name=name; } Person.prototype.showName=function(){ console.log(this.name); } var p=new Person("Sue"); //以上函数的原型链 p-->Person.prototype-->Object.prototype-->null //其中,-->表示__proto__,该原型链的含义为:p.__proto__指向其构造函数的原型Person.prototype,而构造函数的原型默认是Object的实例,因而指向Object.prototype,之后便结束为空,至于原理,请参照上篇web前端开发中关于面向对象(二)进行理解。
通过几次的实验和验证可以发现,原型链的末端都是Object.prototype,所有的对象都直接或间接的继承Object。
二、精确判断数据类型的方法
判断数据类型不仅仅有typeof一种方式,且typeof方法只能判断一般的数据类型,得到的结果较为模糊,不够精准。若想要精确的判断数据类型,需用到Object.prototype上的toString方法。使用Object.prototype.toString方法判断数据类型需要改变this的指向,因而需要配合call一起使用。typeof与Object.prototype.toString的区别:
var arr= []; var fn = function(){}; var str = "str"; var obj = {}; var date = new Date(); var regExp = new RegExp(); console.log("toString判断结果:"+Object.prototype.toString.call(arr)); console.log("typeof判断结果:"+typeof arr); console.log('------------------') console.log("toString判断结果:"+Object.prototype.toString.call(fn)); console.log("typeof判断结果:"+typeof fn); console.log('------------------') console.log("toString判断结果:"+Object.prototype.toString.call(str)); console.log("typeof判断结果:"+typeof str); console.log('------------------') console.log("toString判断结果:"+Object.prototype.toString.call(obj)); console.log("typeof判断结果:"+typeof obj); console.log('------------------') console.log("toString判断结果:"+Object.prototype.toString.call(date)); console.log("typeof判断结果:"+typeof date); console.log('------------------') console.log("toString判断结果:"+Object.prototype.toString.call(regExp)); console.log("typeof判断结果:"+typeof regExp); /*结果: toString判断结果:[object Array] typeof判断结果:object ------------------ toString判断结果:[object Function] typeof判断结果:function ------------------ toString判断结果:[object String] typeof判断结果:string ------------------ toString判断结果:[object Object] typeof判断结果:object ------------------ toString判断结果:[object Date] typeof判断结果:object ------------------ toString判断结果:[object RegExp] typeof判断结果:object */
三、函数和Function的关系
函数,在上篇已经提到过,在不同的情况下所担任的角色就各不相同,可作为构造函数、普通函数等。而普通函数在使用字面量声明时就是构造函数,
var fn=new Function(){}有时候也可是构造函数。那么,函数和Function两者之间又有何关联?仅仅使用文字是解释不太明白的,还是让代码来告诉大家。
function foo(){...} console.log(foo.__prototype==Function.prototype);//true console.log(Object.__proto__==Function.prototype);//true console.log(Function.__proto__==Function.prototype);//true /*原型链: foo-->Function.prototype-->Object.prototype-->null object-->Function.prototype-->Object.prototype-->null Function-->Function.prototype */
四、关于defineProperty
Object中具有一个方法:defineProperty,该方法是定义特性。该方法具有三个参数。
(1)第一个参数:目标对象
(2)第二个参数:需要定义属性和方法的名字
(3)第三个参数:目标属性所拥有的特性,必须是对象
例:
var a={}; Object.defineProperty(a,"b",{ value:1, writable:true, configurable:true, enumerable:true });
以上例子的意思是:为对象a定义了一个属性,该属性为b,且为b赋值为1。defineProperty中第三个参数,对象中各个属性的含义:
(1)value:属性的值
(2)writable:属性值是否可以被重写,默认为false,若为true,则可以被重写
(3)configurable:总开关,默认为false。总开关一旦为false,value、writeable、configurable就不可被重设
(4)enumerable:是否可以在for/in中循环遍历,默认为false
defineProperty方法的第三个参数对象中还有两个属性,get和set,若使用get和set者两个属性,则就不需要再同时使用以上四个属性。
(1)get:获取值
(2)set:赋值
例:
Object.defineProperty(a,"b",{ set:function(val){}, get:function(){} });
我们可以通过defineProperty中的set和get者两个属性来实现数据的双向绑定。
例:
<input type="text" v-model="val"/> <p v-model="val"></p> <script> var inp=document.getElementsByTagName("input")[0]; var p=document.getElementsByTagName("p")[0]; var obj={}; Object.defineProperty(obj,"val",{ get:function() return inp.value; }, set:function(val){ p.innerHtml=val; inp.value=val; } }); inp.oninput=function(){ obj.val=inp.value; } </script>
五、实例判断
如何判断对象是否是构造函数的实例?instanceof:判断对象是否是构造函数的实例。如果构造函数的原型在原型链上,那么原型链开始的那个实例是所有原型所属的构造函数的实例。
例:
function Person(name){ this.name=name; } Person.prototype.showName=function(){ console.log(this.name); } function Student(num){ this.num=num; } Student.prototy=new Person("Sue"); var stu=new Student(90); console.log(stu instanceof Student);//true console.log(stu instanceof Person);//true console.log(stu instanceof Object);//true console.log(stu instanceof Function);//false //原型链: //stu-->Student.prototype-->Person.prototype-->Object.prototype-->null
六、属性判断
(1)hasOwnProperty():判断对象中是否有某个属性,该方法只能判断实例对象上的属性,不能判断原型对象上的属性。
(2)in:既可以判断实例对象上的属性,又可以判断原型对象上的属性
例:
var obj=new Object(); obj.info="Sue"; obj.name="Mike"; Object.prototype.age="20"; console.log(obj.hasOwnProperty("info"));//true console.log("info" in obj);//true console.log(obj.hasOwnProperty("name"));//true console.log("name in obj);//true console.log(obj.hasOwnProperty("age"));//false console.log("age" in obj);//true
判断某个属性是否在原型上的方法:
if("info" in obj &&!obj.hasOwnProperty("info")){...}
七、原型继承
在其他语言中,面向对象中也存在继承和封装。在前端开发中面向对象也存在着继承,前端将继承分为几种,今天先看一看原型继承。其实,在以上提到的知识中已经涉及到也使用到了原型继承。
例:
function Animal(name){ this.name=name; } Animal.prototype.showName={ console.log(this.name); } function Tiger(age){ this.age=age; } var tiger=new Tiger("12");
以上代码块执行的结果只会输出12。老虎是动物的一种,按照常理而言,老虎应该具有动物的特性,那么执行以上代码块,老虎应该具有姓名和年龄两个属性才是合理的,而如今只输出了年龄,那么怎样才可以在不再Tiger构造函数中添加属性而获得Animal构造函数中的name属性?这里便涉及到–继承的知识点。若想要继承Animal,则代码块为:
function Animal(name){ this.name=name; } Animal.prototype.showName={ console.log(this.name); } function Tiger(age){ this.age=age; } Tiger.prototype=new Animal("caser"); var tiger=new Tiger("12");
如此,老虎便可继承Animal中的属性和方法,且它自身的方法和属性也不会被共享。这便是原型继承。但原型继承存在几个问题:
(1)无法在不影响所有实例的情况下,给要继承的构造函数传参
(2)继承的构造函数中的引用类型对于所有的实例是共享的
那么,又该如何解决原型继承存在的这些问题呢?请阅读下一篇。
相关文章推荐
- web前端开发中关于面向对象(一)
- 收藏的一些关于web前端开发的资源(很强大,种类很多)
- web前端-关于javascript开发的重要知识点
- J2EE 关于Web前端与服务端实现开发分离的实践 .
- 关于web前端开发的一些认识
- [WEB前端开发]-关于Velocity中Map与List操作-解决velocity无法识别Map对象key的问题
- 关于WEB前端开发的工具
- 关于Web前端开发,附:(百度web前端笔试面试题目)
- J2EE 关于Web前端与服务端实现开发分离的实践
- Web前端从入门到精通-2 关于html和开发工具
- 关于web前端开发的资源
- 常见Web前端开发笔试题
- 推荐几个Web前端开发实用的Chrome插件
- 淘宝前端工程师:国内WEB前端开发十日谈
- Web前端开发基础知识--部分总结
- web前端开发之div+css教程精华收集二
- web前端开发的学习内容:致那些有意学习web前端开发的人
- 腾讯WEB前端开发面试经历,一面二面HR面,面面不到!
- 【Web前端开发】之Bootstrap基础(一)
- Web前端开发最佳实践(1):前端开发概述