整合營銷服務商

          電腦端+手機端+微信端=數據同步管理

          免費咨詢熱線:

          JavaScript基礎:濃縮的都是精華,ES6常用

          JavaScript基礎:濃縮的都是精華,ES6常用語法總結

          let 和 const

          let 的作用域與 const 命令相同:只在聲明所在的塊級作用域內有效。且不存在變量提升 。

          1.1 let

          let 所聲明的變量,可以改變。

          let a=123
          a=456 // 正確,可以改變
          let b=[123]
          b=[456] // 正確,可以改變
          

          1.2 const

          const 聲明一個只讀的常量。一旦聲明,常量的值就不能改變。

          簡單類型的數據(數值、字符串、布爾值),不可以變動

          const a=123
          a=456 // 報錯,不可改變
          const b=[123]
          b=[456] // 報錯,不可以重新賦值,不可改變
          

          復合類型的數據(主要是對象和數組),可以這樣子變動

          const a=[123]
          a.push(456) // 成功
          const b={}
          b.name='demo' // 成功
          

          1.3 不存在變量提升

          {
           let a=10;
           var b=1;
          }
          a // ReferenceError: a is not defined.
          b // 1
          

          所以 for循環的計數器,就很合適使用 let 命令。

          let a=[];
          for (let i=0; i < 10; i++) {
           a[i]=function () {
           console.log(i);
           };
          }
          a[6](); // 6
          

          1.4 推薦

          對于 數值、字符串、布爾值 經常會變的,用 let 聲明。

          對象、數組和函數用 const 來聲明。

          // 如經常用到的導出 函數
          export const funA=function(){
           // ....
          }
          

          2 解構(Destructuring)

          2.1 數組

          一次性聲明多個變量:

          let [a, b, c]=[1, 2, 3];
          console.log(a) // 1
          console.log(b) // 2
          console.log(c) // 3
          

          結合擴展運算符:

          let [head, ...tail]=[1, 2, 3, 4];
          console.log(head) // 1
          console.log(tail) // [2, 3, 4]
          

          解構賦值允許指定默認值:

          let [foo=true]=[];
          foo // true
          let [x, y='b']=['a'];
          // x='a', y='b'
          

          2.2 對象

          解構不僅可以用于數組,還可以用于對象。

          let { a, b }={ a: "aaa", b: "bbb" };
          a // "aaa"
          b // "bbb"
          

          數組中,變量的取值由它 排列的位置 決定;而對象中,變量必須與 屬性 同名,才能取到正確的值。

          對象的解構也可以指定默認值。

          let {x=3}={};
          x // 3
          let {x, y=5}={x: 1};
          x // 1
          y // 5
          

          2.3 字符串

          字符串也可以解構賦值。這是因為此時,字符串被轉換成了一個類似數組的對象。

          const [a, b, c, d, e]='hello';
          a // "h"
          b // "e"
          c // "l"
          d // "l"
          e // "o"
          

          2.4 用途

          2.4.1交換變量的值

          let x=1;
          let y=2;
          [x, y]=[y, x];
          

          2.4.2從函數返回多個值

          // 返回一個數組
          function example() {
           let [a, b, c]=[1, 2, 3]
           return [a, b, c] 
          }
          let [a, b, c]=example();
          // 返回一個對象
          function example() {
           return {
           foo: 1,
           bar: 2
           };
          }
          let { foo, bar }=example();
          

          2.4.3函數參數的默認值

          function funA (a=1, b=2){
           return a + b;
          }
          funA(3) // 5 因為 a 是 3, b 是 2
          funA(3,3) // 6 因為 a 是 3, b 是 3
          

          2.4.4輸入模塊的指定方法

          加載模塊時,往往需要指定輸入哪些方法。解構賦值使得輸入語句非常清晰。

          const { SourceMapConsumer, SourceNode }=require("source-map");
          

          在 utils.js 中:

          export const function A (){
           console.log('A')
          }
          export const function B (){
           console.log('B')
          }
          export const function C (){
           console.log('C')
          }
          

          在 組件中引用時:

          import { A, B, C } from "./utils.js" 
          //調用
          A() // 輸出 A 
          

          3. 模板字符串(template string)

          模板字符串(template string)用反引號(`)標識。

          3.1 純字符串

          所有模板字符串的空格和換行,都是被保留的.

          console.log(`輸出值為 N, 
          換行`)
          // "輸出值為 N
          換行"
          

          3.2 字符串中加變量

          模板字符串中嵌入變量,需要將變量名寫在 ${ } 之中

          let x=1;
          let y=2;
          console.log(`輸出值為:${x}`) // "輸出值為:1"
          console.log(`輸出值為:${x + y}`) // "輸出值為:3"
          

          3.3 模板字符串之中還能調用函數。

          function fn() {
           return "Hello World";
          }
          console.log(`輸出值為:${fn()}`) // "輸出值為:Hello World"
          

          4. 字符串函數擴展

          • includes():返回布爾值,表示是否找到了參數字符串。
          • startsWith():返回布爾值,表示參數字符串是否在原字符串的頭部。
          • endsWith():返回布爾值,表示參數字符串是否在原字符串的尾部。
          let s='Hello world!';
          s.startsWith('Hello') // true
          s.endsWith('!') // true
          s.includes('o') // true
          

          這三個方法都支持第二個參數,表示開始搜索的位置。

          let s='Hello world!';
          s.startsWith('world', 6) // true
          s.endsWith('Hello', 5) // true
          s.includes('Hello', 6) // false
          

          5. 數值擴展

          5.1 指數運算符

          ES2016 新增了一個指數運算符(**)。

          2 ** 2 // 4
          2 ** 3 // 8
          

          這個運算符的一個特點是右結合,而不是常見的左結合。多個指數運算符連用時,是從最右邊開始計算的。


          // 相當于 2 ** (3 ** 2)
          2 ** 3 ** 2
          // 512
          

          上面代碼中,首先計算的是第二個指數運算符,而不是第一個。

          指數運算符可以與等號結合,形成一個新的賦值運算符(**=)。

          let a=1.5;
          a **=2;
          // 等同于 a=a * a;
          let b=4;
          b **=3;
          // 等同于 b=b * b * b;
          

          6. 函數的擴展

          除了在解構中說到的函數參數的默認值,還有不少經常會用到的方法。

          6. 1 rest 參數

          ES6 引入 rest 參數(形式為…變量名),用于獲取函數的多余參數,這樣就不需要使用 arguments 對象了。rest 參數搭配的變量是一個數組,該變量將多余的參數放入數組中。

          function add(...values) {
           let sum=0;
           for (let val of values) {
           sum +=val;
           }
           return sum;
          }
          add(2, 5, 3) // 10
          

          上面代碼的 add 函數是一個求和函數,利用 rest 參數,可以向該函數傳入任意數目的參數。

          注意,rest 參數之后不能再有其他參數(即只能是最后一個參數),否則會報錯。

          // 報錯
          function f(a, ...b, c) {
           // ...
          }
          

          6.2 箭頭函數

          ES6 允許使用“箭頭”(=>)定義函數。

          const f=v=> v;
          console.log('輸出值:', f(3)) // 輸出值: 3
          // 等同于
          const f=function (v) {
           return v;
          };
          

          如果箭頭函數不需要參數或需要多個參數,就使用一個圓括號代表參數部分。

          const f=()=>5
          // 等同于
          const f=function () { return 5 };
          
          
          const sum=(num1, num2)=> num1 + num2;
          // 等同于
          const sum=function(num1, num2) {
           return num1 + num2;
          };
          

          如果箭頭函數的代碼塊部分多于一條語句,就要使用大括號將它們括起來,并且使用 return 語句返回。

          const sum=(num1, num2)=> { return num1 + num2; }
          

          箭頭函數的一個用處是簡化回調函數。

          const square=n=> n * n;
          // 正常函數寫法
          [1,2,3].map(function (x) {
           return x * x;
          });
          // 箭頭函數寫法
          [1,2,3].map(x=> x * x);
          

          注意: 函數體內的 this 對象,就是定義時所在的對象,而不是使用時所在的對象。

          this 對象的指向是可變的,但是在箭頭函數中,它是固定的。

          function foo() {
           setTimeout(()=> {
           console.log('id:', this.id);
           }, 100);
          }
          let id=21;
          foo.call({ id: 42 });
          // id: 42
          

          上面代碼中,setTimeout 的參數是一個箭頭函數,這個箭頭函數的定義生效是在 foo 函數生成時,而它的真正執行要等到 100 毫秒后。如果是普通函數,執行時 this 應該指向全局對象window,這時應該輸出 21。但是,箭頭函數導致 this 總是指向函數定義生效時所在的對象(本例是{ id: 42}),所以輸出的是 42。

          7. 數組的擴展

          擴展運算符(spread)是三個點(…)。它好比 rest 參數的逆運算,將一個數組轉為用逗號分隔的參數序列。

          7.1 數組合并的新寫法。

          const arr1=['a', 'b'];
          const arr2=['c'];
          const arr3=['d', 'e'];
          // ES5 的合并數組
          arr1.concat(arr2, arr3);
          // [ 'a', 'b', 'c', 'd', 'e' ]
          // ES6 的合并數組
          [...arr1, ...arr2, ...arr3]
          // [ 'a', 'b', 'c', 'd', 'e' ]
          

          7.2 函數調用。

          function add(x, y) {
           return x + y;
          }
          const numbers=[4, 4];
          add(...numbers) // 8
          

          7.3 復制數組的簡便寫法。

          const a1=[1, 2];
          // 寫法一
          const a2=[...a1];
          a2[0]=2;
          a1 // [1, 2]
          
          // 寫法二
          const [...a2]=a1;
          a2[0]=2;
          a1 // [1, 2]
          

          寫法一更符合邏輯。

          上面的兩種寫法,a2 都是 a1 的克隆,且不會修改原來的數組。

          7.4 將字符串轉為真正的數組。

          [...'hello']
          // [ "h", "e", "l", "l", "o" ]
          

          7.5 數組實例的 entries(),keys() 和 values()

          用 for…of 循環進行遍歷,唯一的區別是 keys() 是對鍵名的遍歷、values() 是對的遍歷,entries() 是對鍵值對的遍歷。

          for (let index of ['a', 'b'].keys()) {
           console.log(index);
          }
          // 0
          // 1
          for (let elem of ['a', 'b'].values()) {
           console.log(elem);
          }
          // 'a'
          // 'b'
          for (let [index, elem] of ['a', 'b'].entries()) {
           console.log(index, elem);
          }
          // 0 "a"
          // 1 "b"
          

          7.6 includes()

          Array.prototype.includes 方法返回一個布爾值,表示某個數組是否包含給定的值,與字符串的 includes 方法類似。ES2016 引入了該方法。

          [1, 2, 3].includes(2) // true
          [1, 2, 3].includes(4) // false
          [1, 2, NaN].includes(NaN) // true
          

          該方法的第二個參數表示搜索的起始位置,默認為 0。如果第二個參數為負數,則表示倒數的位置,如果這時它大于數組長度(比如第二個參數為 -4,但數組長度為 3 ),則會重置為從 0 開始。

          [1, 2, 3].includes(3, 3); // false
          [1, 2, 3].includes(3, -1); // true
          

          8. 對象的擴展

          8.1 屬性和方法 的簡潔表示法

          let birth='2000/01/01';
          const Person={
           name: '張三',
           //等同于birth: birth
           birth,
           // 等同于hello: function ()...
           hello() { console.log('我的名字是', this.name); }
          };
          

          8.2 Object.assign()

          Object.assign方法用于對象的合并,將源對象(source)的所有可枚舉屬性,復制到目標對象(target)。

          const target={ a: 1 };
          const source1={ b: 2 };
          const source2={ c: 3 };
          Object.assign(target, source1, source2);
          target // {a:1, b:2, c:3}
          

          Object.assign方法的第一個參數是目標對象,后面的參數都是源對象。

          注意,如果目標對象與源對象有同名屬性,或多個源對象有同名屬性,則后面的屬性會覆蓋前面的屬性。

          const target={ a: 1, b: 1 };
          const source1={ b: 2, c: 2 };
          const source2={ c: 3 };
          Object.assign(target, source1, source2);
          target // {a:1, b:2, c:3}
          

          Object.assign 方法實行的是淺拷貝,而不是深拷貝。

          const obj1={a: {b: 1}};
          const obj2=Object.assign({}, obj1);
          obj1.a.b=2; // 修改b
          obj2.a.b // 2, 也改變了 
          

          上面代碼中,源對象 obj1 的 a 屬性的值是一個對象,Object.assign 拷貝得到的是這個對象的引用。這個對象的任何變化,都會反映到目標對象上面。

          9. Set

          ES6 提供了新的數據結構 Set。它類似于數組,但是成員的值都是唯一的,沒有重復的值。

          Set 本身是一個構造函數,用來生成 Set 數據結構。

          // 基本用法
          const s=new Set();
          [2, 3, 5, 4, 5, 2, 2].forEach(x=> s.add(x));
          for (let i of s) {
           console.log(i);
          }
          // 2 3 5 4
          // 去除數組的重復成員
          const array=[1, 1, 2, 3, 4, 4]
          [...new Set(array)]
          // [1, 2, 3, 4]
          

          10. Promise 對象

          Promise 是異步編程的一種解決方案。

          Promise 對象代表一個異步操作,有三種狀態:pending(進行中)、fulfilled(已成功)和rejected(已失敗)。

          Promise 對象的狀態改變,只有兩種可能:從 pending 變為 fulfilled 和從 pending 變為

          rejected。只要這兩種情況發生,狀態就凝固了,不會再變了,會一直保持這個結果,這時就稱為 resolved(已定型)

          const someAsyncThing=function(flag) {
           return new Promise(function(resolve, reject) {
           if(flag){
           resolve('ok');
           }else{
           reject('error')
           }
           });
          };
          someAsyncThing(true).then((data)=> {
           console.log('data:',data); // 輸出 'ok'
          }).catch((error)=>{
           console.log('error:', error); // 不執行
          })
          someAsyncThing(false).then((data)=> {
           console.log('data:',data); // 不執行
          }).catch((error)=>{
           console.log('error:', error); // 輸出 'error'
          })
          

          上面代碼中,someAsyncThing 函數成功返回 ‘OK’, 失敗返回 ‘error’, 只有失敗時才會被 catch 捕捉到。

          最簡單實現:

          // 發起異步請求
           fetch('/api/todos')
           .then(res=> res.json())
           .then(data=> ({ data }))
           .catch(err=> ({ err }));
          

          來看一道有意思的面試題:

          setTimeout(function() {
           console.log(1)
          }, 0);
          new Promise(function executor(resolve) {
           console.log(2);
           for( var i=0 ; i<10000 ; i++ ) {
           i==9999 && resolve();
           }
           console.log(3);
          }).then(function() {
           console.log(4);
          });
          console.log(5);
          

          這道題應該考察 JavaScript 的運行機制的。

          首先先碰到一個 setTimeout,于是會先設置一個定時,在定時結束后將傳遞這個函數放到任務隊列里面,因此開始肯定不會輸出 1 。

          然后是一個 Promise,里面的函數是直接執行的,因此應該直接輸出 2 3 。

          然后,Promise 的 then 應當會放到當前 tick 的最后,但是還是在當前 tick 中。

          因此,應當先輸出 5,然后再輸出 4 。

          最后在到下一個 tick,就是 1 。

          答案:“2 3 5 4 1”

          11. async 函數

          ES2017 標準引入了 async 函數,使得異步操作變得更加方便。

          async 函數的使用方式,直接在普通函數前面加上 async,表示這是一個異步函數,在要異步執行的語句前面加上 await,表示后面的表達式需要等待。async 是 Generator 的語法糖

          1. async 函數內部 return 語句返回的值,會成為 then 方法回調函數的參數。

          async function f() {
           return 'hello world';
          }
          f().then(v=> console.log(v))
          // "hello world"
          

          上面代碼中,函數 f 內部 return 命令返回的值,會被 then 方法回調函數接收到。

          2. async 函數內部拋出錯誤,會導致返回的 Promise 對象變為 reject 狀態。拋出的錯誤對象會被 catch 方法回調函數接收到。

          async function f() {
           throw new Error('出錯了');
          }
          f().then(
           result=> console.log(result),
           error=> console.log(error)
          )
          // Error: 出錯了
          


          3. async 函數返回的 Promise 對象,必須等到內部所有 await 命令后面的 Promise 對象執行完,才會發生狀態改變,除非遇到 return 語句或者拋出錯誤。也就是說,只有 async 函數內部的異步操作執行完,才會執行 then 方法指定的回調函數。

          下面是一個例子:

          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(function(res) {
           console.log(res)
           })
          // "ECMAScript 2017 Language Specification"
          

          上面代碼中,函數 getTitle 內部有三個操作:抓取網頁、取出文本、匹配頁面標題。只有這三個操作全部完成,才會執行 then 方法里面的 console.log。

          4. 在 vue 中,我們可能要先獲取 token ,之后再用 token 來請求用戶數據什么的,可以這樣子用:

          methods:{
           getToken() {
           return new Promise((resolve, reject)=> {
           this.$http.post('/token')
           .then(res=> {
           if (res.data.code===200) {
           resolve(res.data.data)
           } else {
           reject()
           }
           })
           .catch(error=> {
           console.error(error);
           });
           })
           },
           getUserInfo(token) {
           return new Promise((resolve, reject)=> {
           this.$http.post('/userInfo',{
           token: token
           })
           .then(res=> {
           if (res.data.code===200) {
           resolve(res.data.data)
           } else {
           reject()
           }
           })
           .catch(error=> {
           console.error(error);
           });
           })
           },
           async initData() {
           let token=await this.getToken()
           this.userInfo=this.getUserInfo(token)
           },
          }
          

          12. import 和 export

          import 導入模塊、export 導出模塊

          // example2.js // 導出默認, 有且只有一個默認
          export default const example2={
           name : 'my name',
           age : 'my age',
           getName=function(){ return 'my name' }
          }
          //全部導入 // 名字可以修改
          import people from './example2.js'
          -------------------我是一條華麗的分界線---------------------------
          // example1.js // 部分導出
          export let name='my name'
          export let age='my age'
          export let getName=function(){ return 'my name'}
          // 導入部分 // 名字必須和 定義的名字一樣。
          import {name, age} from './example1.js'
          //有一種特殊情況,即允許你將整個模塊當作單一對象進行導入
          //該模塊的所有導出都會作為對象的屬性存在
          import * as example from "./example1.js"
          console.log(example.name)
          console.log(example.age)
          console.log(example.getName())
          -------------------我是一條華麗的分界線---------------------------
          // example3.js // 有導出默認, 有且只有一個默認,// 又有部分導出
          export default const example3={
           birthday : '2018 09 20'
          }
          export let name='my name'
          export let age='my age'
          export let getName=function(){ return 'my name'}
          // 導入默認與部分
          import example3, {name, age} from './example1.js'
          

          總結:

          1.當用 export default people 導出時,就用 import people 導入(不帶大括號)

          2.一個文件里,有且只能有一個 export default。但可以有多個 export。

          3.當用 export name 時,就用 import { name }導入(記得帶上大括號

          4.當一個文件里,既有一個 export default people, 又有多個 export name 或者 export age 時,導入就用 import people, { name, age }

          5.當一個文件里出現 n 多個 export 導出很多模塊,導入時除了一個一個導入,也可以用 import * as example

          13. Class

          對于 Class ,小汪用在 react 中較多。

          13.1基本用法:

          class Point {
           constructor(x, y) {
           this.x=x;
           this.y=y;
           }
           sum() {
           console.log(this.x + this.y)
           }
          }
          
          
          let f=new Point(10, 20);
          f.sum() // 30
          

          13.2 繼承

          class ColorPoint extends Point {
           constructor(x, y, color) {
           super(x, y); // 調用父類的constructor(x, y)
           this.color=color;
           }
           toString() {
           return this.color + ' ' + super.toString(); // 調用父類的toString()
           }
          }
          
          let g=new ColorPoint(10, 11, 'red')
          

          上面代碼中,constructor 方法和 toString 方法之中,都出現了super關鍵字,它在這里表示父類的構造函數,用來新建父類的 this 對象。

          子類必須在 constructor 方法中調用 super 方法,否則新建實例時會報錯。這是因為子類自己的 this 對象,必須先通過父類的構造函數完成塑造,得到與父類同樣的實例屬性和方法,然后再對其進行加工,加上子類自己的實例屬性和方法。如果不調用 super 方法,子類就得不到 this 對象。

          class Point { /* ... */ }
          class ColorPoint extends Point {
           constructor() {
           }
          }
          let cp=new ColorPoint(); // ReferenceError
          

          上面代碼中,ColorPoint 繼承了父類 Point,但是它的構造函數沒有調用 super 方法,導致新建實例時報錯。

          參考:https://mp.weixin.qq.com/s/TCpXWORIqZk34gBVIid3vA

          明 發自 凹非寺

          量子位 報道 | 公眾號 QbitAI

          鏡子里的人,是人嗎?對于計算機視覺系統來說:是。

          大部分系統也不考慮鏡子因素,它們很難分清楚鏡中人。

          鏡子作為日常生活中非常重要的物體無處不在,不僅能夠反射光線,能呈現出周圍物體或者場景的鏡像。

          這就導致計算機視覺系統或者機器人一旦遇到有鏡子的場景,性能就會大幅下降,可以說是遇到了克星。



          怎么辦?來自大連理工、鵬城實驗室和香港城市大學的研究團隊提出了一個方法。

          他們發表了一篇名為Where Is My Mirror?的論文,已經被ICCV2019收錄。

          在這篇論文中,他們構建了一個大規模的鏡像數據集,并提出了一種從輸入圖像中分割鏡子的新方法。

          不僅能夠準確識別并分割出場景中的鏡子,還能夠消除由于鏡子反射所導致的對于場景的錯誤理解,并幫助一些計算機視覺任務(例如深度估計和目標檢測)提升魯棒性。

          他們說,這是首個解決鏡子分割的方法,經過大量的實驗表明,性能表現比最先進的檢測和分割方法都要好。

          未來,他們的目標是檢測出現在城市街道上的鏡子,這對戶外執行的視覺任務——自動駕駛和無人機導航——都有助益。

          Where Is My Mirror?

          對于計算機視覺系統來說,鏡子反射的內容與鏡子外部的內容(即周圍環境)非常相似,它們很難區分出來,更不用說從一個背景中自動分割鏡子了。

          從這點來看,系統是比不上人的。大多數人類,通常能很好地察覺鏡子的存在。

          向人類學習,成了這篇論文的突破點。研究人員觀察到,人們識別鏡像中的內容,通常會從邊界入手,觀察其不連續性。

          因此,這個問題的一個直接的解決方案,是應用低層次的特征,比如顏色和紋理變化,來檢測鏡子邊界。

          但如果一個鏡子前面有物體遮擋,這個方法就不管用了,比如這樣的情況:

          單靠檢測鏡子邊界很難將對象的反射與對象本身分離開,也需要語義,即上下文對比信息來進行進行分割。

          基于此,研究人員從兩個方面來解決鏡子分割問題:數據和神經網絡。

          自建數據集

          因為這一領域之前并未有太多人關注,自然也沒有可用數據集。

          于是他們就自己動手,創建數據集MSD,包含4018對包含鏡子和相應的手動注釋的蒙版圖像。

          其中,有3677張來自室內場景,341張來自室外場景,基本上涵蓋了生活中常見的出現鏡子的場景:化妝臺、裝飾品、浴室、路面鏡子、臥室、辦公室、花園、街道和停車場。



          最后有3063張圖像用于訓練,955張圖像用于測試。

          怎么找鏡子?

          論文中提出的鏡子分割網絡MirrorNet的架構,以單幅圖像為輸入,通過特征提取網絡(FEN)提取多層特征。

          然后,將最深層的、語義豐富的特征輸入到所提出的上下文對比特征提取(CCFE)模塊中,學習上下文對比特征,通過檢測對比出現的分界線,用初始的粗糙的鏡子分割圖來定位鏡子。

          這一鏡子分割圖作為注意力圖,用于抑制非鏡子區域上一層 FEN 特征的特征噪聲,使上一層能夠集中學習候選鏡子區域的鑒別特征。

          通過這種方式,MirrorNet逐步利用上下文對比信息以從粗到精的方式細化鏡子區域。最后,對最粗的網絡輸出進行上行采樣,得到原始的圖像分辨率作為輸出。

          鏡子在這里

          自建數據集提出的MirrorNet效果怎么樣?

          研究人員采用了相關領域中常用的5個度量(即語義分割、顯著目標檢測和陰影檢測) ,對鏡子分割性能進行定量評估。

          比較對象也都是目標分割領域先進的模型,比如Mask RCNN、R3Net等等。

          從這些指標來看,MirrorNet表現都是最佳。

          一次跨越南北的合作

          這一論文來自大連理工、鵬城實驗室和香港城市大學,是一次跨越南北的合作。

          第一作者有兩位,分別是楊鑫和梅海洋。

          楊鑫,大連理工大學計算機學院副教授、博士生導師、學校學科辦建設副主任。本科畢業于吉林大學計算機學院,于浙江大學-美國加州大學戴維斯分校計算機學院進行博士生聯合培養,獲工學博士學位,香港城市大學博士后。

          梅海洋,大連理工大學在讀博士生,本科也畢業于大連理工大學。研究興趣為圖像處理、計算機視覺和深度學習。

          梅海洋介紹稱,他們團隊圍繞鏡子,用了一年半的時間進行課題調研、確定問題、制作數據集、設計模型、優化模型,研究成果最終被ICCV2019接收。

          后續將圍繞城市間建筑表面的鏡子來展開研究,以此來進一步擴展問題,緩解各種場景下鏡子對于其他視覺任務的影響,提高應用價值。

          最后,梅海洋說,關于這一研究的數據集和代碼將會開源,希望廣大的研究者們能夠一起加入到這個問題的研究中~

          如果你對這一研究感興趣,請收好傳送門:

          https://mhaiyang.github.io/ICCV2019_MirrorNet/index.html

          — 完 —

          誠摯招聘

          量子位正在招募編輯/記者,工作地點在北京中關村。期待有才氣、有熱情的同學加入我們!相關細節,請在量子位公眾號(QbitAI)對話界面,回復“招聘”兩個字。

          量子位 QbitAI · 頭條號簽約作者

          ?'?' ? 追蹤AI技術和產品新動態

          rid布局概念

          CSS Gird已經被W3C納入到css3的一個布局模塊中,被稱為CSS Grid Layout Module,一般習慣稱為網格布局

          網格布局可以將應用程序分割成不同的空間,定義它們的大小、位置和層級

          簡單來說,網格布局就像表格一樣可以讓元素按對齊排列,不同的是,網格布局沒有內容結構,比如一個網格布局的子元素可以定位自己的位置,可以是實現類似定位的效果。

          兼容性:

          測試地址:https://www.caniuse.com/

          可以看到幾大瀏覽器都已經支持了Grid布局,接下來我們來一步步的來玩轉Grid布局

          grid vs flex

          我們知道flex和grid都是css3新的布局方式,如果瀏覽器都支持兩種布局,你會選擇那種呢?當我們了解兩者以后就能做出正確的選擇了。

          flex布局是一維布局,grid布局是二維布局。

          網格容器和網格項

          我們知道給一個元素設置了display:flex就指定了flex彈性布局,實現grid布局一樣簡單,給元素設置display:grid就可以了。

          container 就是一個網格容器,里面的item就是網格項

          網格術語

          網格線 grid lines

          網格線組成了網格,是網格水平和垂直的分界線。

          網格軌道 grid track

          就是兩條網格線之間的空間,可以理解成表格里面的行或者列,網格里面為grid-rowgrid-column,網格軌道可以設置大小,來控制高度或者寬度。

          上圖grid-column2和grid-column3之間的區域就是一個網格軌道

          網格單元格 grid cell

          就是四條網格線之間的空間,是最小的單位。

          網格區域 area

          也是四條網格線組成的空間,可能包含一個或者多個單元格。

          實現一個grid布局

          了解網格個相關概念,接下來我們來創建一個簡單的grid布局。

          上面我們說網格軌道的時候說了可以給網格軌道設置大小,可以控制高度或者寬度。

          我們來分析下上面的css

          1、給grid元素設置了 display: grid來聲明使用grid布局

          2、使用grid-template-columns來設置列寬,分別為 300px 200px 150px

          3、使用grid-template-rows來設置行高,分別為150px 100px

          以上代碼我們是實現了一個兩行三列的grid布局,此時瀏覽器顯示如下

          進階

          單位 fr

          grid-template-columns和grid-template-rows不只是可以設置具體的數值,還可以設置百分比、rem一類的,還可以設置一個新單位 fr,它是來干什么的呢?

          我們先把上面demo里面的css文件改下

          展示如下:

          以上實現了彈性布局,fr用來實現彈性布局, 我們這里使用里repeat(2, 1fr),表示重復兩次,都是1fr。

          grid-gap 網格項間隙

          css修改如下

          展示如下

          網格布局屬性 grid-placement-properties

          網格布局屬性主要用來放置容器內的網格項目,就是單一項目的位置。網格布局屬性主要有以下四個屬性:

           1、grid-column-start 設置垂直方向的開始位置網格線
           2、grid-column-end 設置垂直方向的結束位置網格線
           3、grid-row-start 設置水平方向的開始位置網格線
           4、grid-row-end 設置水平方向的結束位置網格線
          

          以上的簡寫方式

           1、grid-column: grid-column-start / grid-column-end
           2、grid-row: grid-row-start / grid-row-end
          

          終極簡寫

          grid-area: grid-row-start / grid-column-start / grid-row-end / grid-colun-end
          

          是不是有點蒙,我們可以大概看下,先來看deme

          還是熟悉的html布局

          先來看看我們的成果

          顯示網格線的圖片

          我們來分析下css

          1、grid元素聲明grid布局,grid-template-columns和grid-template-rows來創建一個兩行三列的網格,但是渲染的結果卻是三行三列,為什么?我們先接著往下分析

          2、css文件中單獨設置item-2網格項的位置,

           grid-column-start:2 垂直線開始位置為2
           grid-column-end:4垂直線結束位置為4
           grid-row-start:1 水平線開始位置為1
           grid-row-end:2 水平線結束位置為2
          

          3、通過單獨設置item-2的位置,把本身要在第一行的item-3給擠下來了,然后 3、4、5按照300 200 150 排列

          4、這時候兩件三列排列完了,但是還有個元素,此時剩下的元素就會獨自占一行的位置,它的大小一樣會按照網格容器定義的行高列寬來渲染

          5、最后我們給item-6來設置了終極簡寫方式,

          終極簡寫:行開始 / 列開始 / 行結束 / 列結束,然后我們把位置對應上

           grid-area:3 / 1 / 4 / 4
          

          通過設置網格項樣式屬性,我們可以就實現很多復雜的布局結構了。

          幾種布局

          最后我們結合上面所學到的實現幾個常見布局

          1、左右固定,中間自適應

          設置網格容器的 grid-template-columns: 100px 1fr 100px或者grid-template-columns: 100px auto 100px就可以實現,再簡單不過了

          效果:

          2、九宮格

          使用grid-gap設置網格項間距 使用fr來平分

          顯示如下

          3、圣杯、雙飛翼

          使用grid-area設置header元素和footer元素位置,結合grid-template-columns和grid-template-rows實現布局

          效果圖:


          主站蜘蛛池模板: 国产一区高清视频| 中文字幕精品亚洲无线码一区| 亚洲一区二区三区香蕉| 人妻在线无码一区二区三区| 糖心vlog精品一区二区三区| 天堂Aⅴ无码一区二区三区| 精品无码人妻一区二区三区18| 人妻少妇精品视频一区二区三区| 久久久久成人精品一区二区| 国产凹凸在线一区二区| 国产手机精品一区二区| 国产一区二区三区在线观看免费| 亚洲av午夜精品一区二区三区| 在线观看免费视频一区| 日韩精品一区二区三区在线观看l| 国产精品一区二区AV麻豆| 日韩一区二区三区无码影院| 日本精品高清一区二区2021| 秋霞无码一区二区| 国产福利电影一区二区三区久久老子无码午夜伦不 | 亚洲av色香蕉一区二区三区蜜桃| 日本一区二区三区在线网| 国产91大片精品一区在线观看| 亚洲成人一区二区| 日本精品视频一区二区| 精品福利视频一区二区三区| 国产一区二区免费| 一区二区3区免费视频| 亚洲AV无码一区二区三区牲色| 国精无码欧精品亚洲一区| 精品视频在线观看你懂的一区| 免费一本色道久久一区| 精品国产日韩一区三区| 免费无码毛片一区二区APP| 国产一区二区三区在线看| 久久精品人妻一区二区三区| 国产精品香蕉在线一区| 国精产品一区一区三区| 国产一区二区精品久久岳| 亚洲av一综合av一区| 精品无码人妻一区二区三区不卡|