TedQin


  • Home

  • Categories

  • Archives

  • Tags

什么时候需要保存this?

Posted on 2019-10-17 | In 前端 , javascript

https://www.imooc.com/wenda/detail/312105

javascript中this什么时候可以直接调用?什么时候要把它赋值给一个变量后才能调用?

  • 1) 避免多层this

      var o = {  
    
           f1: function() {    
    
               console.log(this);      
    
              var f2 = function() {      
    
                   console.log(this);    
    
               }();   
    
              }     
    
      } 
    
      o.f1()
    

    上面代码包含两层this,结果运行后,第一层指向该对象,第二层指向全局对象。一个解决方法是在第二层改用一个指向外层this的变量。

      var o = {   
    
          f1: function() {     
    
              console.log(this);      
    
              var that = this;     
    
              var f2 = function() {       
    
                  console.log(that);     
    
              }();   
    
          } 
    
      } 
    
      o.f1()
    

    上面代码定义了变量that,固定指向外层的this,然后在内层使用that,就不会发生this指向的改变。

  • 2) 避免数组处理方法中的this

    数组的map和foreach方法,允许提供一个函数作为参数。这个函数内部不应该使用this。

      var o = {
       v: 'hello',
       p: [ 'a1', 'a2' ],
       f: function f() {
         this.p.forEach(function (item) {
           console.log(this.v+' '+item);
         });
       }}
    
      o.f()
    

    上面代码中,foreach方法的参数函数中的this,其实是指向window对象,因此取不到o.v的值。

    解决这个问题的一种方法,是使用中间变量。

      var o = {
       v: 'hello',
       p: [ 'a1', 'a2' ],
       f: function f() {
         var that = this;
         this.p.forEach(function (item) {
           console.log(that.v+' '+item);
         });
       }}
    
      o.f()
    

    另一种方法是将this当作foreach方法的第二个参数,固定它的运行环境。

      var o = {
       v: 'hello',
       p: [ 'a1', 'a2' ],
       f: function f() {
         this.p.forEach(function (item) {
           console.log(this.v+' '+item);
         }, this);
       }}
    
      o.f()
    
  • 3) 避免回调中的this

      var o = new Object();o.f = function (){
      console.log(this === o);}o.f()
    

    上面代码表示,如果调用o对象的f方法,其中的this就是指向o对象。

    但是,如果将f方法指定给某个按钮的click事件,this的指向就变了。

      $('#button').on('click', o.f);
    

vue的一些知识整理

Posted on 2019-10-10 | In 前端

父子组件传值

  • 父组件向子组件传值

      //html
      //1.父组件通过v-bind给子组件传值
      <todo-item v-bind:content="data1"></todo-item>
    
      //script
      //定义全局组件
      Vue.component("TodoItem", {
          //2.子组件通过props接收
          props: ['content']
          //也可以用对象形式进行参数校验
          //props: {content: String}//只允许接受string
          template: "<li>{{content}}</li>"
      })
    
      var app = new Vue({
          ...
          data: {
              data1: "ted" 
          }
      })
    
  • 子组件向父组件传值

      //html
      //2.父组件使用子组件时,通过v-on监听触发的事件
      //一旦子组件delete触发,就会触发父组件handleItemDelete这个方法
      <todo-item v-on:delete="handleItemDelete">
      </todo-item>
    
      //script
      var TodoItem = {
          data: {
              data1: 'ted'
          },
          template: "<li v-on:click='handleButtonClick'>点我删除</li>",
          methods: {
              handleButtonClick: function() {
                  //1.子组件通过$emit向外触发delete事件,并传出data1
                  this.$emit("delete", data1)
              }
          }
      }
    
      var app = new Vue({
          ...
          methods: {
              //3.父组件使用子组件的值
              handleItemDelete: function(data1) {
                  alert("data1")
              }
          }
      })
    

非父子组件传值

  • 观察者模式

      <!-- 非父子组件传值 -->
    <!-- 通过观察者模式实现,两个子组件之间传值,点击其中一个组件,另一个组件的值变成这个被点击组件的值-->
    <!DOCTYPE html>
    <html lang="en">
    <head>
    <meta charset="UTF-8">
    <title>Document</title>
    <script src="./vue.js"></script>
    </head>
    <body>
    <div id="root">
      <child :content="content1"></child>
      <child :content="content2"></child>
    </div>
    <script>
      //1. 在Vue的prototype上定义一个bus
      Vue.prototype.bus = new Vue()
    
      Vue.component('child', {
        props: {
          content: String
        },
        template: '<div v-on:click="handleClick">{{content}}</div>',
        methods: {
          handleClick: function() {
            //使用bus向外触发事件
            this.bus.$emit('change', this.content)
          }
        },
        //利用钩子函数,监听change事件
        mounted: function() {
          var this_ = this
          this.bus.$on('change', function(msg) {
            this_.content = msg
          })
        }
      })
    
      var vm = new Vue({
        el: "#root",
        data: {
          content1: "tedqin",
          content2: "teddymoon"
        }
      })
    </script>
    </body>
    </html>
    
    
  • vuex

