cocoscreator面試題集錦

公眾號 亮亮同學(xué)TT
cocoscreator 版本:2.4.x
技術(shù)交流: 117871561

js/ts 遵循es6標準

第一篇

Javascript部分

  • Javascript有哪些數(shù)據(jù)類型? 舉例兩個最常見的內(nèi)置對象數(shù)據(jù)類型。
    【答案】Number, String, Boolean, Null, Undefined, Object
    常見內(nèi)置對象類型:數(shù)組,函數(shù)

  • 如下一段代碼:

var a = [];
a[100] = 1;
console.log(a.length);
console.log(a[0]);
a[200] = undefined;
console.log(a.length);
console.lolg(a['100']);

請問四條log語句分別輸出什么?
【答案】分別輸出 101,undefined, 201,1

  • 如下代碼 打印結(jié)果分別是什么?
function counter_1() {
    let count = 0;
    function inc(count) {
      return count++;
    }
    return () => inc(count);
  }
 let inc = this.counter_1()
    console.log(inc());
    console.log(inc());
    console.log(inc());

答案是 0,0,0

解析:

雖然是閉包 ,但是 變量不同, 每次調(diào)用閉包 都會傳參 ,此時 參數(shù)是number類型 number類型屬于基礎(chǔ)類型 ,也就是說是值的傳遞 , 當進行值傳遞時 在棧內(nèi)存中 實際上是 新開辟了一份新的內(nèi)存,所以每次傳進來的參數(shù)都是全新的 參數(shù)是 0 ,也就是count一直是0,里面做了count++操作 ,所以 得到的是 +1之前的 數(shù)值 仍是0 最后每次 調(diào)用閉包都會是 0

技巧:變量就近原則

  • 如下代碼 打印結(jié)果分別是什么?
function counter_2() {
    let count = 0;
    function inc() {
      return count++;
    }
    return inc;
  }
 let inc = this.counter_2()
    console.log(inc());
    console.log(inc());
    console.log(inc());

答案:

0,1,2

解析:

利用了閉包的特性,在函數(shù)運行結(jié)束后count變量不會被釋放,此時 變量的內(nèi)存情況是 存放在堆里面,因為是count++所以 是 先用后加+ 1 結(jié)果是 0,1,2

  • 一個數(shù)組里面有number類型,string類型和數(shù)組 要將里面的所有非數(shù)組數(shù)據(jù)存到一個一元數(shù)組中.

答案:

let arr:any[] = []
function  flatDeep(data: any) {
        if (!Array.isArray(data)) {
            arr.push(data)
        } else {
            for (let one of data) {
                flatDeep(one);
            }
        }
    }

解析:

利用遞歸,每次遞歸查找篩選 非數(shù)組的元素 放入一維數(shù)組arr中。

  • parseInt('1.9'); parseInt('hello')分別返回什么值?
    【答案】分別返回 1, NaN

  • null和undefined的區(qū)別。
    【參考答案】null表示一個“空”的值,它和0以及空字符串''不同,0是一個數(shù)值,''表示長度為0的字符串,而null表示“空”。在其他語言中,也有類似JavaScript的null的表示,例如Java也用null,Swift用nil,Python用None表示。但是,在JavaScript中,還有一個和null類似的undefined,它表示“未定義”。
    JavaScript的設(shè)計者希望用null表示一個空的值,而undefined表示值未定義。大多數(shù)情況下,我們都應(yīng)該用null。undefined僅僅在判斷函數(shù)參數(shù)是否傳遞的情況下有用。

  • ==和===的區(qū)別
    【參考答案】==在比較的時候可以自動轉(zhuǎn)換數(shù)據(jù)類型。===嚴格比較,不會進行自動轉(zhuǎn)換,要求進行比較的操作數(shù)必須類型一致,不一致時返回flase。

  • 函數(shù)中this指向什么? call, apply, bind的用法和區(qū)別。
    【參考答案】this指代函數(shù)的運行環(huán)境,執(zhí)行obj.func()時,this指向obj,直接執(zhí)行func()時,this指向全局環(huán)境。
    call, apply, bind都可以改變函數(shù)執(zhí)行時的運行環(huán)境,即this的指向。
    call和apply都是調(diào)用時立刻執(zhí)行的,而bind調(diào)用后返回了綁定this對象的原函數(shù),bind比較適合將this綁定后的函數(shù)傳入到其他函數(shù)中去執(zhí)行,特別是作為回掉函數(shù)異步執(zhí)行。
    call和bind的參數(shù)第一個參數(shù)是要綁定的對象,后面是要傳入原函數(shù)的多個參數(shù);而apply第二個參數(shù)必須是一個數(shù)組,數(shù)組中是要傳入的參數(shù)。

  • 說說對 prototype和 __proto __ 的理解
    【參考答案】prototype是函數(shù)才有的屬性,prototype本身也是個函數(shù)對象;__proto __是所有對象都有的屬性,__proto __指向構(gòu)造它的對象的對象的prototype。例如:

> var o = new Object()
o.__proto__ == Object.prototype
< true

o是Object構(gòu)造出的對象,o的__proto __指向Object的prototype,這樣o可以使用Object.prototype里面的方法。原型鏈:當js查找對象的屬性時,先查找對象自身是否具有該屬性,如果沒有,就會去__proto __指向的prototype對象上查找,直到找到或者__proto __為null

  • 使用構(gòu)造函數(shù)實現(xiàn)一個類Foo,需要有屬性 count, 方法bar(), 并且寫出創(chuàng)建該類對象的方法
    【參考答案】
function Foo(){
  this.count = 0;
}

Foo.prototype.bar = function(){
}

var foo = new Foo();
foo.bar();

  • 以下代碼片段輸出是什么,為什么?如果想輸出0,1,2請問如何修改?
var s = [];
function foo() {
    for(var i=0; i<3; i++){
            s[i] = function(){
                  console.log(i);
            }
    }
}
foo();
s[0]();
s[1]();
s[2]();

【參考答案】輸出3,3,3。因為foo()函數(shù)執(zhí)行時生成了三個閉包,這三個閉包綁定了同一個變量i,第三個閉包生成時,i的值為3。因此執(zhí)行這三個閉包時都會輸出3。
修改為輸出0,1,2的原則是讓三個閉包綁定不同的變量,所以在生成閉包時就要區(qū)分出來,一種修改方法如下:

let s = [];
function foo() {
    for(let i=0; i<3; i++){
            s[i] = function(){
                  console.log(i);
            }
    }
}
foo();
s[0]();
s[1]();
s[2]();
  • 說說ES6為什么要引入let關(guān)鍵字
    【參考答案】因為要解決var聲明對象產(chǎn)生的問題。
    var是函數(shù)級作用域,而let是塊作用域。
    var存在變量提升,即變量可以在聲明之前使用,值為undefined,而let聲明的變量如果在聲明之前使用會拋出一個錯誤。
    另外let不允許重復(fù)聲明變量。
    ES6 規(guī)定暫時性死區(qū)和let、const語句不出現(xiàn)變量提升,主要是為了減少運行時錯誤,防止在變量聲明前就使用這個變量,從而導(dǎo)致意料之外的行為。這樣的錯誤在 ES5 是很常見的,現(xiàn)在有了這種規(guī)定,避免此類錯誤就很容易了。

Cocos creator部分

  • cocos creator和cocos2dx的區(qū)別
    【參考答案】cocos creator是一套包含編輯器在內(nèi)的開發(fā)框架,其內(nèi)部引擎使用了cocos2d-x js的精簡修改版本。creator使用js/ts語言開發(fā),以內(nèi)容創(chuàng)作為核心,腳本作為自定義組件添加到場景的節(jié)點上。

  • creator中需要動態(tài)載入的資源,放在工程的哪個子目錄中
    【參考答案】asserts/resources

  • 寫出代碼片段:獲取節(jié)點node上Label組件,并設(shè)置其內(nèi)容為'hello'
    【參考答案】

let label = node.getComponent(cc.Label);
label.string = 'hello';

  • 列舉出組件的生命周期回掉函數(shù),并說明其調(diào)用時機
    【參考答案】
onLoad   組件首次激活時觸發(fā)
onEnable  組件的enabled屬性從false變?yōu)閠rue時
start    組件第一次執(zhí)行update之前觸發(fā)
update     每一幀渲染前調(diào)用
lateUpdate 所有組件update調(diào)用后調(diào)用
onDisable  組件的enabled屬性從true變?yōu)閒alse時
onDestroy  組件或所在節(jié)點調(diào)用了destroy()時調(diào)用,并在當前幀結(jié)束時統(tǒng)一回收組件
  • creator對齊UI控件使用什么組件?如果想制作一個和屏幕大小一樣的節(jié)點如何設(shè)置該組件
    【參考答案】widget組件。設(shè)置top,bottom,left,right為0px,且該節(jié)點從直接的父節(jié)點到場景根節(jié)點都必須有widget組件且設(shè)置為同屏幕大小?;蛘?.10之后可設(shè)置target為最上層的節(jié)點。

  • 寫一小段代碼,將節(jié)點node在1秒鐘之內(nèi)從當前位置移動到(100,100)
    【參考答案】

