JS原型函数相关基础知识
函数对象和普通对象
//普通对象var oo1 = {}, oo2 = new Object(), oo3 = [];console.log(typeof oo1 + ',' + typeof oo2 + ',' + typeof oo3); //object,object,object//函数对象function ff1() {}var ff2 = function () {}var ff3 = new Function();console.log(typeof ff1 + ',' + typeof ff2 + ',' + typeof ff3); //function,function,functionconsole.log(typeof Object + ',' + typeof Function + ',' + typeof Array + ',' + typeof Date); //function,function,function,function
如上typeof返回值为object的认为普通对象,typeof返回值为function的认为函数对象,其主要差别如下:
- 每一个函数对象都有一个显示的prototype属性,它代表了对象的原型(Function.prototype函数对象是个例外,没有prototype属性)。每个对象都有一个名为proto的内部隐藏属性,指向于它所对应的原型对象(chrome、firefox中名称为proto,并且可以被访问到)。原型链正是基于proto才得以形成(函数对象也有proto属性)。
- 函数对象可以作为对象构造器,通过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)。
var F4 = function () {this.a = 'a';return this.a;}var o4 = new F4();console.log(o4.a); //'a'console.log(F4.prototype === o4.__proto__); //trueconsole.log(F4.prototype === F4.__proto__); //falseconsole.log(F4.prototype === Function.prototype); //falseconsole.log(F4.__proto__ === Function.prototype); //trueconsole.log(o4.constructor === F4); //trueconsole.log(o4.constructor === F4.prototype); //falseconsole.log(o4.constructor === F4.prototype.constructor); //trueconsole.log(F4.constructor === Function); //trueconsole.log(F4.constructor === Function.prototype.constructor); //trueconsole.log(Function === Function.prototype.constructor); //trueconsole.log(F4 === F4.prototype.constructor); //trueconsole.log(Object.constructor === Function); //trueconsole.log(Function.prototype === Function.__proto__); //trueconsole.log(typeof Object + ',' + typeof Object.prototype + ',' + Object.prototype.__proto__ + ',' + Object.prototype.prototype); //function,object,null,undefinedconsole.log(typeof Function + ',' + typeof Function.prototype + ',' + Function.prototype.__proto__ + ',' + Function.prototype.prototype); //function,function,[Object],undefinedconsole.log(typeof F4 + ',' + typeof F4.prototype + ',' + F4.prototype.__proto__ + ',' + F4.prototype.prototype); //function,function,[Object],undefinedconsole.log(typeof o4 + ',' + typeof o4.__proto__ + ',' + o4.__proto__.__proto__ + ',' + o4.__proto__.prototype); //object,object,[Object],undefined

