一、知识储备:

1、枚举属性名称的函数:

(1)for...in:可以在循环体中遍历对象中所有可枚举的属性(包括自有属性和继承属性)

(2)Object.keys():返回数组(可枚举的自有属性)

(3)Object.getOwnPropertyNames():所有的自有属性

3、属性的特性:数据属性和存取器属性

(1)数据属性:可写(writable)  可枚举(enumerable)  可配置(configurable)  值(value)

    数据属性只有一个简单的值;

(2)存取器属性: 写入(set)  读取(get)  可枚举(enumerable)  可配置(configurable)

    存取器属性不可写(即没有writable特性)。

    属性有set方法,那这个属性是可写的,有get方法,那这个属性就是可读的。

4、定义属性特性的方法:Object.defineProperty(对象,属性,描述符对象)

5、获取属性的描述符对象:Object.getOwnPropertyDescriptor(对象,属性)

二、示例

1、根据for...in的用法,我们可以写出模拟“继承”的方法:

  1. <script type="text/javascript">
  2. var child={};
  3. var mother={
  4. name:"zhangzhiying",
  5. lastAge:21,
  6. sex:"女"
  7. };
  8. function extend(target,source){
  9.     for(var p in source){
  10.   target[p]=source[p];
  11.     }
  12.     return target;
  13. }
  14. extend(child,mother);
  15. console.log(child); //Object {name: "zhangzhiying", lastAge: 21, sex: "女"}
  16. </script>

2、使用for in来循环遍历原型对象的属性,然后一一赋值给我们的空对象,从而实现了“继承”。这个思路很正确,下面我们来对以上示例进行改造:

  1. <script type="text/javascript">
  2. var child={};
  3. var mother={
  4. name:"zhangzhiying",
  5. lastAge:21,
  6. set age(value){
  7. this.lastAge=value;
  8. },
  9. get age(){
  10. return this.lastAge+1;
  11. },
  12. sex:"女"
  13. };
         mother.age=15; //有set方法,具有可写性
  14. function extend(target,source){
  15.     for(var p in source){
  16.   target[p]=source[p];
  17.     }
  18.     return target;
  19. }
  20. extend(child,mother);
  21. console.log(child); //Object {name: "zhangzhiying", lastAge: 15, age: 16, sex: "女"}
  22. </script>

可以看到代码中使用了一对set,get;其中age是一个存取器属性。

运行的结果:一个不包含set,get的普通对象。 

结论:for  in实现的“继承”不处理set和get ,它把存取器属性(age)转换为一个静态的数据属性。

3、给mother对象设置数据属性

  1. <script type="text/javascript">
  2. var child={};
  3. var mother={
  4. name:"zhangzhiying",
  5. lastAge:21,
  6. set age(value){
  7. this.lastAge=value;
  8. },
  9. get age(){
  10. return this.lastAge+1;
  11. },
  12. sex:"女"
  13. };
  14. Object.defineProperty(mother,"lastAge",{writable:false}); //把lastAge设置成了不可写
  15. mother.age=15; //设置无效,因为lastAge的值不变,所以lastAge+1不变,即age不变
  16. function extend(target,source){
  17. for(var p in source){
  18. target[p]=source[p];
  19. }
  20. return target;
  21. }
  22. extend(child,mother);
  23. console.log(child); //Object {name: "zhangzhiying", lastAge: 21, age: 22, sex: "女"}
  24. child.lastAge=12;    //结果显示lastAge改变,说明child.lastAge没有“继承”到mother.lastAge的特性,我们再用getOwnPropertyDesriptor()方法确认一下
         console.log(Object.getOwnPropertyDescriptor(child,"lastAge")); //Object {value: 12, writable: true, enumerable: true, configurable: true}
    console.log(child); //Object {name: "zhangzhiying", lastAge: 12, age: 22, sex: "女"}
  1. </script>

结论:要实现继承,我们还需要解决的问题->“继承”属性特性。

4、完善版本  

  1. <script type="text/javascript">
  2. var child={};
  3. var mother={
  4. name:"zhangzhiying",
  5. lastAge:21,
  6. set age(value){
  7. this.lastAge=value;
  8. },
  9. get age(){
  10. return this.lastAge+1;
  11. },
  12. sex:"女"
  13. };
  14. Object.defineProperty(mother,"lastAge",{writable:false});
  15. mother.age=15;
  16. function extend(target,source){
  17. var names=Object.getOwnPropertyNames(source); //获取所有的属性名
  18. for(var i=0;i<names.length;i++){
  19. if(names[i] in target) continue; //如果这个属性存在,就跳过(原型继承中,如果自有属性和原型对象的属性重名,保留自有属性)
  20. var desc=Object.getOwnPropertyDescriptor(source,names[i]); //获取mother属性的描述符对象(即属性特性的集合,es5中用描述符对象来表示)
  21. Object.defineProperty(target,names[i],desc); //将mother的描述符对象给child的属性定义
  22. }
  23. return target;
  24. }
  25. extend(child,mother);
  26. console.log(child);
  27. child.lastAge=12;
  28. console.log(Object.getOwnPropertyDescriptor(child,"lastAge"));
  29. console.log(child);
  30. </script>

