• js的作用域 与 this
    • 作用域
    • this
    • 实战经验
      • 1.在Vue的方法定义中容易用错。
      • 2.在发起http请求时容易用错
      • 3.在event handler中容易用错

    js的作用域 与 this

    无论是 javascript, 还是 emscript, 变量的作用域都属于高级知识。 我们想考察一个js程序员的水平如何,可以直接用作用域来提问。

    同时,我们在实际的开发中发现,很多js/emscript 的新人,对于作用域和 this 都很含混,所以这里要单独的提一下。

    作用域

    无论是 javascript, 还是 emscript, 对于作用域的使用基本是一样的。 后者更加严密一些。 我们看几个例子。

    1.全局变量, 可以直接引用。

    1. //全局变量 a:
    2. var a = 1;
    3. function one() {
    4. console.info(a)
    5. }

    打印结果是 1

    2.函数内的普通变量

    1. function two(a ){
    2. console.info('a is' + a)
    3. }

    运行:

    two(2) 打印结果是 : a is 2

    3.普通函数可以对全局变量做赋值。 如下图所示:

    1. var a = 1;
    2. function four(){
    3. console.info(' in four, before a=4: ' + a)
    4. if(true) a = 4;
    5. console.info(' in four, after a=4: ' + a)
    6. }

    运行:

    1. four(4)

    结果:

    1. in four, before a=4: 1 ( 这个是符合正常的scope逻辑的。)
    2. in four, after a=4: 4 ( 这个也是符合)

    再运行: console.info(a), 可以看到输出: 4 说明 全局变量 a 在 four()函数中已经被发生了永久的变化。

    4.通过元编程定义的函数

    1. var six = ( function(){
    2. var foo = 6;
    3. return function(){
    4. return foo;
    5. }
    6. }
    7. )();

    在上述代码中, js解析器会先运行(忽略最后的 () ):

    1. var temp = function(){
    2. var foo = 6;
    3. return function(){
    4. return foo;
    5. }
    6. }

    然后再运行: var six = (temp)() , 所以, six 就是:

    1. function(){
    2. return foo;
    3. }

    上面的 foo 就是来自于方法最开始定义的 var foo = 6, 而这个变量的定义,是在一个 function() 中的。 所以它不是一个全局变量。

    所以,如果我们在console中输入 foo , 会看到报错消息: Uncaught ReferenceError: foo is not defined

    5.通过元编程定义的函数中的变量,不会污染全局变量。

    1. var foo = 1;
    2. var six = ( function(){
    3. var foo = 6;
    4. return function(){
    5. console.info("in six, foo is: " + foo);
    6. }
    7. }
    8. )();

    在上面的代码中,我们先定义了一个 全局变量 foo, 再定义了一个方法 six, 里面定义了一个临时方法 foo. 并且进行来了一些操作。

    运行:

    1. six() // 返回: in six, foo is: 6
    2. foo // 返回: 1

    this

    对于 this 的使用, 在这里 https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/this 指出了对于javascript中this的详细用法。

    在emscript中也基本是一样的。

    简单的说,大家只要记得, this 指的是当前作用域的对象实例就好了。

    1. var apple = {
    2. color: 'red',
    3. show_color: function() {
    4. return this.color
    5. }
    6. }

    我们输入 apple.show_color 就可以看到输出 red. 这里的 this 指的就是 apple 变量。

    实战经验

    1.在Vue的方法定义中容易用错。

    当我们发现 代码看起来没问题, 但是console 总报错说 xx undefined 时, 十有八九就是 忘记加 this 了。

    例如:

    1. <html>
    2. <head>
    3. <script src="https://cdn.jsdelivr.net/npm/vue@2.5.16/dist/vue.js"></script>
    4. </head>
    5. <body>
    6. <div id='app'>
    7. {{ message }}
    8. <br/>
    9. <button v-on:click='highlight' style='margin-top: 50px'>真的吗</button>
    10. </div>
    11. <script>
    12. var app = new Vue({
    13. el: '#app',
    14. data: {
    15. message: 'this 是很重要的。 不要忘记它哟~'
    16. },
    17. methods: {
    18. highlight: function() {
    19. // 报错: message is not defined.
    20. message += '是的, 工资还会涨~!'
    21. // 正确的代码应该是:
    22. // this.message += '是的, 工资还会涨~!'
    23. }
    24. }
    25. })
    26. </script>
    27. </body>
    28. </html>

    使用浏览器加载上述代码,我们会发现报错了:

    this的错误用法

    上面的代码中, message += ... 那一行中, message 是当前的vue的实例的一个”property”(属性), 而我们如果希望在 methods 中引用这个属性的话,就需要用 this.message 才对。 这里的 this 对应的就是 var app = new Vue() 中定义的 app.

    2.在发起http请求时容易用错

    我们看下面的例子,是一段代码片段:

    1. new Vue({
    2. data: {
    3. cities: [...]
    4. },
    5. methods: {
    6. my_http_request: function(){
    7. let that = this
    8. axios.get('http://mysite.com/my_api.do')
    9. .then(function(response){
    10. // 这里不能使用 this.cities 来赋值
    11. that.cities = response.data.result
    12. })
    13. }
    14. }
    15. })

    在上面的代码中,我们定义了一个属性: cities, 定义了一个方法: my_http_request. 该方法会向远程发起一个请求,然后把返回的response中的值赋给 cities.

    可以在上面代码中看到, 需要先在 axios.get之前,定义一个变量 let that = this. 这个时候, thisthat 都处于 “Vue”的实例中。

    但是在 axios.get(..).then() 函数中,就不能再使用this 了。 因为在 then(...) 中,这是个function callback, 其中的 this 会代表这个 http request event. 这是个事件。

    所以, 只能用这样的方式。

    (如果使用了 emscript 的 => 的话,就可以避免上述问题)

    3.在event handler中容易用错

    道理同上。