函数对象和普通对象

  1. //普通对象
  2. var oo1 = {}, oo2 = new Object(), oo3 = [];
  3. console.log(typeof oo1 + ',' + typeof oo2 + ',' + typeof oo3); //object,object,object
  4. //函数对象
  5. function ff1() {}
  6. var ff2 = function () {}
  7. var ff3 = new Function();
  8. console.log(typeof ff1 + ',' + typeof ff2 + ',' + typeof ff3); //function,function,function
  9. console.log(typeof Object + ',' + typeof Function + ',' + typeof Array + ',' + typeof Date); //function,function,function,function

如上typeof返回值为object的认为普通对象,typeof返回值为function的认为函数对象,其主要差别如下:

  1. 每一个函数对象都有一个显示的prototype属性,它代表了对象的原型(Function.prototype函数对象是个例外,没有prototype属性)。每个对象都有一个名为proto的内部隐藏属性,指向于它所对应的原型对象(chrome、firefox中名称为proto,并且可以被访问到)。原型链正是基于proto才得以形成(函数对象也有proto属性)。
  2. 函数对象可以作为对象构造器,通过new操作符来返回一个对象。

即函数对象是特殊的对象,它拥有prototype属性,可作为对象构造器。JS提供的对象如Function、Object等都是函数对象。(注意Function是特殊的函数对象,new Fucntion()返回的是一个函数对象,而其它函数对象如Object等通过new操作符——new Object()返回的是一个普通对象)。

prototype、proto和constructor

prototype是函数对象的一个属性(每个函数都有一个prototype属性),这个属性是一个指针,指向一个对象。它是显示修改对象的原型的属性。
proto是一个对象拥有的内置属性(请注意:prototype是函数的内置属性,proto是对象的内置属性),是JS内部使用寻找原型链的属性。
每个函数对象都有名为“prototype”的属性(上面提到过Function.prototype函数对象是个例外,没有prototype属性),用于引用原型对象。此原型对象又有名为“constructor”的属性,它反过来引用函数本身。这是一种循环引用(F4.prototype.constructor===F4)。

  1. var F4 = function () {
  2. this.a = 'a';
  3. return this.a;
  4. }
  5. var o4 = new F4();
  6. console.log(o4.a); //'a'
  7. console.log(F4.prototype === o4.__proto__); //true
  8. console.log(F4.prototype === F4.__proto__); //false
  9. console.log(F4.prototype === Function.prototype); //false
  10. console.log(F4.__proto__ === Function.prototype); //true
  11. console.log(o4.constructor === F4); //true
  12. console.log(o4.constructor === F4.prototype); //false
  13. console.log(o4.constructor === F4.prototype.constructor); //true
  14. console.log(F4.constructor === Function); //true
  15. console.log(F4.constructor === Function.prototype.constructor); //true
  16. console.log(Function === Function.prototype.constructor); //true
  17. console.log(F4 === F4.prototype.constructor); //true
  18. console.log(Object.constructor === Function); //true
  19. console.log(Function.prototype === Function.__proto__); //true
  20. console.log(typeof Object + ',' + typeof Object.prototype + ',' + Object.prototype.__proto__ + ',' + Object.prototype.prototype); //function,object,null,undefined
  21. console.log(typeof Function + ',' + typeof Function.prototype + ',' + Function.prototype.__proto__ + ',' + Function.prototype.prototype); //function,function,[Object],undefined
  22. console.log(typeof F4 + ',' + typeof F4.prototype + ',' + F4.prototype.__proto__ + ',' + F4.prototype.prototype); //function,function,[Object],undefined
  23. console.log(typeof o4 + ',' + typeof o4.__proto__ + ',' + o4.__proto__.__proto__ + ',' + o4.__proto__.prototype); //object,object,[Object],undefined