全局组件和局部组件

  • 全局组件:用Vue.component()方法定义,其他组件可以直接使用

      //html
      //父组件通过v-bind给子组件传值
      <todo-item v-bind:content="data1"></todo-item>
    
      //script
      //定义全局组件
      Vue.component("TodoItem", {
          //子组件通过props接收
          props: ['content']
          template: "<li>{{content}}</li>"
      })
    
      var app = new Vue({
          ...
          data: {
              data1: "ted" 
          }
      })
    
  • 局部组件:像普通对象一样定义,其他组件引用的时候需要注册

      //html
      //父组件通过v-bind给子组件传值
      <todo-item v-bind:content="data1"></todo-item>
    
      //script
      //定义局部组件
      var TodoItem = {
          props: ['content']
          template: "<li>{{content}}</li>"
      }
    
      var app = new Vue({
          ...
          //把局部逐渐注册到到需要引用它的组件的vue实例中
          components: {
              TodoItem: TodoItem
          }
          data: {
              data1: "ted" 
          }
      })
    

v-bind,v-model,v-for和v-on

  • v-bind:用于给标签/组件绑定属性,实现动态管理标签的属性

      //html
      <a v-bind:href="url">网络测试</a>  //v-bind绑定href
    
      //script
      var app = new Vue({
          ...
          data {
              url: "http://www.baidu.com"
              }
      })
    
      //html
      //父组件通过v-bind给子组件传值
      <todo-item v-bind:content="data1"></todo-item>
    
      //script
      Vue.component("TodoItem", {
          //子组件通过props接收
          props: ['content']
          template: "<li>{{content}}</li>"
      })
    
      var app = new Vue({
          ...
          data: {
              data1: "ted" 
          }
      })
    
  • v-model:实现数据和视图层的双向绑定,只能定义在input,select,textarea上,绑定之后随着input输入的变化,对应绑定的内容也变化,反之也变化

      //html
      <input type="text" v-model="inputValue" />
    
      //script
      var app = new Vue({
          ...
          data: {
              inputValue: ''
          }
      })
    
  • v-for:循环data

      //循环数组
      //html
      <li v-for="item of list">{{item.text}}</li>
      <li v-for="(item, index) of list">{{item.text}}---{{index}}</li>
      <li v-for="(item, index) of list" :key="item.id">{{item.text}}---{{index}}</li>  <!--用index的时候最好再用key唯一标识-->
    
      //script
      var app = new Vue({
          ...
          data: {
              list: [{
                  id: "1",
                  text: "ted"
              }, {
                  id: "2",
                  text: "xxy"
              }]
          }
      })
    
      //循环对象
      //html
      <li v-for="(item, key, index) of list">{{item}}--{{key}}--{{index}}</li>
      <!--输出"ted--name--0 23--age--1"-->
    
      //script
      var app = new Vue({
          ...
          data: {
              list: {
                  name: "ted",
                  age: "23"
              }
          }
      })
    
  • v-on:绑定事件

      //html
      <button v-on:click="handleButtonClick">提交</button>
    
      //script
      var app = new Vue({
          ...
          methods: {
              handleButtonClick: function() {
                  alert("click!")
              }
          }
      })
    

v-text和v-html的区别

  • v-text: 等同于插值表达式双括号,绑定当前元素的innerText,会原封不动的输出纯文本
  • v-html: 绑定当前元素的innerText,会以html规则编译文本内容后输出

      //html
      <div v-text="name"></div>    <!--输出<h1>ted</h1>-->
      <div v-html="name"></div>    <!--输出h1大小的ted-->
    
      //script
      var vm = new Vue({
          el:"#app",
          data: {
              name:"<h1>ted</h1>"
          }
      })
    

计算属性 computed

和逻辑有关的计算都放在computed中,不方便直接在模版中计算

例子:

  • get属性

      <div id="example">
        <p>Original message: "{{ message }}"</p>
        <p>Computed reversed message: "{{ reversedMessage }}"</p>
      </div>
    
      var vm = new Vue({
        el: '#example',
        data: {
          message: 'Hello'
        },
        computed: {
          // 计算属性的 getter
          reversedMessage: function () {
            // `this` 指向 vm 实例
            return this.message.split('').reverse().join('')
          }
        }
      })
    
  • set属性

      computed: {
        fullName: {
          // getter
          get: function () {
            return this.firstName + ' ' + this.lastName
          },
          // setter
          set: function (newValue) {
            var names = newValue.split(' ')
            this.firstName = names[0]
            this.lastName = names[names.length - 1]
          }
        }
      }
    