最后的结果:

可以明显看到三次的打印,child“继承”到了set和get,lastAge数值没发生变化,writable也是false了。 

总结:最近在看《javascript权威指南》,总结一点心得,有错误欢迎指正,共同学习进步~

javascript 用函数实现“继承”的更多相关文章

  1. JavaScript中函数的继承

    大多OOP语言都支持两种继承方式: 接口继承和实现继承 ,而ECMAScript中无法实现接口继承,ECMAScript只支持实现继承,而且其实现继承主要是依靠 原型链 来实现. 1.原型链 基本思想 ...

  2. javascript的函数、创建对象、封装、属性和方法、继承

    转自原文javascript的函数.创建对象.封装.属性和方法.继承 一,function 从一开始接触到js就感觉好灵活,每个人的写法都不一样,比如一个function就有N种写法 如:functi ...

  3. 玩转JavaScript OOP[4]——实现继承的12种套路

    概述 在之前的文章中,我们借助构造函数实现了"类",然后结合原型对象实现了"继承",并了解了JavaScript中原型链的概念. 理解这些内容,有助于我们更深入 ...

  4. JavaScript对寄生组合式继承的理解

    有关JavaScript的几种继承方式请移步JavaScript的几种继承方式 原型链的缺陷 SubType.prototype = new SuperType(); 这样做的话,SuperType构 ...

  5. web前端学习(二) javascript对象和原型继承

    目录 1. JavaScrpt对象 2. 原型对象和继承 3. 对象的克隆 (1)javascript对象 在JS中,对象是属性的容器.对于单个对象来说,都由属性名和属性值构成:其中属性名需要是标识符 ...

  6. 【面试必备】javascript的原型和继承

    原型.闭包.作用域等知识可以说是js中面试必考的东西,通过你理解的深度也就能衡量出你基本功是否扎实.今天来复习一下javascript的原型和继承,虽说是老生常谈的话题,但对于这些知识,自己亲手写一遍 ...

  7. Javascript的实例化与继承:请停止使用new关键字

    本文同时也发表在我另一篇独立博客 <Javascript的实例化与继承:请停止使用new关键字>(管理员请注意!这两个都是我自己的原创博客!不要踢出首页!不是转载!已经误会三次了!) 标题 ...

  8. 小白科普之JavaScript的函数

    一 概述 1.1 函数声明 (1)function命令 函数就是使用function命令命名的代码区块,便于反复调用.这种声明方式叫做函数的声明(Function Declaration). func ...

  9. Javascript之对象的继承

    继承是面向对象语言一个非常重要的部分.许多OOP语言都支持接口继承和实现继承两种方式.接口继承:继承方法签名:实现继承:继承实际的方法.在ECMAScript中函数是没有签名的,所以也就无法实现接口继 ...

随机推荐

  1. 去掉有序数组中重复数字 原地 leetcode java (最简单的方法)

    1.利用荷兰国旗的思路,每次记住最后一个位置,遇到一个不重复的数,放在它后面,代码很简单. Given a sorted array, remove the duplicates in place s ...

  2. Tornado自定义分布式session框架

    一.session框架处理请求执行的流程: 1.服务器端生成随机的cookie字符串 2.浏览器发送请求,服务器将cookie返回给浏览器. 3.服务器在生成一个字典.字典的key为cookie,va ...

  3. hdoj 2502 月之数

    月之数 Time Limit: 1000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submiss ...

  4. FairScheduler的任务调度机制——assignTasks(续)

    上一篇文章浅析了FairScheduler的assignTasks()方法,介绍了FairScheduler任务调度的原理.略过了最后一步通过JobScheduler获取Task时调用JobInPro ...

  5. Session案例

    用户登入案例: 按一般的网站登入实例,用户在页面登入页输入账号.密码,验证通过后,在首页显示其"欢迎回来,xxx". 首先完成登入页login.html <!DOCTYPE ...

  6. 理解标签重置reset

    /*样式表文件来自 懒人css http://lrcss.lrjz100.com *//*---------重置---------*/html{font-size: 100%;-webkit-text ...

  7. JavaScript效果之选项卡

    拼了命学习js,想把学到的Javascript效果,可以记在博客里,在记录过程中,加深理解. gogogo,第一个效果,选项卡. 一.选项卡效果的实现思路 选项卡效果的应用很广泛,几乎所有的网站都会用 ...

  8. C++中this指针的使用方法.

    this指针仅仅能在一个类的成员函数中调用,它表示当前对象的地址.以下是一个样例: void Date::setMonth( int mn ) { month = mn; // 这三句是等价的 thi ...

  9. 在Eclipse上搭建Cocos2d-x的Android开发环境

    很多其它相关内容请查看本人博客:http://www.bokeyi.com/ll/category/cocos2d-x/ 本文的搭建方法是最新最正确的方法,好多朋友反映搭建eclipse交叉编译环境非 ...

  10. linux内核分析系列--百度

    http://www.baidu.com/p/frsllzh http://www.baidu.com/p/%E9%98%BF%E4%BF%A1sxq