上图中o为普通对象,F为普通函数对象,椭圆表示函数对象,矩形表示函数对象,从中可以看出:

  1. 所有对象,包括函数对象的原型链最终都指向了Object.prototype,而Object.prototype.proto===null,原型链至此结束。
  2. Function.prototype是一个函数对象,但是Function.prototype却没有prototype属性,即Function.prototype.prototype===undefined,所以Function.prototype函数对象是一个特例,没有prototype属性。除Function.prototype外,其它函数对象如Object.prototype
  3. Object.constructor===Function;说明Object是Function函数构造出来的。

    函数对象的特殊属性

    arguments

    arguments其主要用途是用来保存函数参数。

    1. arguments.length//值来判断实参的个数
    2. arguments[0]//表示传递的第一个元素
    3. arguments[1]//表示传递的第二个元素

    arguments(不是Array的实例)对象还有一个属性:callee,指向拥有arguments对象的函数,在编写递归函数时常用。

    1. function factorial(num){
    2. if(num<=1){
    3. return 1;
    4. }
    5. else{
    6. //return num*factorial(num-1);
    7. //一个实例化的函数对象可以拥有很多个名字,不应限定函数名必须是factorial
    8. return num*arguments.callee(num-1);
    9. }
    10. }

    length

    length表示每个函数准备接收的命名参数的个数,即形参的个数,区别于内部对象arguments是实参的个数。

    1. function sum(num1,num2,num3)
    2. {
    3. alert(arguments.callee.length);//方法2:内部对象调用
    4. }
    5. sum(1,2)
    6. alert(sum.length);//方法1:函数调用

    this对象

    this指向调用当前函数的对象,当在网页全局作用域中调用时,this对象引用的就是window。

    1. function hello(){
    2. console.log('hello '+this.val);
    3. }
    4. var a={"val":"a","hello":hello},b={"val":"b","hello":hello};
    5. hello();//hello undefined
    6. a.hello();//hello a
    7. b.hello();//hello b

    call,apply, bind

    apply方法有两个参数,1个是在其中运行函数的作用域(即要调用函数的对象),另一个是参数数组。
    call方法与apply方法的作用一样,但是接收参数的方式不同,其参数必须逐个例出来。
    bind方法新创建一个函数对象,这个函数对象的this值绑定参数传入的对象。
    call 和 apply差别:参数的样子不一样,另一个就是性能不一样。(apply的性能要差很多,可到 JSPerf 上去跑跑看看)
    注意,在bind后,call、apply方法也不能改变this指针,如下面的示例

    1. hello.call(a,'pa');//hello a pa
    2. hello.apply(a,['pa']);//hello a pa
    3. hello.call(b,'pb');//hello b pb
    4. hello.apply(b,['pb']);//hello b pb
    5. var h = hello.bind(a);
    6. hello();//hello undefined undefined
    7. h();//hello a undefined
    8. h.call(b,'pb');//hello a pb
    9. h.apply(b,['pb']);//hello a pb

    new关键字

    1. var Base=function(){}
    2. var obj=new Base();
    3. //上面中new操作符干了三件事情
    4. //1.初始化一个空对象obj
    5. var obj = {};
    6. //2.将这个空对象的__proto__成员指向了Base函数对象prototype成员对象
    7. obj.__proto__ = Base.prototype;
    8. //3.将Base函数对象的this指针替换成obj,然后再调用Base函数,初始化obj
    9. Base.call(obj);

    但要注意但函数本身返回值为对象时new操作符不起作用。

    如果函数返回值为常规意义上的值类型(Number、String、Boolean)时,new函数将会返回一个该函数的实例对象,而如果函数返回一个引用类型(Object、Array、Function),则new函数与直接调用函数产生的结果等同。

  1. var F3 = function () {
  2. this.a = 'a';
  3. var o = {
  4. 'name' : 'name'
  5. };
  6. return o;
  7. }
  8. var o3 = new F3();
  9. console.log(o3.a); //undefined
  10. console.log(o3.__proto__ === F3.prototype); //false
  11. console.log(F3.prototype == F3.__proto__); //false
  12. console.log(F3.__proto__ == Function.prototype); //true
  13. console.log(o3.constructor === F3); //false;
  14. var F4 = function () {
  15. this.a = 'a';
  16. return this.a;
  17. }
  18. var o4 = new F4();
  19. console.log(o4.a); //'a'
  20. console.log(F4.prototype === o4.__proto__); //true
  21. console.log(F4.prototype === F4.__proto__); //false
  22. console.log(F4.prototype === Function.prototype); //false
  23. console.log(F4.__proto__ === Function.prototype); //true
  24. console.log(o4.constructor === F4); //true
  25. console.log(o4.constructor === F4.prototype); //false
  26. console.log(o4.constructor === F4.prototype.constructor); //true

JS面向对象编程时类函数定义方式

  1. var F2 = function () {
  2. var inner='inner';
  3. this.o1 = 'o1';
  4. this.f1 = function () {
  5. console.log('f1 ' + this.o1+' '+ inner);
  6. }
  7. function f2() {
  8. console.log('f2 ' + this.o1+' '+ inner);
  9. }
  10. }
  11. F2.prototype.f3 = function () {
  12. //console.log('f3' + this.o1+' '+ inner);失败,找不到inner
  13. console.log('f3' + this.o1);
  14. }
  15. var o2 = new F2();
  16. o2.f1();
  17. //o2.f2();失败,找不到f2
  18. o2.f3();

js面向对象编程时类定义函数用prototype方式和this方式区别:this方式定义的函数如f1可以访问构造函数内部的变量如上例inner,prototype方式定义的函数f3则不能访问内部变量; 但如果所有函数都采用this方式定义则每次实例化都要执行,浪费内存,也不合理。
this方式定义方法叫做特权方法,主要是为了访问内部的私有字段,这样就可以控制对某些字段的访问。prototype方式定义的函数能访问这些特权方法,进而间接访问私有字段。

因此,如果要直接访问私有字段,应该使用特权方法,也就是this定义的方法,应该定义在构造函数内部。相反,如果不需要直接访问私有字段,应该使用prototype定义的方法,定义在构造函数外部。

参考:
Js中Prototype、proto、Constructor、Object、Function关系介绍
Js New一个函数和直接调用的区别