上面代码中,get作用是通过监听firstName和lastName的改变,获取fullName的值;
set的所用是传入需要改变的fullName,并根据参数更新firstName和lastName的值

  • 和method的不同:
    • 计算属性中的值依赖data中相关联的值
    • computed存在缓存机制:每次重新渲染时,对于method,每次都会重新计算;对于计算属性,仅当data中依赖的值改变时,计算属性的值才改变,

侦听器 watch

和computed相似,同样是监听data中的值,当data发生改变时,执行相应的操作
也具有缓存效果

  • 和computed的不同:
    • computed是定义并计算一个新的值,这个值依赖data中的某些值
    • watch是监听data中已经存在的变量,并在data发生改变的时候做相应的操作
    • computed比watch更加简洁

样式绑定

  • class绑定::class=等价于: v-bind:class= ,将class绑定在一个标签上,可以控制class的显示与否

    • class的对象绑定 :class="{activated: isActivated}"

        <style>
            .activated {color: red}
        </style>
      
        <div @click="handleDivClick>  
              :class="{activated: isActivated}"></div>
      
          var vm = new Vue({
              el: "#app",
              data: {
                  isActicated: false
              },
              method: {
                  handleDivClick: function() {
                      this.isActivated = true
                  }
              }
          })
      
      
    • class的数组绑定 :class="[activated]"
    ```
    <style>
        .activated {color: red}
    </style>

    <div @click="handleDivClick>  
          :class="{activated: isActivated}"></div>

      var vm = new Vue({
          el: "#app",
          data: {
              activated: ""
          },
          method: {
              handleDivClick: function() {
                  this.activated = "activated"
              }
          }
      })

    ``` 
  • 内联样式绑定

    • style的对象绑定

        <div :style="styleObj" v-on:click="handleDivClick"></div>
      
          var vm = new Vue({
              el: "#app",
              data: {
                  styleObj: {
                      color: red
                  }
              },
              methods: {
                  handleDivClick: function() {
                      this.styleObj.color = red
                  }
              }
          })
      
    • style的数组绑定

      只需要把<div :style="styleObj"换成<div :style=[styleObj, {fontSize: '20px'}]

条件渲染

  • v-if: 隐藏的元素不会被渲染到页面上,还可以用v-else
  • v-show: 隐藏的元素已经被渲染到页面上,只是用了display:none来隐藏

      <div v-if="show">{{name}}</div>
      <div v-else="show">Bye</div>
      <div v-if="show===a">a</div>
      <div v-else-if="show===b">b</div>
      <div v-else>bye</div>
    
      <div v-show="show">{{name}}</div>
    
      var vm = new Vue({
          el: "#app",
          data: {
              name: 'ted',
              show: false
          },
      })
    

vue中的set方法

arr=[1,2,3,4,5]
data={
    name: "ted",
    age: "23"
}

改变页面中的渲染出来的对象或数组,不能直接用arr[3]=5这样直接改,只能修改数组/对象的引用,即this.arr=[1,2,5,4,5]全部修改

  • 也可以用Vue.set()方法修改,set方法也可以添加新的数据

      //改数组
      Vue.set(this.arr, 0, 11) //[11,2,3,4,5]
      //改对象
      Vue.set(this.data, "name", "teddy") //{name:"teddy", age: "23"}
    

slot插槽:

父组件向子组件传递dom结构: 直接在子组件中定义,然后在template中引入

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Document</title>
  <script src="./vue.js"></script>
</head>
<body>
  <div id="app">
    <child>
      <h1>tedqin</h1>
    </child>
  </div>
  <script>
    Vue.component('child', {
      template: `<div>
                          <p>hello</p>
                      <slot></slot>
                  </div>
                `
    })

    var vm = new Vue({
      el: "#app"
    })
  </script>

</body>
</html>
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Document</title>
  <script src="./vue.js"></script>
</head>
<body>
  <div id="app">
    <child>
      <header slot="header"></header>
      <footer slot="footer"></footer>
    </child>
  </div>
  <script>
    Vue.component('child', {
      template: `<div>
                          <slot name="header"></slot>
                          <p>hello</p>
                      <slot name="footer"></slot>
                  </div>
                `
    })

    var vm = new Vue({
      el: "#app"
    })
  </script>

</body>
</html>

动态组件

<component :is="type"></component>

//
Vue.component('type1', {
    template: '<div>type1</div>'
})
Vue.component('type2', {
    template: '<div>type2</div>'
})

//
data:{
    type: 'type1'
}

//
methods: {
    handleBtnClick: function(){
        this.type = (this.type==="type1" ? 'type2' : 'type1')
    }
}

根据is属性绑定的data数据中的type动态切换组件

v-once

将第一次展示在页面中的资源保存在内存中,下次直接从内存中取资源,可以优化性能,提高静态页面展示效率

