本文旨在记录JavaScript中面向对象的基础知识
JavaScript中,除了基本类型外,其它类型都是对象类型
typeof
: 当返回时"function"或者"object"字符串说明是引用类型对象instanceof
:通过obj instanceOf Object
返回true判断对象hasOwnProperty , isPrototypeOf
等对象都是由函数创建的,函数也是对象
var obj = new Object()
语句中的Object就是构造函数var obj = {}
这种字面量的创建方式其实是构造函数方式的语法糖而已,仅仅形式不同Number instanceof Object
返回true便可知var MyFunction = function(){}
其中MyFunction也是对象,该对象是通过Function函数创建的每个函数都有一个prototype
属性,该属性也是一个对象,称之为(显式)原型,默认含有一个constructor
属性,指向函数本身
constrcutor
的作用探讨,请参见两篇博客
__proto__
上的一个属性(如果该对象是函数,则在其prototype
上),通常指向生成这个对象的函数。另外,该对象上的__proto__
中的constructor与创建这个对象函数的prototype
中的contructor
是等同的对比函数上的显式原型prototype
,每一个对象上都有一个隐式原型__Proto__
__proto__
都指向创建该对象的函数的prototype函数中的prototype也是一个对象,依然拥有__proto__
属性。 自定义函数的prototype本质上就是和 var obj = {} 是一样的,都是被Object创建,所以它的__proto__
指向的就是Object.prototype
。Object.prototype
是一个特例,它的__proto__
指向的是null
函数也是一个对象,也是被创建出来的,因此也有__proto__
属性,指向的是Function.prototype
,Function.prototype
的__proto__
是Object创建的,因此指向了Object.prototype
传统的Javascript中只有对象,没有类的概念。它是基于原型的面向对象语言。原型对象特点就是将自身的属性共享给新对象 , ES6引入了Class(类)这个概念,通过class关键字可以定义类。该关键字的出现使得其在对象写法上更加清晰,更像是一种面向对象的语言 。这里只描述传统JS的继承实现,也就是ES6之前的版本
instanceOf 判断对象原理:Instanceof运算符的第一个变量是一个对象,暂时称为A;第二个变量一般是一个函数,暂时称为B。Instanceof的判断规则是:沿着A的__proto__
这条线来找,同时沿着B的prototype这条线来找,如果两条线能找到同一个引用,即同一个对象,那么就返回true。如果找到终点还未重合,则返回false
js的继承是基于原型链
__proto__
这条链向上找,这就是原型链继承的几种方式:
构造函数绑定
object()方法
以上关于继承的几种方式,可以参考阮一峰大神的三篇文章:
对比ES5和ES6的继承方式,关于ES6的继承,可以参考文章:
this是上下文环境的一部分,每次调用函数,都会产生一个新的执行上下文环境,this的取值都会有所不同
扩展:
所谓构造函数就是用来new对象的函数。其实严格来说,所有的函数都可以new一个对象,但是有些函数的定义是为了new一个对象,而有些函数则不是。另外注意,构造函数的函数名第一个字母大写(规则约定)。例如:Object、Array、Function等
call和apply的异同 :
callee和caller(这两个玩意少用) :
关于caller:
caller 返回一个对函数的引用,该函数调用了当前函数
对于函数来说,caller 属性只有在函数执行时才有定义。 如果函数是由 Javascript 程序的顶层调用的,那么 caller 包含的就是 null
关联在函数上 functonName(函数名).caller
注意:arguments.caller 已经不可使用了,但是你还可以使用 Function.caller。
function whoCalled() {
if (whoCalled.caller == null)
console.log('I was called from the global scope.');
else
console.log(whoCalled.caller + ' called me!');
}
关于 callee
返回正被执行的 Function 对象,也就是所指定的 Function 对象的正文,callee 属性的初始值就是正被执行的 Function 对象
关联在arguments上 arguments.callee
callee拥有length属性,arguments.length是实参长度,arguments.callee.length是形参长度
//1. callee可以打印其本身
function calleeDemo() {
alert(arguments.callee);
}
//2. 用于验证参数
function calleeLengthDemo(arg1, arg2) {
if (arguments.length==arguments.callee.length) {
window.alert("验证形参和实参长度正确!");
return;
} else {
alert("实参长度:" +arguments.length);
alert("形参长度: " +arguments.callee.length);
}
}
//3. 递归计算
var sum = function(n){
if (n < = 0)
return 1;
else
return n +arguments.callee(n - 1)
}
执行上下文也叫执行上下文环境
执行上下文就是JavaScript 在被解析和运行时环境的抽象概念,JavaScript 运行任何代码都是在执行上下文环境中运行的,执行上下文包括三个周期:创建——运行——销毁
几乎所有的语言都有作用域的概念,简单的说,作用域就是变量和函数的可访问范围,即作用域控制在变量和函数的可见性和生命周期。
在Javascript中,引擎、编译器和作用域共同协调完成Javascript的执行过程
Javascript没有块级作用域,所以我们在编写代码的时候,不要在“块”里面声明变量,要在代码的一开始就声明好了。以避免发生歧义
Javascript除了全局作用域之外,只有函数可以创建的作用域。所以,我们在声明变量时,全局代码要在代码前端声明,函数中要在函数体一开始就声明好。除了这两个地方,其他地方都不要出现变量声明。而且建议用“单var”形式
作用域有上下级的关系,上下级关系的确定就看函数是在哪个作用域下创建的。例如,fn作用域下创建了bar函数,那么“fn作用域”就是“bar作用域”的上级
作用域有上下级的关系,上下级关系的确定就看函数是在哪个作用域下创建的。例如,fn作用域下创建了bar函数,那么“fn作用域”就是“bar作用域”的上级
作用域最大的用处就是隔离变量。不同作用域下同名变量不会有冲突
如jQuery源码的最外层是一个自动执行的匿名函数。在jQuery源码中,声明了大量的变量,这些变量将通过一个函数被限制在一个独立的作用域中,而不会与全局作用域或者其他函数作用域的同名变量产生冲突。全世界的开发者都在用jQuery,如果不这样做,很可能导致jQuery源码中的变量与外部javascript代码中的变量重名,从而产生冲突
作用域和执行上下文关系
如我在全局中定义了一个变量a,然后我在函数中使用了这个a,这个a就可以称之为自由变量,可以这样理解,凡是跨了自己的作用域的变量都叫自由变量
闭包就是能够读取其他函数内部变量的函数。例如在javascript中,只有函数内部的子函数才能读取局部变量,所以闭包可以理解成“定义在一个函数内部的函数“。在本质上,闭包是将函数内部和函数外部连接起来的桥梁--百度百科
闭包的两种用法
bar函数作为返回值,赋值给f1变量。执行f1(15)时,用到了fn作用域下的max变量的值
fn函数作为一个参数被传递进入另一个函数,赋值给f参数。执行f(15)时,max变量的取值是10,而不是100
?
闭包的用途
读取函数内部的变量
让变量的值始终保持在内存中
注意点
闭包相关参考
原文:https://www.cnblogs.com/DiDi516/p/11762474.html