“链”这个概念也算是JS的一大特色了,这里总结了常见的JS链相关概念,资料主要还是来自于js权威指南这本书,再加上自己的一点理解,欢迎补充。
js作用域链
简单来说就是一个对象列表。那么这个对象列表是怎么来的呢?每次调用js函数时,编译器环境都会为这个js函数创建一个新的对象(上下文对象)来保存局部变量,并且把这个新的对象添加到作用域链中。当函数返回时,就从作用域链中将绑定变量的对象移除。
js权威指南中的一段话很好的诠释这个概念,摘录如下:
在js的顶层代码中(即不包含在任何函数定义内的代码),作用域链由一个全局对象组成。在不包含嵌套的函数体内,作用域链上有两个对象,第一个是定义函数参数和局部变量的对象(上下文对象),第二个是全局对象。在一个嵌套函数体内,作用域链上至少有三个对象。
对象作用域链创建规则,当定义一个函数时,它实际上保存一个作用域链。当调用这个函数时,它创建一个新的对象来存储它的局部变量,并将这个对象添加至保存的那个作用域链上,同时创建一个新的更长的表示函数调用作用域的"链"。
对于嵌套函数,每次调用外部函数时,内部函数会重新定义一遍。因此每次调用外部函数时,作用域链都不同。每次调用外部函数时,虽然内部嵌套函数的代码没变,但是关联这段代码的作用域链不相同了,所以内部函数也有差别,做永远链不同了。
js链式调用
这个就很容易理解了,使用过jQuery
的人应该都知道链式调用。方法的链式调用又称为方法链。如果一个对象有多个方法属性,并且每个方法属性的返回值都是这个对象,那么这个对象的方法属性就可以链式调用
例如:
//支持方法链式调用的对象
var obj = {
"first":function(){
console.log("first");
return this;
},
"second":function(){
console.log("second");
return this;
}
}
//方法链调用,在控制台输出:first second
obj.first().second()
最典型的例子就是jQuery
库,jQuery
库中绝大多数方法都支持链式调用。关于如何创建js对象,请参见这篇文章。
js原型链
理解原型链概念之前必须先理解原型的概念。
原型:是一个可以让其他对象继承属性的对象。没有原型的对象很少,例如Object.prototype
。普通对象都有原型,函数对象都有一个继承自Object.prototype
的原型,其中函数对象的原型通过prototype
属性获取,普通对象的原型通过__proto__
属性访问(只有标准浏览器支持)。
例子:var date = new Date() // Date.prototype就是Date的原型,date从原型中继承Date属性
接着上面的例子,date
对象的属性继承自Date.prototype
,Date.prototype
的属性又继承自Object.prototype
,所以date
对象的属性同时继承Date.prototype
和Object.prototype
,此时的Date.prototype
和Object.prototype
就是原型链。
下面的代码可以证明date
的属性继承自Date.prototype
,Date.prototype
的属性继承自Object.prototype
:
date instanceof Date //true
Date.prototype instanceof Object //true
date instanceof Object //true
date instanceof Date.prototype.constructor //true
Date.prototype instanceof Object.prototype.constructor //true
date instanceof Object.prototype.constructor //true
Object.getPrototypeOf(date) === Date.prototype //true
Object.getPrototypeOf(Date.prototype) === Object.prototype //true
Object.getPrototypeOf(date) === Object.prototype //false
PS:
instanceof
运算符用来测试一个对象在其原型链中是否存在一个构造函数的 prototype 属性;
Object.getPrototypeOf
,用来获取对象的原型,ES5标准推出的方法,用来获取生成对象的类的原型。