标签:har https 指定 function name each fill length 函数调用
前端技术更新很快,几个月前我还在写React,现在又有人建议我学学Vue了。思考之后决定先沉下心来补补JavaScript基础。You Dont Know JS一系列书不错。这一系列博客是我读这本书以后总结的干货。
知乎的习惯是先问是什么,再问为什么,到这篇博客却要翻过来讲。如果没有需要使用this的场景,那我们就没必要知道this到底是什么了。
请看下面的例子:
// 使用this的动机
function tellName(){
console.log(‘name is‘, this.name);
}
let personOne = {
name: ‘Claire‘
}
let personTwo = {
name: ‘LYY‘
}
tellName.call(personOne);
tellName.call(personTwo);
控制台打印结果:
从以上this
的使用中可以发现,我们在写代码时候往往希望一个函数在不同环境下行为风格一致但是具体表现不一样,也就是使用当前环境下的同名变量进行相同工序的“加工”,变量的具体值不同但“加工”工序相同。当然可以选择把这个“环境”作为参数传入函数,但this
是一个更优雅的选择。
我们现在模糊知道this
是一个和调用环境相关的东西,但是很多时候我们还是不知道如何确定this
。在说明如何确定本次调用this
之前,请明确以下几点。
this
不是编写时候绑定的,而是运行时绑定的,它依赖于函数调用的上下文条件,也就是说this
与函数声明的位置无关,反而和函数被调用的方式有关this
引用下面是一个使用this的例子:
// 通用例子
function foo(num){
console.log(‘foo: ‘ + num);
//尝试追踪foo被调用的次数
this.count++;
}
foo.count = 0;
var i;
for(i=0; i<10; i++){
if(i > 5){
foo(i);
}
}
console.log(‘The times foo is called: ‘, foo.count);
下面进行讲解确定this
的规则。
一个完全独立的函数(既不是构造函数也不是对象的方法,直接通过function关键字声明),在‘use strict‘
模式下this
为undefined
,非严格模式下this
绑定到window
上。举个小例子:
function findThis(){
console.log(this);
}
findThis();
打印结果:
"use strict";
function findThis(){
console.log(this);
}
findThis();
打印结果:
现在我们可以分析一下上一小节中通用例子打印了什么。上一节例子直接用function声明,适用Default Binding规则,分两种情况:
foo
中的this
为undefined
,程序会报错,毕竟undefined
不能执行++
操作foo
中的this
为window
,window
下没有声明count
这个变量,会自动赋值window.count = NaN
,程序可以执行,但是在执行++
操作的是window.count
而不是foo.count
,所以打印结果为0,见下图如果把foo
中的this.count++
改为foo.count++
就可以打印出4啦。
隐含绑定:调用该函数时,该函数是否拥有一个环境对象(Context Object)。
要理解这句话,首先得知道函数在何时被调用,这就涉及到两个概念——调用点(call-site)和调用栈(call-stack)。调用点指函数在代码中被调用的位置(不是被声明的位置)。调用栈指使我们到达当前执行位置而被调用的所有方法的堆栈。原文中举了如下例子:
function baz() {
// call-stack is: `baz`
// so, our call-site is in the global scope
console.log( "baz" );
bar(); // <-- call-site for `bar`
}
function bar() {
// call-stack is: `baz` -> `bar`
// so, our call-site is in `baz`
console.log( "bar" );
foo(); // <-- call-site for `foo`
}
function foo() {
// call-stack is: `baz` -> `bar` -> `foo`
// so, our call-site is in `bar`
console.log( "foo" );
}
baz(); // <-- call-site for `baz`
很容易理解,复杂情况下人工分析调用点和调用栈可能比较难,可以借助debug进行。
隐含绑定:调用该函数时,该函数是否拥有一个环境对象(Context Object)。这里的调用函数时,就是函数的调用点。
看下面的代码:
function findThis(){
console.log(this.name);
}
var name = ‘window‘;
var context = {
name: ‘context‘,
findThis: findThis
};
context.findThis(); //context
但是,请注意以下两种情况:
function findThis(){
console.log(this.name);
}
var name = ‘window‘;
var contextOne = {
name: ‘one‘,
findThis: findThis
};
var contextTwo = {
name: ‘two‘,
context: contextOne
}
//仅离函数最近的对象为其调用环境
contextTwo.context.findThis(); //one
function findThis(){
console.log(this.name);
}
var name = ‘window‘;
var contextOne = {
name: ‘one‘,
findThis: findThis
};
var newFindThis = contextOne.findThis;
//赋值以后调用环境丢失,降级为default binding
newFindThis(); //window
为了避免调用环境丢失,常常进行明确绑定。可以使用call
, apply
, bind
或者自己写一个工具函数。bind
与call
和apply
的区别在于,bind
在定义函数时候就绑定this
,call
和apply
在调用函数时候才绑定this
,故而bind
更不容易被更改,在书中被称为Hard Binding,是Explicit Binding的变种。
另外,一些API中会隐含地使用以上函数,比如:
var context = {
name: ‘context‘
};
[1, 2, 3].map(function(item){console.log(item, this.name)}, context);
打印结果:
JavaScript中构造函数就是一个普通的函数。当一个函数前被使用new调用时就称为构造函数。new调用会自动完成以下工作:
function Person(name){
this.tellName = function(){
console.log(name);
};
}
var lyy = new Person(‘lyy‘);
lyy.tellName(); //lyy
当一次调用符合以上四条规则的多条时候,按照以下优先级确定this
:
JavaScript-读 You Dont Know JS,this到底是什么
标签:har https 指定 function name each fill length 函数调用
原文地址:http://blog.csdn.net/qiqingjin/article/details/71200688