##vue的路由

  • src/main.js

    • 入口文件,定义了一个根实例

      import Vue from 'vue'
      import App from './App'
      import router from './router'
      
      new Vue({
        el: "app", //app挂载点在./index.html上
        router, //使用router,在路由配置文件index.js中配置路由
        components: { App }, //使用子组件App
        template: '<App/>' //渲染App这个局部组件
      })
      
  • src/App.js

    • App局部组件,也就是main.js渲染的页面,也就是主页面

      <template>
        <div id="app>
            <router-view> //显示当前路由地址所对应的路由内容
        </div>
      </template>
      
      <script>
      export default {
        name: 'App'
      }
      <sctipt>
      
      <style>
      #app {
        ...
      }
      <style>
      
  • src/router/index.js

    • 路由配置项

      `
      import Vue from ‘vue’
      import Router from ‘vue-router’
      import Home from ‘@/pages/home/Home’
      import Home from ‘@/pages/list/List’

Vue.use(Router)

export default new Router({
    routes: [
        {
            path: '/', //1.当用户访问根路径的时候
            name: 'Home', 
            components: Home // 2.访问home这个单文件组件
        }, {
            //增加其他页面的配置项
            path: '/list',
            name: 'List',
            components: List
        }
    ]
})
```     
  • @/pages/home/Home.vue

    • 主页,单文件组件

      <template>
        <div>home</div>
      </template>
      
      <script>
      export default {
        name: 'Home'
      }
      </script>
      
      <style>
      </style>
      
  • @/pages/list/List.vue

    • list页面,单文件组件

      <template>
        <div>list</div>
      </template>
      
      <script>
      export default {
        name: 'List'
      }
      </script>
      
      <style>
      </style>
      

vue是单页面应用,用替换a标签

<router-link to="/list">点击跳转</router-link>

html5知识整理

Posted on 2019-09-30 | In 前端

h5变化

  • 表单增强属性
    • 日期、时间、搜索
    • 表单验证 (required必填,minmax输入范围,正则)
    • placeholder 表单空的时候显示什么内容 自动聚焦
  • 新增语义
    • header/footer
    • section/article 区域 (块级)
    • nav 导航(快级)
    • aside(快级)
    • em/strong 强调
  • 新API
    • 离线 (applicationCache )
    • 音视频 (audio, vidio)
    • 图形 (canvas)
    • 实时通信(websoket)
    • 本地存储(localStorage, indexDB)
    • 设备能力(地图定位,手机摇一摇)

Doctype 作用?标准模式与兼容模式各有什么区别?

<!DOCTYPE html>声明位于HTML文档中的第一行,不是一个HTML标签,它的作用:告知web浏览界面应该使用哪个html版本。

  • 标准模式:<!DOCTYPE html>

    h5及以后的版本,以该浏览器支持的最高标准运行

  • 兼容模式:
    <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">

    h5以前的版本,页面以宽松的向后兼容的方式显示,模拟老式浏览器的行为以防止站点无法工作。
    需引用DTD(文档类型说明),因为html 4.0.1是基于SGML(Standard Generalized Markup Language,标准通用标记语言)。DTD指定了标记语言的规则,确保了浏览器能正确的渲染内容。

行内元素有哪些?块级元素有哪些? 空(void)元素有那些?

定义:CSS 规范规定,每个元素都有 display 属性,确定该元素的类型,每个元素都有默认的 display 值,如 div 的 display 默认值为“block”,则为“块级”元素;span 默认 display 属性值为“inline”,是“行内”元素。

  • 行内元素有:a b span img input select strong(强调的语气)
  • 块级元素有:div ul ol li dl dt dd h1 h2 h3 h4…p
  • 空元素:
    • 常见: br hr img input link meta
    • 不常见: area base col command embed keygen param source track wbr

不同浏览器(版本)、HTML4(5)、CSS2 等实际略有差异 参考: http://stackoverflow.com/questions/6867254/browsers-default-css-for-html-elements

哪些元素可以自闭合?

  • 表单元素 input
  • img
  • br, hr
  • meta, link

HTML和DOM的关系

  • HTML只是一个字符串
  • DOM由HTML解析而来
  • JS可以维护DOM

form 作用

  • 直接提交表单
  • 使用submit / reset按钮
  • 便于浏览器保存表单
  • 第三方库可以整体取值
  • 第三方库可以进行表单验证

简述一下你对 HTML 语义化的理解?

  • 用正确的标签做正确的事情。
  • html 语义化让页面的内容结构化,结构更清晰,便于对浏览器、搜索引擎解析;
  • 即使在没有样式 CSS 情况下也以一种文档格式显示,并且是容易阅读的;
  • 搜索引擎的爬虫也依赖于 HTML 标记来确定上下文和各个关键字的权重,利于 SEO;
  • 使阅读源代码的人对网站更容易将网站分块,便于阅读维护理解。

介绍一下你对浏览器内核的理解?

主要分成两部分:渲染引擎(layout engineer 或 Rendering Engine)和 JS 引擎。