cc.tween(node)
.to(1,{position:cc.v2(100,100)})
.start()

游戲開發(fā)部分

  • 什么是draw call? 為什么減少draw call可以優(yōu)化游戲速度。如何減少draw call? 在creator中如何做
    【參考答案】
    1)Draw Call 簡稱 ”繪制調(diào)用“
    就是CPU調(diào)用圖形繪制接口(api)(例如OpenGL中的glDrawElement命令。)來命令GPU進行圖形繪制(渲染)的操作。

2)在每次調(diào)用Draw Call之前,CPU需要向GPU發(fā)送很多內(nèi)容,包括數(shù)據(jù),狀態(tài),命令等。在這一階段,CPU需要完成很多工作,例如檢查渲染狀態(tài)等。而一旦CPU完成了這些準備工作,GPU就可以開始本次的渲染。GPU的渲染能力是很強的,渲染300個和3000個三角網(wǎng)格通常沒有什么區(qū)別,因此渲染速度往往快于CPU提交命令的速度。如果Draw Call的數(shù)量太多,CPU就會把大量時間花費在提交Draw Call命令上,造成CPU的過載。

因此造成Draw Call性能問題的是CPU。
3)解決辦法是 盡可能合批處理 即將小的dc 合并成大的dc 。
1,將碎圖 合并成大圖
1),靜態(tài)合圖
2),動態(tài)合圖
3),textuepaker打包圖集

注意:
1, 盡量將處于同一界面(UI)下的相鄰且渲染狀態(tài)相同的碎圖 打包成圖集
2,改變渲染狀態(tài)會打斷渲染合批,例如改變紋理狀態(tài)(預(yù)乘、循環(huán)模式和過濾模式)或改變 Material(材質(zhì))、Blend(混合模式)等等,所以使用自定義 Shader 也會打斷合批。

3,合理控制圖集最大尺寸,避免單個圖像加載時間過長。
4,尺寸太大的圖像沒有必要打進圖集(如背景圖)而且圖像尺寸越大,加載的時間也越長,而且是非線性的那種增長,例如加載一張圖像比加載兩張圖像所消耗的時間還長。,得不償失。
5, 間距保持默認的 2 并保持勾選擴邊選項,避免圖像裁剪錯誤和出現(xiàn)黑邊的情況。

2,label用bmfont位圖

  • 一張1024x1024,32位的貼圖,在內(nèi)存里面占多少字節(jié)?
    【參考答案】
    圖像占用內(nèi)存的公式是:numBytes = width * height * bitsPerPixel / 8

套用公式,RGBA8888 是32位
1024102432/8 = 4194304(字節(jié))
4194304/1024/1024 = 4M ,
1024*1024 RGBA8888 圖片加載到內(nèi)存的大小 = 4M

  • cocos中sprite的Blend屬性,Src Blend Factor設(shè)置為 SRC_ALPHA, Dst Blend Factor設(shè)置為 ONE_MINUS_SRC_ALPHA是什么意思,有什么作用?
    【參考答案】這表示繪制這個Sprite時,和Frame buffer上面已經(jīng)有的像素進行混合的公式參數(shù)。以上參數(shù)設(shè)置的公式為: FinalColor = SpriteColor(RGB) * SpriteAlpha + BufferColor(RGB) * (1-SpriteAlpha)。效果是標準的透明圖元渲染。

  • 如果做一個射擊游戲,需要發(fā)射大量的子彈,為了避免頻繁的申請內(nèi)存,一般會采取什么方法?
    【參考答案】會采用對象池/內(nèi)存對象緩存的機制。cocoscreator提供了相關(guān)的api nodepool對象池。

常用算法:

對數(shù)

如果a^x=N(a>0,且a≠1),則x叫做以a為底N的對數(shù),記做x=log(a)(N),其中a要寫于log右下。其中a叫做對數(shù)的底,N叫做真數(shù) 。通常我們將以10為底的對數(shù)叫做常用對數(shù),以e為底的對數(shù)稱為自然對數(shù)。