上图中o为普通对象,F为普通函数对象,椭圆表示函数对象,矩形表示函数对象,从中可以看出:
- 所有对象,包括函数对象的原型链最终都指向了Object.prototype,而Object.prototype.proto===null,原型链至此结束。
- Function.prototype是一个函数对象,但是Function.prototype却没有prototype属性,即Function.prototype.prototype===undefined,所以Function.prototype函数对象是一个特例,没有prototype属性。除Function.prototype外,其它函数对象如Object.prototype
Object.constructor===Function;说明Object是Function函数构造出来的。
函数对象的特殊属性
arguments
arguments其主要用途是用来保存函数参数。
arguments.length//值来判断实参的个数arguments[0]//表示传递的第一个元素arguments[1]//表示传递的第二个元素
arguments(不是Array的实例)对象还有一个属性:callee,指向拥有arguments对象的函数,在编写递归函数时常用。
function factorial(num){if(num<=1){return 1;}else{//return num*factorial(num-1);//一个实例化的函数对象可以拥有很多个名字,不应限定函数名必须是factorialreturn num*arguments.callee(num-1);}}
length
length表示每个函数准备接收的命名参数的个数,即形参的个数,区别于内部对象arguments是实参的个数。
function sum(num1,num2,num3){alert(arguments.callee.length);//方法2:内部对象调用}sum(1,2)alert(sum.length);//方法1:函数调用
this对象
this指向调用当前函数的对象,当在网页全局作用域中调用时,this对象引用的就是window。
function hello(){console.log('hello '+this.val);}var a={"val":"a","hello":hello},b={"val":"b","hello":hello};hello();//hello undefineda.hello();//hello ab.hello();//hello b
call,apply, bind
apply方法有两个参数,1个是在其中运行函数的作用域(即要调用函数的对象),另一个是参数数组。
call方法与apply方法的作用一样,但是接收参数的方式不同,其参数必须逐个例出来。
bind方法新创建一个函数对象,这个函数对象的this值绑定参数传入的对象。
call 和 apply差别:参数的样子不一样,另一个就是性能不一样。(apply的性能要差很多,可到 JSPerf 上去跑跑看看)
注意,在bind后,call、apply方法也不能改变this指针,如下面的示例hello.call(a,'pa');//hello a pahello.apply(a,['pa']);//hello a pahello.call(b,'pb');//hello b pbhello.apply(b,['pb']);//hello b pbvar h = hello.bind(a);hello();//hello undefined undefinedh();//hello a undefinedh.call(b,'pb');//hello a pbh.apply(b,['pb']);//hello a pb
new关键字
var Base=function(){}var obj=new Base();//上面中new操作符干了三件事情//1.初始化一个空对象objvar obj = {};//2.将这个空对象的__proto__成员指向了Base函数对象prototype成员对象obj.__proto__ = Base.prototype;//3.将Base函数对象的this指针替换成obj,然后再调用Base函数,初始化objBase.call(obj);
但要注意但函数本身返回值为对象时new操作符不起作用。
如果函数返回值为常规意义上的值类型(Number、String、Boolean)时,new函数将会返回一个该函数的实例对象,而如果函数返回一个引用类型(Object、Array、Function),则new函数与直接调用函数产生的结果等同。
var F3 = function () {this.a = 'a';var o = {'name' : 'name'};return o;}var o3 = new F3();console.log(o3.a); //undefinedconsole.log(o3.__proto__ === F3.prototype); //falseconsole.log(F3.prototype == F3.__proto__); //falseconsole.log(F3.__proto__ == Function.prototype); //trueconsole.log(o3.constructor === F3); //false;var F4 = function () {this.a = 'a';return this.a;}var o4 = new F4();console.log(o4.a); //'a'console.log(F4.prototype === o4.__proto__); //trueconsole.log(F4.prototype === F4.__proto__); //falseconsole.log(F4.prototype === Function.prototype); //falseconsole.log(F4.__proto__ === Function.prototype); //trueconsole.log(o4.constructor === F4); //trueconsole.log(o4.constructor === F4.prototype); //falseconsole.log(o4.constructor === F4.prototype.constructor); //true
JS面向对象编程时类函数定义方式
var F2 = function () {var inner='inner';this.o1 = 'o1';this.f1 = function () {console.log('f1 ' + this.o1+' '+ inner);}function f2() {console.log('f2 ' + this.o1+' '+ inner);}}F2.prototype.f3 = function () {//console.log('f3' + this.o1+' '+ inner);失败,找不到innerconsole.log('f3' + this.o1);}var o2 = new F2();o2.f1();//o2.f2();失败,找不到f2o2.f3();
js面向对象编程时类定义函数用prototype方式和this方式区别:this方式定义的函数如f1可以访问构造函数内部的变量如上例inner,prototype方式定义的函数f3则不能访问内部变量; 但如果所有函数都采用this方式定义则每次实例化都要执行,浪费内存,也不合理。
this方式定义方法叫做特权方法,主要是为了访问内部的私有字段,这样就可以控制对某些字段的访问。prototype方式定义的函数能访问这些特权方法,进而间接访问私有字段。
因此,如果要直接访问私有字段,应该使用特权方法,也就是this定义的方法,应该定义在构造函数内部。相反,如果不需要直接访问私有字段,应该使用prototype定义的方法,定义在构造函数外部。
参考:
Js中Prototype、proto、Constructor、Object、Function关系介绍
Js New一个函数和直接调用的区别
JS原型函数相关基础知识的更多相关文章
- three.js学习笔记--基础知识
基础知识 从去年开始就在计划中的three.js终于开始了 历史介绍 (摘自ijunfan1994的转载,感谢作者) OpenGL大概许多人都有所耳闻,它是最常用的跨平台图形库. WebGL是基于Op ...
- js基础例子dom+原型+oop基础知识记录01
//oo:概念是计算机中对于现实世界的理解和抽象的方法 //由计算机利用编程技术发展到现在的产物 //面向对象几要素 //对象:由属性和方法组成的集合 //属性:保存数据,存储在对象内存空间中的唯一的 ...
- JS 数组的基础知识
数组 一.定义 1.数组的文字定义 广义上说,数组是相同类型数据的集合.但是对于强类型语言和弱类型语言来说其特点是不一样的.强类型语言数组和集合有以下特点. 数组强类型语言:1.数组里面只能存放相同数 ...
- 云笔记项目-补充JS面向对象编程基础知识
简单介绍: 此部分知识为在做云笔记项目中补充,因为云笔记项目中涉及到前端js,里面写了很多js脚本,用到了创建js属性和方法,在js中直接声明的属性和方法最终都会变成window的对象,即其成为了全局 ...
- js与juery基础知识对比(一)---2017-05-06
用表格做的,想要对比的内容一目了然,红色部分为重点 js jquery 取元素 id: document.getElementById("aa"); 取到的是dom对象 cla ...
- js与jquery基础知识对比(一)---2017-05-06
用表格做的,想要对比的内容一目了然,红色部分为重点 js jquery 取元素 id: document.getElementById("aa"); 取到的是dom对象 cla ...
- HTML+CSS+JS基础知识
HTML+CSS+JS基础知识 目录 对HTML+CSS+JS的理解 基础知识 对HTML+CSS+JS的理解 基础知识 插入样式表的三种方式 外部样式表:<link rel="sty ...
- JavaScript基础知识从浅入深理解(一)
JavaScript的简介 javascript是一门动态弱类型的解释型编程语言,增强页面动态效果,实现页面与用户之间的实时动态的交互. javascript是由三部分组成:ECMAScript.DO ...
- Js基础知识(二) - 原型链与继承精彩的讲解
作用域.原型链.继承与闭包详解 注意:本章讲的是在es6之前的原型链与继承.es6引入了类的概念,只是在写法上有所不同,原理是一样的. 几个面试常问的几个问题,你是否知道 instanceof的原理 ...
随机推荐
- HTML5本地化应用开发-HTML5 Web存储详解
文章不是简单的的Ctrl C与V,而是一个字一个标点符号慢慢写出来的.我认为这才是是对读者的负责,本教程由技术爱好者成笑笑(博客:http://www.chengxiaoxiao.com/)写作完成. ...
- 【锋利的jQuery】学习笔记01
第一章 认识jQuery 一.常见的JS库 Prototype 最早的js库之一.把好用JS方法组合,缺点结构松散. Dojo 离线存储API.生成图标组件.矢量图形库.Comet支持.企业级JS库, ...
- JS 判断 Radio 单选按钮是否为选中状态 并弹出 值信息
今天项目中所解决的问题:JS 判断 Radio 单选按钮是否为选中状态 并弹出 值信息,一开始总是获取不到 radio 的值,后来发现逻辑存在些问题,特此共享该代码留笔记 和 分享给遇到 这类问题的 ...
- TransactionScope简单用法
记录TransactionScope简单用法,示例如下: void Test() { using (TransactionScope scope = new TransactionScope()) { ...
- 【基础】Oracle 表空间和数据文件
多个表空间的优势:1.能够将数据字典与用户数据分离出来,避免由于字典对象和用户对象保存在同一个数据文件中而产生的I/O冲突2.能够将回退数据与用户数据分离出来,避免由于硬盘损坏而导致永久性的数据丢失3 ...
- 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 ...
- [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 ...
- Command 模式
Command 模式通过将请求封装到一个对象(Command)中,并将请求的接受者存放具体的 ConcreteCommand 类中(Receiver)中,从而实现调用操作的对象和操作的具体实现 者之间 ...
- 3D Game Programming with directx 11 习题答案 8.2
第八章 第二题 1.首先找到Directx Texture Tool,它位于 2.填入配置 3.用画图工具画好每个level的图片,例如level0 4.用Directx Texture Tool添加 ...
- android入门到熟练(一)
1.andro系统架构:Linux内核层(提供驱动),系统运行库层和android运行时库(提供C/C++库的主要特性,如SQLite,OpenGL,Webkit等和Dalvik虚拟机),应用框架层, ...