渲染引擎:负责取得网页的内容(HTML、XML、图像等等)、整理讯息(例如加入 CSS 等),以及计算网页的显示方式,然后渲染到用户的屏幕上。

JS 引擎则:解析和执行 javascript 来实现逻辑和控制 DOM 进行交互。

最开始渲染引擎和 JS 引擎并没有区分的很明确,后来 JS 引擎越来越独立,内核就倾向于只指渲染引擎。

html 中 title 属性和 alt 属性的区别?

<img src="#" alt="alt信息" />

当图片不输出信息的时候,会显示 alt 信息 鼠标放上去没有信息,当图片正常读取,不会出现 alt 信息。

<img src="#" alt="alt信息" title="title信息" />

  • 当图片不输出信息的时候,会显示 alt 信息 鼠标放上去会出现 title 信息;
  • 当图片正常输出的时候,不会出现 alt 信息,鼠标放上去会出现 title 信息。
  • 除了纯装饰图片外都必须设置有意义的值,搜索引擎会分析。

另外还有一些关于 title 属性的知识:

  • title 属性可以用在除了 base,basefont,head,html,meta,param,script 和 title 之外的所有标签。
  • title 属性的功能是提示。额外的说明信息和非本质的信息请使用 title 属性。title 属性值可以比 alt 属性值设置的更长。
  • title 属性有一个很好的用途,即为链接添加描述性文字,特别是当连接本身并不是十分清楚的表达了链接的目的。

为什么我们要弃用table标签?

table的缺点在于服务器把代码加载到本地服务器的过程中,本来是加载一行执行一行,但是table标签是里面的东西全都下载完之后才会显示出来,那么如果图片很多的话就会导致网页一直加载不出来,除非所有的图片和内容都加载完。如果要等到所有的图片全都加载完之后才显示出来的话那也太慢了,所以table标签现在我们基本放弃使用了。

head子元素大概分为三类,分别是:

  • 描述网页基本信息的
  • 指向渲染网页需要其他文件链接的
  • 各大厂商根据自己需要定制的

网页基本信息

一个网页,首先得有个标题,就跟人有名字一样。除此之外,还可以根据实际需要补充一些基本信息。

  • 文档标题(浏览器标签中显示的文本):<title>深入了解 head 元素</title>
  • 编码格式: 如果你的页面出现乱码,那一般就是编码格式不对
  • 视窗设置:
  • 搜索引擎优化相关内容:
  • IE浏览器版本渲染设置:

其他文件链接

  • CSS 文件:
  • JavaScript 文件:<script src=“script.js"></script>

但是为了让页面的样子更早的让用户看到,一般把JS文件放到body的底部

厂商定制

同样分享页面到QQ的聊天窗口,有些页面直接就是一个链接,但是有些页面有标题,图片,还有文字介绍。为什么区别这么明显呢?其实就是看有没有设置下面这三个内容

<meta itemprop="name" content="这是分享的标题"/>
<meta itemprop="image" content="http://imgcache.qq.com/qqshow/ac/v4/global/logo.png" />
<meta name="description" itemprop="description" content="这是要分享的内容" />

移动端项目需要注意的4个问题

meta中设置viewport

阻止用户手滑放大或缩小页面,需要在 index.html中添加meta元素,设置viewport。

<meta name="viewport" content="width=device-width,initial-scale=1.0,minimum-scale=1.0,maximum-scale=1.0,user-scalable=no">

CSS样式统一问题

我们需要重置页面样式,因为在不同的手机浏览器上,默认的css样式不是统一的。 解决方法:使用reset.css重置所有元素的默认样式

一像素边框问题

有的手机分辨率比较高,是2倍屏或3倍屏,手机上的浏览器就会把CSS中的1像素值展示为2个或3个物理宽度

解决方法: 添加一个border.css库,将利用scroll缩放的原理将边框重置。当我们需要使用一像素边框时只需要在标签上添加对应类名,如设置底部一像素边框就在标签上加入”border-bottom”的class名

300毫秒点击延迟问题

在移动端开发中,某些机型上使用click事件会延迟300ms才执行,这样影响了用户体验。 解决方法: 引入fastclick.js。

嵌套

  • 块级一般不能嵌套块级(但div可以嵌套p)
  • a可以包含div

html问题

  • doctype的意义是什么
    • 让浏览器以标准模式渲染
    • 让浏览器知道元素的合法性
  • html xhtml h5的关系
    • html属于sgml
    • xhtml属于xml,是html进行xml严格化的结果
    • h5是一个独立的规范,比hxtml宽松
  • H5有什么变化
    • 新的语义化元素section article header footer aside
    • 表单增强
    • 新的API
  • em和i有什么区别
    • 都是斜体,em是语义化标签,i是纯样式
  • 语义化的意义
    • 维护的开发者容易理解
    • 机器容易理解结构
    • 有助于seo
  • 哪些标签可以自闭和(不能嵌套其他标签)
    • input
    • img
    • br(换行) hr(水平线)
    • meta link