「基本知識」

image

時間復(fù)雜度

通常我們會用大O來表示一個算法的時間復(fù)雜度,即 某個算法的時間增量。

例如: 要在 一個 5個元素的數(shù)組中 查找 1個數(shù) , 不管從第幾個元素開始查找 要想 找到這個數(shù) ,最多需要 5次查找操作 ,最少需要1次 如果是 6個元素的數(shù)組,要找到這個數(shù) 則 最多 6次 ,最少1次。 通過 大O表示 時間復(fù)雜度就是 O(n), 即 每增加 n個元素 就需要 多查找n次 ,算法的時間增量就是o(n).通常大O表示算法復(fù)雜度增量 都是以 最壞的 情況為 準。

簡單查找

在一個數(shù)組中挨個查找某個數(shù)據(jù),這種查找就是簡單查找

比如 5個元素的數(shù)組中 查找 1個數(shù) ,從頭到尾查找,最多需要查找五次。

「時間復(fù)雜度」:O(n) , 算法時間是線性增長的。 n個數(shù) 最多查找n次 最少查找1次。

「例子」

   * 簡單查找
   * @param arr 目標數(shù)組
   * @param num 要查找的數(shù)字
   */
  function simpleSearch(arr: number[], num: number):number {
    for (let one of arr) {
      if (one === num) {
        return one;
      }
    }
    return -1;
  }

二分查找

「前提」:已經(jīng)排序的數(shù)據(jù)

「邏輯」:在排好序(降序如 1,2,3)的 容器中 每次選擇 容器的 中間或者+1或者-1的數(shù)字,進行比較,如果 該數(shù)字 大于要查找的數(shù)字 ,那么以該數(shù)字索引-1對應(yīng)的值為最大元素,以原來最小的值為最小值 ,繼續(xù) 折中 查找,如果 該數(shù)字 小于要查找的數(shù)字 則以 該數(shù)字索引+1所對應(yīng)的值為最小值 ,原最大值為最大值 再次折中查找 ,一直到最小數(shù)索引等于最大數(shù)索引 即 找到對應(yīng)的值或者 查找完 沒有該值為止。

「時間復(fù)雜度」:O(log2n) 以2為底 真數(shù)為n的對數(shù)。

比如 在 n個已經(jīng)排好序的數(shù)中查找某個數(shù)據(jù),每次折中查找 ,那么找到這個數(shù)的 最多次數(shù)是 log2n 次 。如果 n是 10 那么 找到這個數(shù) 最多需要4次 即 2 * 2 * 2 * 2。因為222是 8不到10 不能完全查完容器的數(shù)據(jù),所以還需要折中查找一次,所以是 4次

「例子」

   * arr 目標數(shù)組
   * num  要查找的數(shù)字
  */
 function binarySearch(arr: number[], num: number):number {
    let low = 0;
    let hight = arr.length - 1;
    let count = 0;
    while (low <= hight) {
      count++;
      let mid = Math.floor((low + hight) / 2);
      let guess = arr[mid];
      if (guess === num) return guess;
      if (guess > num) {
        hight = mid - 1;
      } else {
        low = mid + 1;
      }
    }
    return -1;
  }

選擇排序

「邏輯」:需要遍歷n-1趟,n表示容器中n個元素,每趟從待排序的記錄序列中選擇最小或最大的數(shù)字放到已排序表的最前位置,直到全部排完。 每趟交換一次數(shù)據(jù)

「時間復(fù)雜度」:log(n*n) 最多需要 n * n 次排完

「穩(wěn)定性」:不穩(wěn)定

「例子」

   * 選擇排序 從小到大
   * @param arr 容器
   */
 function selectionSort(arr: number[]) {
    let len = arr.length;
    for (let i = 0; i < len - 1 ; i++) {
      //設(shè)定第一個元素為最小元素
      let minindex = i;
      for (let j = i + 1; j < len ; j++) {
        if (arr[minindex] > arr[j]) {
          minindex = j;
        }
      }
      //每次遍歷找出最小值與上一次的最小值交換
      if (i != minindex) {
        let temp = arr[minindex];
        arr[minindex] = arr[i];
        arr[i] = temp;
      }

    }
  }

冒泡排序