JS原型函数相关基础知识的更多相关文章

  1. three.js学习笔记--基础知识

    基础知识 从去年开始就在计划中的three.js终于开始了 历史介绍 (摘自ijunfan1994的转载,感谢作者) OpenGL大概许多人都有所耳闻,它是最常用的跨平台图形库. WebGL是基于Op ...

  2. js基础例子dom+原型+oop基础知识记录01

    //oo:概念是计算机中对于现实世界的理解和抽象的方法 //由计算机利用编程技术发展到现在的产物 //面向对象几要素 //对象:由属性和方法组成的集合 //属性:保存数据,存储在对象内存空间中的唯一的 ...

  3. JS 数组的基础知识

    数组 一.定义 1.数组的文字定义 广义上说,数组是相同类型数据的集合.但是对于强类型语言和弱类型语言来说其特点是不一样的.强类型语言数组和集合有以下特点. 数组强类型语言:1.数组里面只能存放相同数 ...

  4. 云笔记项目-补充JS面向对象编程基础知识

    简单介绍: 此部分知识为在做云笔记项目中补充,因为云笔记项目中涉及到前端js,里面写了很多js脚本,用到了创建js属性和方法,在js中直接声明的属性和方法最终都会变成window的对象,即其成为了全局 ...

  5. js与juery基础知识对比(一)---2017-05-06

    用表格做的,想要对比的内容一目了然,红色部分为重点   js jquery 取元素 id: document.getElementById("aa"); 取到的是dom对象 cla ...

  6. js与jquery基础知识对比(一)---2017-05-06

    用表格做的,想要对比的内容一目了然,红色部分为重点   js jquery 取元素 id: document.getElementById("aa"); 取到的是dom对象 cla ...

  7. HTML+CSS+JS基础知识

    HTML+CSS+JS基础知识 目录 对HTML+CSS+JS的理解 基础知识 对HTML+CSS+JS的理解 基础知识 插入样式表的三种方式 外部样式表:<link rel="sty ...

  8. JavaScript基础知识从浅入深理解(一)

    JavaScript的简介 javascript是一门动态弱类型的解释型编程语言,增强页面动态效果,实现页面与用户之间的实时动态的交互. javascript是由三部分组成:ECMAScript.DO ...

  9. Js基础知识(二) - 原型链与继承精彩的讲解

    作用域.原型链.继承与闭包详解 注意:本章讲的是在es6之前的原型链与继承.es6引入了类的概念,只是在写法上有所不同,原理是一样的. 几个面试常问的几个问题,你是否知道 instanceof的原理 ...

随机推荐

  1. HTML5本地化应用开发-HTML5 Web存储详解

    文章不是简单的的Ctrl C与V,而是一个字一个标点符号慢慢写出来的.我认为这才是是对读者的负责,本教程由技术爱好者成笑笑(博客:http://www.chengxiaoxiao.com/)写作完成. ...

  2. 【锋利的jQuery】学习笔记01

    第一章 认识jQuery 一.常见的JS库 Prototype 最早的js库之一.把好用JS方法组合,缺点结构松散. Dojo 离线存储API.生成图标组件.矢量图形库.Comet支持.企业级JS库, ...

  3. JS 判断 Radio 单选按钮是否为选中状态 并弹出 值信息

    今天项目中所解决的问题:JS 判断 Radio 单选按钮是否为选中状态 并弹出 值信息,一开始总是获取不到 radio 的值,后来发现逻辑存在些问题,特此共享该代码留笔记 和 分享给遇到 这类问题的 ...

  4. TransactionScope简单用法

    记录TransactionScope简单用法,示例如下: void Test() { using (TransactionScope scope = new TransactionScope()) { ...

  5. 【基础】Oracle 表空间和数据文件

    多个表空间的优势:1.能够将数据字典与用户数据分离出来,避免由于字典对象和用户对象保存在同一个数据文件中而产生的I/O冲突2.能够将回退数据与用户数据分离出来,避免由于硬盘损坏而导致永久性的数据丢失3 ...

  6. ca-bundle.crt to java truststore(e.g. trustStore.jks)

    1. download java keyutilhttps://java-keyutil.googlecode.com/files/keyutil-0.4.0.jar 2. run the follo ...

  7. [Introduction to programming in Java 笔记] 1.3.8 Gambler's ruin simulation 赌徒破产模拟

    赌徒赢得机会有多大? public class Gambler { public static void main(String[] args) { // Run T experiments that ...

  8. Command 模式

    Command 模式通过将请求封装到一个对象(Command)中,并将请求的接受者存放具体的 ConcreteCommand 类中(Receiver)中,从而实现调用操作的对象和操作的具体实现 者之间 ...

  9. 3D Game Programming with directx 11 习题答案 8.2

    第八章 第二题 1.首先找到Directx Texture Tool,它位于 2.填入配置 3.用画图工具画好每个level的图片,例如level0 4.用Directx Texture Tool添加 ...

  10. android入门到熟练(一)

    1.andro系统架构:Linux内核层(提供驱动),系统运行库层和android运行时库(提供C/C++库的主要特性,如SQLite,OpenGL,Webkit等和Dalvik虚拟机),应用框架层, ...