es6中的async&await异步调用方法

Posted on 2019-09-25 | In 前端 , javascript

基本用法

async函数

  • async定义的函数返回一个Promise对象,可以使用then方法添加回调函数。

      async function timeout() {
          return 'hello world'
      }
      console.log(timeout());
      console.log('虽然在后面,但是我先执行');
    

  • 它和promise一样,有异步回掉功能

      async function timeout() {
          return 'hello world'
      }
      timeout().then(result => {
          console.log(result);
      })
      console.log('虽然在后面,但是我先执行');
    

  • async原理:如果async成功返回一个promise对象,实际会调用Promise.resolve()返回,否则会调用Promise.reject()

      async function timeout(flag) {
          if (flag) {
              return 'hello world'
          } else {
              throw 'my god, failure'
          }
      }
      console.log(timeout(true))  // 调用Promise.resolve() 返回promise 对象。
      console.log(timeout(false)); // 调用Promise.reject() 返回promise 对象。
    

await

当函数执行时,一旦遇到await(后面定义的也是一个promise对象)就会先返回,等异步操作完成,再执行后面的语句。

await只能出现在async函数内部,等待async函数返回或执行promise,

// 2s 之后返回双倍的值
function doubleAfter2seconds(num) {
    return new Promise((resolve, reject) => {
        setTimeout(() => {
            resolve(2 * num)
        }, 2000);
    } )
}

async function testResult() {
    let result = await doubleAfter2seconds(30);
    console.log(result);
}

testResult(); //2s后输出60

代码执行过程:

  1. 调用testResult()函数,遇到await,开始等待(后面的promise执行完毕)
  2. 执行await后的doubleAfter2seconds(30),返回promise开始执行,2s后执行完毕,值为60并返回
  3. await拿到60,赋值给result,等待结束,代码继续运行,执行console

这里如果计算多个值,可以像写同步代码那样,避免回掉地狱

async function testResult() {
    let first = await doubleAfter2seconds(30);
    let second = await doubleAfter2seconds(50);
    let third = await doubleAfter2seconds(30);
    console.log(first + second + third);
}

demo

  • 获取股票报价的函数(可以用.then处理async函数)
async function getStockPriceByName(name) {
  const symbol = await getStockSymbol(name);
  const stockPrice = await getStockPrice(symbol);
  return stockPrice;
}

getStockPriceByName('goog').then(function (result) {
  console.log(result);
});
  • 在api中,把结果return 出去
export async function getRetailUnitPrice () {
const reqBody = await get('/race/spot/racespot/enter/dayahead')
return reqBody
}

注意点

  • async函数返回的promise对象,必须等到内部所有await命令后面的对象执行完,才会执行then
  • 当async返回一个常量,返回Promise.resolve(常量)自动构建promise返回值
  • 当async函数没有返回值的时候,返回Promise.resolve(undefiend)自动构建promise返回值
async function getTitle(url) {
  let response = await fetch(url);
  let html = await response.text();
  return html.match(/<title>([\s\S]+)<\/title>/i)[1];
}
getTitle('https://tc39.github.io/ecma262/').then(console.log)
// "ECMAScript 2017 Language Specification"

与promise相比

优点:处理.then链,不必把回掉嵌套在.then中,只要await即可

function sing() {
        return new Promise(function(resolve, reject) {
            setTimeout(function() {
                resolve(`来一首好听的歌吧~~~`);
            }, 1000);
        });
    }
    async function demo() {
        try {
            const v = await say(); 
            const s = await sing(); 
            console.log(v); // 输出:hello, joel。今年我 26 岁
            console.log(s) // 来一首好听的歌吧~~~
        } catch (e) {
            console.log(e)
        }
    }
    demo();

如果使用原来的Promise 就是把回调放在then()中。

浅谈Javascript的垃圾回收机制与内存泄漏问题

Posted on 2019-09-25 | In 前端 , javascript

javascript的垃圾回收机制

Javascript浏览器具有自动垃圾回收机制
最常用的方式是标记清除(mark-and-sweep)

当申明一个变量时,就将这个变量标记为“进入环境”。从逻辑上来讲,永远都不能释放进入环境的变量。当变量离开环境时,标记为“离开环境”

js定期进行垃圾回收(非实时),销毁带“离开环境”标记的变量,回收内存

function test(){
var a = 10 ;       // 被标记 ,进入环境 
var b = 20 ;       // 被标记 ,进入环境
}
test();            // 执行完毕 之后 a、b又被标离开环境,被回收

内存泄漏

内存泄漏是指一块被分配的内存即不能使用也不能回收

浏览器会使用自动垃圾回收机制,但是也会产生一些内存泄漏问题

1. 意外的全局变量

function foo(arg) {
    bar = "this is a hidden global variable";
}

bar没被申明,会变成一个全局变量,在页面关闭之前不会被释放

2. 被遗忘的计时器或callback函数

