前端:JavaScript编码原则 | 青训营笔记
这是我参与「第五届青训营 」伴学笔记创作活动的第 18 天
内容
this 指向问题
this 指代当前的对象,也就是调用了函数的对象。如果在一个对象上使用点或者方括号来访问属性或方法,这个对象就成了 this。如果并没有使用“点”运算符调用某个对象,那么 this 将指向全局对象(global object)。这是一个经常出错的地方。
case1:
function makePerson(first, last) {
return {
first: first,
last: last,
fullName: function() {
return this.first + ' ' + this.last;
},
fullNameReversed: function() {
return this.last + ', ' + this.first;
}
}
}
s = makePerson("Simon", "Willison");
s.fullName(); // "Simon Willison"
s.fullNameReversed(); // Willison, Simon
case2:
s = makePerson("Simon", "Willison");
var fullName = s.fullName;
fullName(); // undefined undefined
case2可以理解为 s = {…}; fullname = {…}.fullName;所以fullname是全局的函数名
再次调用时,fullname()<=>"window".fullname;所以this指向全局对象而报错
同理,case1就好理解了
总之,this始终指向调用它的对象
Person.prototype
Person.prototype 是一个可以被 Person 的所有实例共享的对象。它是一个名叫原型链(prototype chain)的查询链的一部分:当你试图访问 Person 某个实例(例如上个例子中的 s)一个没有定义的属性时,解释器会首先检查这个 Person.prototype 来判断是否存在这样一个属性。所以,任何分配给 Person.prototype 的东西对通过 this 对象构造的实例都是可用的。
这个特性功能十分强大,JavaScript 允许你在程序中的任何时候修改原型(prototype)中的一些东西,也就是说你可以在运行时 (runtime) 给已存在的对象添加额外的方法:
s = new Person("Simon", "Willison");
s.firstNameCaps(); // TypeError on line 1: s.firstNameCaps is not a function
Person.prototype.firstNameCaps = function() {
return this.first.toUpperCase()
}
s.firstNameCaps(); // SIMON
avg.apply()
apply() 的第一个参数应该是一个被当作 this 来看待的对象。
下面是一个 new 方法的简单实现:
function trivialNew(constructor, ...args) {
var o = {}; // 创建一个对象
constructor.apply(o, args);
return o;
}
var bill = trivialNew(Person, "William", "Orange"); == var bill = new Person("William", "Orange");
avg.call()
它也可以允许你设置 this,但它带有一个扩展的参数列表而不是一个数组。
function lastNameCaps() {
return this.last.toUpperCase();
}
var s = new Person("Simon", "Willison");
lastNameCaps.call(s);
// 和以下方式等价
s.lastNameCaps = lastNameCaps;
s.lastNameCaps();
闭包
举例说明
// case1:普通函数
funciton add(a, b) {
return a+b;
}
var sum = add(5, 20)
// case2:闭包
function makeAdder(a) {
return function(b) {
return a + b;
}
}
var add5 = makeAdder(5);
var add20 = makeAdder(20);
add5(6); // ?
add20(7); // ?
case1:
case2:
补充概念
- 执行上下文
创建阶段包括:作用域链、变量对象、this
执行阶段包括:变量赋值、函数引用等- 作用域链:当前变量对+所有父级变量对象
变量对象:参数、变量
每当函数每当 JavaScript 执行一个函数时,都会创建一个作用域对象(scope object),用来保存在这个函数中创建的局部变量。它使用一切被传入函数的变量进行初始化(初始化后,它包含一切被传入函数的变量
当调用makerAdder时,a,这个属性被当作参数传入makeAdder 函数
然后makeAdder 返回一个新创建的函数(暂记为 adder)
通常,JavaScript 的垃圾回收器会在这时回收 makeAdder 创建的作用域对象(暂记为 b),但是,makeAdder 的返回值,新函数 adder,拥有一个指向作用域对象 b 的引用。最终,作用域对象 b 不会被垃圾回收器回收,直到没有任何引用指向新函数 adder。
参考文献:
附:如有错误,恳请指正,侵权必删 :D