-
Notifications
You must be signed in to change notification settings - Fork 0
/
content.json
1 lines (1 loc) · 9.16 KB
/
content.json
1
[{"title":"javascript探路:this为何物","date":"2017-04-06T13:34:04.000Z","path":"2017/04/06/javascript探路-this为何物/","text":"“我是谁,我在哪里,谁在打我”,最近在打《守望屁股》的途中经常听到这样的梗,这对本我的探寻似乎在写代码的途中也经常碰到。不信?你是否遇到过这样的错误 Uncatched TypeError: cannot read property ‘xxx’ of undefined 或者 Uncatched TypeError: xxx.yyy is not a function 回来一查才发现是this.xxx报错了。那么this为何这么神秘?它到底是什么? 1. this为何物 对于this大家必然部陌生,但是对于到底this表示什么,大家都明白吗?学过java,c#这类语言的都知道,this指向当前类的对象。但是在javascript中,this却并不是这么简单的。this是函数作用域中的一个变量,意为函数执行上下文。 2. 如何确定this 不像c#,javascript中的this是在函数执行时动态赋值的。函数的不同调用方式会导致不同的this赋值,关于函数的调用方式有如下4种 作为函数调用 作为方法调用 作为构造器调用 call,apply和bind调用 下面我们来具体看看着4种方式的this时如何确定的 作为函数调用 咋一看好像是巨废话(函数不作为函数调用?那要作为什么?)。这里的第二个“函数”意为,函数不挂靠在某个对象下,而是在全局变量中(其实window下的同名属性也是可以引用该函数的)。在作为函数调用时,this指向window(非严格模式下,在严格模式下为undefined)。让我们来验证一下: 可以看到console.log(this)打印的时window。 而在严格模式下,this变为了undefined。 作为方法调用 函数作为方法调用,意为函数挂载在对象的某个属性上。调用时,this指向该对象。 打印的this为对象a。简单的查找方法就是:作为方法调用是aaa.XXX()中的this指向.之前的aaa。其实你会发现,作为函数调用可以看作作为方法调用的一种特殊情况,因为全局函数x可以使用window.x()调用到。 作为构造器调用 作为构造器调用,就是这种用法new A()。这里的this指向什么呢?要先从new A()的执行流程开始说起。当使用new关键字调用一个函数时,会先产生一个对象o,接着将this指向o,然后执行函数体里的语句。如果函数体里没有return xxx语句,则返回对象o,否则返回xxx。 可以看到,没有显式返回时,返回的对象上有属性name和age,其值为函数体内的赋值。 而显式返回s时,可以看到s.age和s.name都不是函数体内this的赋值,s.a则指向函数A中的this。 call,apply和bind调用 call和apply方法挂载在Function.prototype对象上。作用是强制指定方法的this和函数调用时参数args。这两个函数的不同点是:call函数提供的args是以arg1,arg2…这样的形式提供的;而apply函数提供的args则是以数组的方式提供。而bind则是柯里化函数,返回一个强制绑定this的目标函数。 可以看到func()打印的test为window.test,而func.call(a)和func.apply(a)打印的test为a.test。 3. 复杂情况 上述4种调用方式都很容易确定this的值,那么在更加复杂的情况下会是怎样的呢?让我们来看一看。 new和bind同时使用 从上述实验中看到,在new和bind同时使用时,b.name===’qw’。可以得出结论:在new和bind同时使用时,new的优先级更高,this的取值按照构造器方式确定 函数赋值在上图中有(c=a.logAge)(),打印出的age等于10,由此得出这里的this指向的是window。那么为什么是这样呢?在表达式c=a.logAge中,分为左值c和右值a.logAge。对于左值,js会去作用域链中寻找对应的引用,当找不到时则会创建一个引用;而对于右值,js会去查找并返回引用的值,在上述例子中你可以理解为返回了function (){ console.log(this.age) }。因此表达式相当于(function () { console.log(this.age) })()。 4. 结语 写完收工。一看表11点了…正是睡觉的好时候。","tags":[{"name":"javascript","slug":"javascript","permalink":"http://yoursite.com/tags/javascript/"},{"name":"this","slug":"this","permalink":"http://yoursite.com/tags/this/"}]},{"title":"javascript闭包揭秘","date":"2017-03-05T13:46:47.000Z","path":"2017/03/05/javascript闭包揭秘/","text":"闭包是在学习javascript的过程中不可规避的一道屏障。掌握了闭包,才有可能从初级想中级迈进。自从学习js以来,我也看了许多篇关于闭包的文章,但是一致没能完全理解闭包到底是什么?它显得如此神秘,像是深林中的蓝精灵。在经过无数次的实验和查找书籍之后,终于对闭包有了一个较为清晰的理解。 1. 什么是闭包 就像一万个读者心中有一万个法姆雷特,对于闭包的理解,大家也各不相同。大致可以分为两种意见: 在函数A内创建函数B,就形成了闭包 创建一个函数就形成了闭包 我个人是比较倾向于第二种说法的。 在《Javascript高级程序设计》中关于闭包的解释提到: 闭包是指有权访问另一个函数作用于中变量的函数。创建函数的常见方式,就是在一个函数内部创建另一个函数。 在《你不知道的Javascript》中关于闭包是这样说的: 当函数可以记住并访问所在的词法作用域时,就产生了闭包 什么时词法作用域?简单的说,词法作用域就是定义在词法阶段的作用域(好像时废话),它决定了你能访问哪些变量。当然也有办法可以欺骗词法作用域,那就是使用with或者eval。也正是由于这样做时候作用域混乱,会导致各种不易发现的bug,因此各大规范都不建议使用with和eval。这中题外话就按住不表。 2. 闭包的本质 上面两种解释,都提到了可访问的变量。而函数的可访问变量由词法作用域链决定。所以,简单的说:闭包的本质就是词法作用域链查找变量的过程。理解闭包就是理解词法作用域链。那么,词法作用域链又是什么?既然时链,那么必然是一个类似链表的结构。假设有函数A,函数A内部有函数B。那么函数B的作用域链为: B -> A -> Global 函数A的作用域链为: A -> Global 3. 动手看看 来看个小实验:可以看到右侧的Scope部分的作用域链: Local -> Global,其中Local包括几个属性:B, a_a, a_b, this,而Global指向window 函数B的作用域链为: Local -> A -> Global,可以看到在函数B种包含了函数A的变量a_b。 从上面的实验可以看出: 词法作用域链是从函数本身开始,向上级直到指向Global为止 词法作用域内的可访问变量包括参数,变量和this 再来看另一个经典的实验12345678910function A(){ var result = [] for(var i=0;i<5;i++) { result[i] = function(){ console.log(i) } } return result;}var a = A(); 大家都知道全都会输出5。让我们从作用域链的角度来解析试下原因。a[0]~a[4]为匿名函数,Local作用域内没有可访问的变量;上级作用域为函数A,可访问的变量为result和i。当执行a0时,函数A已经运行完毕,由于循环,i已经赋值为5,因此输出为5. 要解决问题也很简单,将i引入到匿名函数中即可。从上一个实验的结论2中我们知道,作用域中可访问的变量有参数,变量和this。这里的变量指的是函数内部定义的局部变量,因此不可以用来解决这个问题,那么智能使用参数和this了。 上图中使用bind来强制改变this;从而将i引入,而最后的输出和预想的略有不同,应该是bind的机制要求this必须为object(无责任猜想),或者有哪位大大可以解释一下的? 这里使用了匿名函数(alias: nousB)将i引入。同时可以知道,这里的作用域链其实是被改变了的,在匿名函数与函数A之间多了一个作用域nousB,而i实际是在nousB的作用域内。 4. 结语 闭包在javascript的使用中颇为频繁,在各种库与框架中都有出现。它帮我们解决了很多问题,但它本身也并不是完美的:由于作用域链的保存也是需要占用空间的,因此,在大量使用闭包的时候会有内存占用偏高的情况;同时,若作用域链过长,而查找的变量在较外层甚至是Global上时,查找效率较慢。 闭包虽好,可不要贪心哟","tags":[{"name":"javascript","slug":"javascript","permalink":"http://yoursite.com/tags/javascript/"},{"name":"闭包","slug":"闭包","permalink":"http://yoursite.com/tags/闭包/"}]},{"title":"Hello World","date":"2017-01-09T12:50:09.188Z","path":"2017/01/09/hello-world/","text":"Welcome to Hexo! This is your very first post. Check documentation for more info. If you get any problems when using Hexo, you can find the answer in troubleshooting or you can ask me on GitHub. Quick StartCreate a new post1$ hexo new \"My New Post\" More info: Writing Run server1$ hexo server More info: Server Generate static files1$ hexo generate More info: Generating Deploy to remote sites1$ hexo deploy More info: Deployment","tags":[]}]