var someResource = getData();
setInterval(function() {
    var node = document.getElementById('Node');
    if(node) {
        // 处理 node 和 someResource
        node.innerHTML = JSON.stringify(someResource));
    }
}, 1000);

这里如果node元素从dom中移除,该定时器还是会存在;同时因为回掉函数中用了someResource,定时器外面的someResource也不会被释放

3. 闭包

function bindEvent(){
  var obj=document.createElement('xxx')
  obj.onclick=function(){
    // Even if it is a empty function
  }
}

闭包可以维持函数内的局部变量,使得闭包内返回的函数可以调用返回外的局部变量,使其得不到释放,所以会形成内存泄漏

// 将事件处理函数定义在外面
function bindEvent() {
  var obj = document.createElement('xxx')
  obj.onclick = onclickHandler
}
// 或者在定义事件处理函数的外部函数中,删除对dom的引用
function bindEvent() {
  var obj = document.createElement('xxx')
  obj.onclick = function() {
    // Even if it is a empty function
  }
  obj = null
}

解决方法:将事件处理函数定义在外部,或者在定义事件处理函数的外部函数中,删除对dom的引用。

4. 没有清理的dom元素引用

var elements = {
    button: document.getElementById('button'),
    image: document.getElementById('image'),
    text: document.getElementById('text')
};

function removeButton() {
    document.body.removeChild(document.getElementById('button'));
    // 此时,仍旧存在一个全局的 #button 的引用
    // elements 字典。button 元素仍旧在内存中,不能被 GC 回收。
}

虽然我们用removeChild移除了button,但是还在elements对象里保存着#button的引用,换言之,DOM元素还在内存里面。

避免内存泄漏的方法

  • 减少不必要的全局变量,或者生命周期较长的对象,及时对无用的数据进行垃圾回收
  • 注意程序逻辑,避免“死循环”之类的
  • 避免创建过多的对象

总而言之需要遵循一条原则:不用了的东西要及时归还

内存泄漏查看方法

chrome中

  1. 打开开发者工具,选择 performance 面板
  2. 勾选 Memory和screenshots
  3. 点击左上角的录制按钮。
  4. 在页面上进行各种操作,模拟用户的使用情况。
  5. 一段时间后,点击对话框的 stop 按钮,面板上就会显示这段时间的内存占用情况。

如果内存占用基本平稳,接近水平,就说明不存在内存泄漏。

反之,就是内存泄漏了。

vue源码研读

Posted on 2019-09-24 | In 前端 , javascript , vue

不定时更新

computed原理

Vue的响应式系统

当把一个普通的js对象传给Vue实例的data时,Vue将遍历这个对象的所有属性,并使用Object.defineProperty把这些属性全部转换为getter/setter

目的:在data被访问和修改的时候通知变化

组成:

  • observe:遍历data中的属性,使用Object.defineProperty把它们转化为getter/setter,这一步被称为数据劫持
  • dep:每个属性都拥有自己的消息订阅器dep,用于存放所有订阅了该属性的观察者对象
  • watcher:观察者对象,通过dep实现对响应属性的监听,当监听到改变时,触发自己的回掉函数

computed监听的原理步骤

  1. 数据劫持:组件初始化,computed和data建立各自的响应系统,observe遍历data的属性,并使用Object.defineProperty把它们转化为getter/setter
  2. computed初始化:注册一个watcher观察者对象,实例化一个dep消息订阅器
  3. computed调用:
    • 触发getter
    • 调用watcher.depend()向自身的dep中添加所监听data属性的watcher
  4. 当data中某个被监听的数据发生变化时,出发setter,遍历dep,调用watcher.update()完成更新

双向绑定原理

model=>view:使用基本的事件监听即可实现

view=>model:原理的computed相似,也是通过数据劫持+观察者模式来实现

步骤:

    1. 数据劫持:使用Object.defineProperty()给data添加getter和setter属性,
    1. 创建一个消息订阅器类dep,存放订阅者,订阅者是收集的发生变化的数据
    1. 创建一个观察者类watcher,在初始化时把自己添加进dep,观察者是view需要修改的节点

浅谈原型、执行上下文和作用域

Posted on 2019-09-24 | In 前端 , javascript

原型

构造函数

一个普通函数,内部使用了this变量

实例

对构造函数使用new运算符,就能生成实例对象,并且this会绑定在实例上

原型链

一个实例对象,自身不存在的属性可以通过它的隐式原型proto向指向的原型对象找,若没有,则同理顺着该原型对象的proto到该原型对象的原型对象上找

原型(原型对象)