「邏輯」:在要排序的一組數(shù)中,對當前還未排好序的范圍內(nèi)的全部數(shù),對相鄰的兩個數(shù)依次進行比較和調(diào)整,讓較大的數(shù)往下沉,較小的往上冒。即:每當兩相鄰的數(shù)比較后發(fā)現(xiàn)它們的排序與排序要求相反時,就將它們互換。 需要遍歷 n-1趟,每趟 需要對比 n- 當前排序索引-1 次。每趟 交換 n-當前排序索引 -1次 數(shù)據(jù)

「時間復(fù)雜度」:log(n*n) 最多需要 n * n 次排完

「穩(wěn)定性」:穩(wěn)定

「例子」

 * 冒泡排序 從小到大
 * @param arr 
 */
 function bubbleSort(arr: number[]) {
    let len = arr.length;
    for (let i = 0; i < len - 1; i++) {
      for (let j = 0; j < len - i - 1; j++) { // -i 是 排除已經(jīng)沉到最下面的數(shù),沒必要再次比較。
        if (arr[j] > arr[j + 1]) {
          let temp = arr[j];
          arr[j] = arr[j + 1];
          arr[j + 1] = temp;
        }
      }
    }
  }

快速排序

「邏輯」

(1)首先設(shè)定一個分界值,通過該分界值將數(shù)組分成左右兩部分。

(2)將大于或等于分界值的數(shù)據(jù)集中到數(shù)組右邊,小于分界值的數(shù)據(jù)集中到數(shù)組的左邊。此時,左邊部分中各元素都小于或等于分界值,而右邊部分中各元素都大于或等于分界值。

(3)然后,左邊和右邊的數(shù)據(jù)可以獨立排序。對于左側(cè)的數(shù)組數(shù)據(jù),又可以取一個分界值,將該部分數(shù)據(jù)分成左右兩部分,同樣在左邊放置較小值,右邊放置較大值。右側(cè)的數(shù)組數(shù)據(jù)也可以做類似處理。

(4)重復(fù)上述過程,可以看出,這是一個遞歸定義。通過遞歸將左側(cè)部分排好序后,再遞歸排好右側(cè)部分的順序。當左、右兩個部分各數(shù)據(jù)排序完成后,整個數(shù)組的排序也就完成了。

「時間復(fù)雜度」:最好情況 nlog(2n),最差情況log(n*n)

「理想的情況是」:每次劃分所選擇的中間數(shù)恰好將當前序列幾乎等分,經(jīng)過log2n趟劃分,便可得到長度為1的子表。這樣,整個算法的時間復(fù)雜度為O(nlog2n)。

「最壞的情況是」:每次所選的中間數(shù)是當前序列中的最大或最小元素,這使得每次劃分所得的子表中一個為空表,另一子表的長度為原表的長度-1。這樣,長度為n的數(shù)據(jù)表的快速排序需要經(jīng)過n趟劃分,使得整個排序算法的時間復(fù)雜度為O(n*n)

「穩(wěn)定性」:不穩(wěn)定

「例子」

   * 快速排序
   * @param array 輸入待排序數(shù)組
   * @returns 排序后的數(shù)組
   */
function  quickSort(array:number[]) {

    const sort = (arr, left = 0, right = arr.length - 1) => {
     if (left >= right) {//如果左邊的索引大于等于右邊的索引說明整理完畢
      return
      }

    let low = left
    let index = right
    const baseVal = arr[right] // 取無序數(shù)組最后一個數(shù)為基準值

    while (low < index) {//把所有比基準值小的數(shù)放在左邊大的數(shù)放在右邊

      //找到一個比基準值大的數(shù)交換
      while (low < index && arr[low] <= baseVal) { 
        low++
      }
      arr[index] = arr[low] // 將較大的值放在右邊如果沒有比基準值大的數(shù)就是將自己賦值給自己(i 等于 j)

      while (low < index && arr[index] >= baseVal) { //找到一個比基準值小的數(shù)交換
        index--
        break
      }
      arr[low] = arr[index] // 將較小的值放在左邊如果沒有找到比基準值小的數(shù)就是將自己賦值給自己(i 等于 j)
    }

      arr[index] = baseVal // 將基準值放至中央位置完成一次循環(huán)(這時候 j 等于 i )

      sort(arr, left, index-1) // 將左邊的無序數(shù)組重復(fù)上面的操作
      sort(arr, index+1, right) // 將右邊的無序數(shù)組重復(fù)上面的操作
    }
    sort(array)
    return array
   }
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容