原型对象是每个函数的prototype属性指向的一个对象,可以理解为一个仓库,可以在上面定义其他属性,它自带一个constructor,指向回它的构造函数

  • 每创建一个函数,该函数就会自带一个prototype属性(显式原型),该属性是一个指针,指向该函数的原型对象。
  • 若这个函数是构造函数,则由它构建的实例会自带一个proto属性(隐式原型),该属性是一个指针,指向原型对象
  • 原型对象上有一个属性constructor,该属性也是一个指针,指向其关联的构造函数
  • 如果Person的原型Person.prototype对象变成了某一个类的实例Person{},这个实例又会指向一个新的原型对象Object.prototype


执行上下文

针对对象或者函数,可以理解为this的值

  • 分类:
    • 全局上下文:window为全局上下文
    • 函数(局部)上下文
  • 特点:
    • 动态的,函数调用的时候时创建,函数调用结束时释放

作用域

一块地盘,一个代码段所在的区域。

  • 分类:
    • 全局作用域
    • 函数作用域
    • 块级作用域
  • 作用:隔离变量,不同作用域下同名的变量名不会产生冲突
  • 特点:
    • 静态的,只要定义好了就一直存在,不会改变

作用域链

由多个具有从属关系的作用域形成的链,查找变量时沿着作用域链查找

  • 自由变量:当前作用域没有定义的变量,可以顺着作用域链到父级作用域中去找

Javascript的几种继承方法

Posted on 2019-09-23 | In 前端 , javascript

整理一下目前javascript的几种继承方式

1. 利用构造函数和call/apply

缺点:子类无法继承父类原型上的属性

function Parent() {
    this.name = 'parentName'
}
function Child() {
    Parent.call(this)
    this.age = 10
}

2. 利用原型链

缺点:如果改变一个实例的属性,其他的实例也会被改变,原因是公用一个原型

function Parent() {
    this.name = 'parentName'
}
function Child() {
    this.age = 10
}
Child.prototype = new Parent()

3. 组合继承

function Parent() {
    this.name = 'parentName'
}
function Child() {
    Parent.call(this)
    this.age = 10
}
Child.prototype = new Parent()

4. es6 class继承

class Point {
  constructor(x, y) {
    this.x = x;
    this.y = y;
  }
}

class ColorPoint extends Point {
  constructor(x, y, color) {
    super(x, y);
    this.color = color;
  }
}

let cp = new ColorPoint(25, 8, 'green');

深浅拷贝

Posted on 2019-09-23 | In 前端 , javascript

简单的概念:

  • 浅拷贝:将原对象/数组的引用赋值给新对象,新对象/数组只是一个引用
    • 改变新对象的时候,同时改变原对象
  • 深拷贝:创建一个新的对象/数组,将原对象/数组的各项属性的值拷贝过来
    • 改变新对象的时候,不改变原对象

只对第一层做拷贝:浅拷贝

对数组(基本类型数组)

  • 直接遍历

      let arr = [1,2,3,4]
      let newArray=[]
      遍历{
          newArray.push(item)
          }
    
  • slice() let newArray = arr.slice()

  • concat() let newArray = arr.concat()

对对象

  • 直接遍历
  • Object.assign()

      var obj = {name: 'ted', age:23}
      var copyObj = Object.assign({}, obj)
    
  • 扩展运算符…(数组同样适用) let copyObj = {...obj}

深拷贝:拷贝所有层级

  • JSON.parse(JSON.stringify(XXXX))

      let arr = [
          {number1: 1},
          {number2: 2},
          {number3: 3}
      ]
      let copyArr = JSON.parse(JSON.stringify(arr))
    
  • 递归

      function myCopy(obj) {
          let copyObj = obj.constructor === Array ? [] : {}
          for (let i in obj) {
              if (typeof obj[i] === 'object') {
                  copyObj[i] = myCopy(obj[i])
              } else {
                  copyObj[i] = obj[i]
              }
          }
      }
    

牛客网JavascriptV8输入格式

Posted on 2019-08-03 | In javascript

相比Leetcode,牛客和赛码网等网站对于Javascript真的太不友好了,光是输入就可以折腾半天。整理了一下牛客网上Javascript V8的输入

  1. 输入一行,空格隔开

     1 2
    
     while (line = readline()) {
         var lines = line.split(' ')
         var a = parseInt(lines[0])
         var b = parseInt(lines[1])
     }
     console.log(a, b)
    
    
  2. 多行,每行输入一个

     2
     1
     2
    
     var lines = []
     while (line = readline()) {
         lines.push(parseInt(line))
     }
    
     console.log(lines)
    
  3. 多行,第一行为参数,后面行为数组

     //第一行为参数m和n,接下里为数组
     2 3 //m, n
     1 2 3 4 
     11 22 33 44 
    
     var lines = readline().split(' ')
     var n = parseInt(lines[0])
     var m = parseInt(lines[1])
     var Arr1 = readline().split(' ')
     var Arr2 = readline().split(' ')
    
     console.log(n,m,Arr1,Arr2)
    
    
123
Ted Qin

Ted Qin

Output is the best input

22 posts
13 categories
12 tags
GitHub DouBan ZhiHu
© 2017 - 2019 Ted Qin