🎄 preface

This paper mainly summarizes the handwritten questions investigated in 2021 front-end early approval and autumn recruitment. The questions are from the front end of Niuke.com. The statistical period is from the beginning of March to the end of October, and the interviews are from 15 companies such as Alibaba, Tencent, Baidu, Byte, Meituan, JINGdong, Kuaishou and Pinduoduo.

  • ⭐⭐⭐⭐ service: 10+ in 15 company interviews
  • ⭐⭐⭐⭐ : 5-10 in 15 formula interviews
  • ⭐⭐⭐ : 3-5 in interviews with 15 companies
  • No star: 1-2 appears

Part of the problem analysis comes from the writing of the small package, and the other part is to select links from some of the big guys’ blogs if I feel the problem is better expanded.

🌟 promise

Realize the promise

(⭐⭐⭐⭐⭐)

Reference code

Realize the promise. All

(⭐⭐⭐⭐⭐)

function PromiseAll(promises){
    return new Promise((resolve, reject) = >{
        if(!Array.isArray(promises)){
            throw new TypeError("promises must be an array")}let result = [] 
        let count = 0 
        promises.forEach((promise, index) = > {
            promise.then((res) = >{
                result[index] = res
                count++
                count === promises.length && resolve(result) 
            }, (err) = >{
                reject(err)
            })
        })
    })
}


Copy the code

Realize the promise. Finally

(⭐⭐⭐⭐⭐)

Promise.prototype.finally = function (cb) {
  return this.then(function (value) {
    return Promise.resolve(cb()).then(function () {
      return value
    })
  }, function (err) {
    return Promise.resolve(cb()).then(function () {
      throw err
    })
  })
}

Copy the code

Realize the promise. AllSettled

(⭐⭐⭐⭐)

function allSettled(promises) {
  if (promises.length === 0) return Promise.resolve([])
  
  const _promises = promises.map(
    item= > item instanceof Promise ? item : Promise.resolve(item)
    )
  
  return new Promise((resolve, reject) = > {
    const result = []
    let unSettledPromiseCount = _promises.length
    
    _promises.forEach((promise, index) = > {
      promise.then((value) = > {
        result[index] = {
          status: 'fulfilled',
          value
        }
        
        unSettledPromiseCount -= 1
        // resolve after all are settled
        if (unSettledPromiseCount === 0) {
          resolve(result)
        }
      }, (reason) = > {
        result[index] = {
          status: 'rejected',
          reason
        }
        
        unSettledPromiseCount -= 1
        // resolve after all are settled
        if (unSettledPromiseCount === 0) {
          resolve(result)
        }
      })
    })
  })
}
Copy the code

Realize the promise. Race

(⭐⭐⭐)

Promise.race = function(promiseArr) {
    return new Promise((resolve, reject) = > {
        promiseArr.forEach(p= > {
            Promise.resolve(p).then(val= > {
                resolve(val)
            }, err= > {
                rejecte(err)
            })
        })
    })
}
Copy the code

How do you execute multiple promises sequentially

Reference code

promise.any

Promise.any = function(promiseArr) {
    let index = 0
    return new Promise((resolve, reject) = > {
        if (promiseArr.length === 0) return 
        promiseArr.forEach((p, i) = > {
            Promise.resolve(p).then(val= > {
                resolve(val)
                
            }, err= > {
                index++
                if (index === promiseArr.length) {
                  reject(new AggregateError('All promises were rejected'))}})})})}Copy the code

resolve

Promise.resolve = function(value) {
    if(value instanceof Promise) {return value
    }
    return new Promise(resolve= > resolve(value))
}

Copy the code

reject

Promise.reject = function(reason) {
    return new Promise((resolve, reject) = > reject(reason))
}
Copy the code

🐳 Array article

Array to heavy

(⭐⭐⭐⭐⭐)

Using doubleforsplice

function unique(arr){            
    for(var i=0; i<arr.length; i++){
        for(var j=i+1; j<arr.length; j++){
            if(arr[i]==arr[j]){         
            // The first is the same as the second, and the splice method deletes the second
                arr.splice(j,1);
                // delete after note callback jj--; }}}return arr;
}
Copy the code

useindexOfincludesAdd new array

/ / use indexof
function unique(arr) {
    var uniqueArr = []; / / the new array
    for (let i = 0; i < arr.length; i++) {
        if (uniqueArr.indexOf(arr[i]) === -1) {
            // Indexof returns -1 to indicate that the element does not exist in the new array
            uniqueArr.push(arr[i])// Push an element that is not in the new array}}return uniqueArr;
}
/ / use includes
function unique(arr) {
    var uniqueArr = []; 
    for (let i = 0; i < arr.length; i++) {
        //includes checks whether the array has a value
        if(! uniqueArr.includes(arr[i])) { uniqueArr.push(arr[i])//}}return uniqueArr;
}
Copy the code

sortAfter sorting, use the idea of fast or slow Pointers

function unique(arr) {
    arr.sort((a, b) = > a - b);
    var slow = 1,
        fast = 1;
    while (fast < arr.length) {
        if(arr[fast] ! = arr[fast -1]) {
            arr[slow ++] = arr[fast];
        }
        ++ fast;
    }
    arr.length = slow;
    return arr;
}
Copy the code

The sort method is used to sort from smallest to largest (returning a new array), and without the above callbacks in its arguments the sorting error occurs at two digits or more (if omitted, the elements are sorted by the Unicode point of each character in the converted string). The two-digit number is converted to a string of length two for calculation.

ES6To provide theSetduplicate removal

function unique(arr) {
    const result = new Set(arr);
    return [...result];
    // Use the extension operator to convert a Set data structure into an array
}
Copy the code

Elements in a Set occur only once, that is, the elements in a Set are unique.

Use hash tables to store whether elements are present (ES6To provide themap)

function unique(arr) {
    let map = new Map(a);let uniqueArr = new Array(a);// The array is used to return the result
    for (let i = 0; i < arr.length; i++) {
      if(map.has(arr[i])) {  // If there is a key value
        map.set(arr[i], true); 
      } else { 
        map.set(arr[i], false);   // If there is no key valueuniqueArr.push(arr[i]); }}return uniqueArr ;
}
Copy the code

Map objects hold key-value pairs, similar to objects. However, map keys can be of any type, and object keys can only be strings.

You can also use ordinary objects as hash tables if the array contains only numbers.

filterCooperate withindexOf

function unique(arr) {
    return arr.filter(function (item, index, arr) {
        // Current element, the first index in the original array == current index value, otherwise return current element
        // If it is not a duplicate item, discard it
        returnarr.indexOf(item) === index; })}Copy the code

Here’s an example of a possible question:

const arr = [1.1.2.1.3]
arr.indexOf(arr[0= = =])0 // The first occurrence of 1
arr.indexOf(arr[1])! = =1 // show that there is a 1 before
Copy the code

reduceCooperate withincludes

function unique(arr){
    let uniqueArr = arr.reduce((acc,cur) = >{
        if(! acc.includes(cur)){ acc.push(cur); }returnacc; }, [])// [] as the initial value of the first argument to the callback function
    return uniqueArr
}
Copy the code

Array flattening

(⭐⭐⭐)

Reference code

forEach

(⭐⭐⭐)

Array.prototype.myForEach = function (callbackFn) {
    // Check if this is valid
    if (this= = =null || this= = =undefined) {
        throw new TypeError("Cannot read property 'myForEach' of null");
    }
    // Check whether the callbackFn is valid
    if (Object.prototype.toString.call(callbackFn) ! = ="[object Function]") {
        throw new TypeError(callbackFn + ' is not a function')}// Get the array object that executes the method and the this object passed in
    var _arr = this, thisArg = arguments[1] | |window;
    for (var i = 0; i < _arr.length; i++) {
        // Execute the callback functioncallbackFn.call(thisArg, _arr[i], i, _arr); }}Copy the code

reduce

(⭐⭐⭐)

Array.prototype.myReduce = function(callbackFn) {
    var _arr = this, accumulator = arguments[1];
    var i = 0;
    // Determine whether an initial value is passed in
    if (accumulator === undefined) {
        // An error is reported when calling reduce with an empty array with no initial value
        if (_arr.length === 0) {
            throw new Error('initVal and Array.length>0 need one')}// Assign the initial value to the first element of the array
        accumulator = _arr[i];
        i++;
    }
    for (; i<_arr.length; i++) {
        // The computed result is assigned to the initial value
        accumulator = callbackFn(accumulator,  _arr[i], i, _arr)
    }
    return accumulator;
}

Copy the code

map

Array.prototype.myMap = function(callbackFn) {
    var _arr = this, thisArg = arguments[1] | |window, res = [];
    for (var i = 0; i<_arr.length; i++) {
        // Store the result of the operation
        res.push(callbackFn.call(thisArg, _arr[i], i, _arr));
    }
    return res;
}

Copy the code

filter

Array.prototype.myFilter = function(callbackFn) {
    var _arr = this, thisArg = arguments[1] | |window, res = [];
    for (var i = 0; i<_arr.length; i++) {
        // The callback function executes true
        if(callbackFn.call(thisArg, _arr[i], i, _arr)) { res.push(_arr[i]); }}return res;
}
Copy the code

every

Array.prototype.myEvery = function(callbackFn) {
    var _arr = this, thisArg = arguments[1] | |window;
    // The start identifier value is true
    // Return false on a callback
    // If the loop completes, it means that all callbacks return true and the final result is true
    var flag = true;
    for (var i = 0; i<_arr.length; i++) {
        // If the callback is false, the function is interrupted
        if(! callbackFn.call(thisArg, _arr[i], i, _arr)) {return false; }}return flag;
}
Copy the code

some

Array.prototype.mySome = function(callbackFn) {
    var _arr = this, thisArg = arguments[1] | |window;
    // Start identifier value is false
    // If a callback returns true, return true
    // If the loop completes, it means that all callbacks return false and the final result is false
    var flag = false;
    for (var i = 0; i<_arr.length; i++) {
        // If the callback is false, the function is interrupted
        if (callbackFn.call(thisArg, _arr[i], i, _arr)) {
            return true; }}return flag;
}
Copy the code

find/findIndex

Array.prototype.myFind = function(callbackFn) {
    var _arr = this, thisArg = arguments[1] | |window;
    // Returns true on a callback, directly returning the array element
    // If the loop completes, it means that all callbacks return false and the final result is undefined
    for (var i = 0; i<_arr.length; i++) {
        // If the callback is false, the function is interrupted
        if (callbackFn.call(thisArg, _arr[i], i, _arr)) {
            return_arr[i]; }}return undefined;
}
Copy the code

indexOf

function indexOf(findVal, beginIndex = 0) {
    if (this.length < 1 || beginIndex > findVal.length) {
        return -1;
    }
    if(! findVal) {return 0;
    }
    beginIndex = beginIndex <= 0 ? 0 : beginIndex;
    for (let i = beginIndex; i < this.length; i++) {
        if (this[i] == findVal) return i;
    }
    return -1;
}
      

Copy the code

To achieve the sort

Reference code

🌊 anti-shake throttling

Implement the anti-shock function debounce

(⭐⭐⭐⭐⭐)

function debounce(func, wait, immediate) {

    var timeout, result;

    var debounced = function () {
        var context = this;
        var args = arguments;

        if (timeout) clearTimeout(timeout);
        if (immediate) {
            // If yes, no further action is required
            varcallNow = ! timeout; timeout =setTimeout(function(){
                timeout = null;
            }, wait)
            if (callNow) result = func.apply(context, args)
        }
        else {
            timeout = setTimeout(function(){
                result = func.apply(context, args)
            }, wait);
        }
        return result;
    };

    debounced.cancel = function() {
        clearTimeout(timeout);
        timeout = null;
    };

    return debounced;
}
Copy the code

Implement throttle functions

(⭐⭐⭐⭐⭐)

/ / the fourth edition
function throttle(func, wait, options) {
    var timeout, context, args, result;
    var previous = 0;
    if(! options) options = {};var later = function() {
        previous = options.leading === false ? 0 : new Date().getTime();
        timeout = null;
        func.apply(context, args);
        if(! timeout) context = args =null;
    };

    var throttled = function() {
        var now = new Date().getTime();
        if(! previous && options.leading ===false) previous = now;
        var remaining = wait - (now - previous);
        context = this;
        args = arguments;
        if (remaining <= 0 || remaining > wait) {
            if (timeout) {
                clearTimeout(timeout);
                timeout = null;
            }
            previous = now;
            func.apply(context, args);
            if(! timeout) context = args =null;
        } else if(! timeout && options.trailing ! = =false) {
            timeout = setTimeout(later, remaining); }};return throttled;
}

Copy the code

⛲ Object article

Can you write a full deep copy

(⭐⭐⭐⭐⭐)

const getType = obj= > Object.prototype.toString.call(obj);

const isObject = (target) = > (typeof target === 'object' || typeof target === 'function') && target ! = =null;

const canTraverse = {
  '[object Map]': true.'[object Set]': true.'[object Array]': true.'[object Object]': true.'[object Arguments]': true};const mapTag = '[object Map]';
const setTag = '[object Set]';
const boolTag = '[object Boolean]';
const numberTag = '[object Number]';
const stringTag = '[object String]';
const symbolTag = '[object Symbol]';
const dateTag = '[object Date]';
const errorTag = '[object Error]';
const regexpTag = '[object RegExp]';
const funcTag = '[object Function]';

const handleRegExp = (target) = > {
  const { source, flags } = target;
  return new target.constructor(source, flags);
}

const handleFunc = (func) = > {
  // The arrow function returns itself directly
  if(! func.prototype)return func;
  const bodyReg = / (? <={)(.|\n)+(? =})/m;
  const paramReg = / (? < = \ () + (? =\)\s+{)/;
  const funcString = func.toString();
  // Match function parameters and function body respectively
  const param = paramReg.exec(funcString);
  const body = bodyReg.exec(funcString);
  if(! body)return null;
  if (param) {
    const paramArr = param[0].split(', ');
    return new Function(... paramArr, body[0]);
  } else {
    return new Function(body[0]); }}const handleNotTraverse = (target, tag) = > {
  const Ctor = target.constructor;
  switch(tag) {
    case boolTag:
      return new Object(Boolean.prototype.valueOf.call(target));
    case numberTag:
      return new Object(Number.prototype.valueOf.call(target));
    case stringTag:
      return new Object(String.prototype.valueOf.call(target));
    case symbolTag:
      return new Object(Symbol.prototype.valueOf.call(target));
    case errorTag: 
    case dateTag:
      return new Ctor(target);
    case regexpTag:
      return handleRegExp(target);
    case funcTag:
      return handleFunc(target);
    default:
      return newCtor(target); }}const deepClone = (target, map = new WeakMap(a)) = > {
  if(! isObject(target))return target;
  let type = getType(target);
  let cloneTarget;
  if(! canTraverse[type]) {// Process objects that cannot be traversed
    return handleNotTraverse(target, type);
  }else {
    // This operation is critical to ensure that the object's prototype is not lost!
    let ctor = target.constructor;
    cloneTarget = new ctor();
  }

  if(map.get(target)) 
    return target;
  map.set(target, true);

  if(type === mapTag) {
    / / the Map processing
    target.forEach((item, key) = >{ cloneTarget.set(deepClone(key, map), deepClone(item, map)); })}if(type === setTag) {
    / / handle the Set
    target.forEach(item= >{ cloneTarget.add(deepClone(item, map)); })}// Handle arrays and objects
  for (let prop in target) {
    if(target.hasOwnProperty(prop)) { cloneTarget[prop] = deepClone(target[prop], map); }}return cloneTarget;
}

Copy the code

Refer to the blog

Implement new

(⭐⭐⭐⭐)

function createObject(Con) {
    // Create a new object obj
    // var obj = {}; Can also be
    var obj = Object.create(null);

    // put the obj.__proto__ -> constructor prototype
    // (not recommended)obj.__proto__ = con.prototype
    Object.setPrototypeOf(obj, Con.prototype);

    // Execute the constructor and accept the constructor return value
    const ret = Con.apply(obj, [].slice.call(arguments.1));

    // If the constructor returns an object, the object is returned
    // Otherwise return obj
    return typeof(ret) === 'object' ? ret: obj;
}
Copy the code

inheritance

(⭐⭐⭐⭐)

Prototype chain inheritance

Borrowing constructors (classical inheritance)

Combination of inheritance

Primary inheritance

Parasitic inheritance

Parasitic combinatorial inheritance

Class implementation inheritance (sidebar)

class Animal {
    constructor(name) {
        this.name = name
    } 
    getName() {
        return this.name
    }
}
class Dog extends Animal {
    constructor(name, age) {
        super(name)
        this.age = age
    }
}
Copy the code

Reference code

To realize the object. The create

function newCreate(proto, propertiesObject) {
    if (typeofproto ! = ='object' && typeofproto ! = ='function') {
        throw TypeError('Object prototype may only be an Object: ' + proto)
    }
    function F() { }
    F.prototype = proto
    const o = new F()

    if(propertiesObject ! = =undefined) {
        Object.keys(propertiesObject).forEach(prop= > {
            let desc = propertiesObject[prop]
            if (typeofdesc ! = ='object' || desc === null) {
                throw TypeError('Object prorotype may only be an Object: ' + desc)
            } else {
                Object.defineProperty(o, prop, desc)
            }
        })
    }

    return o
}
Copy the code

🚂 Function article

call

(⭐⭐⭐⭐)

Function.prototype.myCall = function (thisArg) {
    thisArg = thisArg || window;
    thisArg.func = this;
    const args = []
    for (let i = 1; i<arguments.length; i++) {
        args.push('arguments['+ i + '] ')}const result = eval('thisArg.func(' + args +') ')
    delete thisArg.func;
    return result;
}
Copy the code

bind

(⭐⭐⭐⭐)

Function.prototype.sx_bind = function (obj, ... args) {
    obj = obj || window

    const fn = Symbol()
    obj[fn] = this
    const _this = this

    const res = function (. innerArgs) {
        console.log(this, _this)
        if (this instanceof _this) {
            this[fn] = _this
            this[fn](... [...args, ...innerArgs])delete this[fn]
        } else{ obj[fn](... [...args, ...innerArgs])delete obj[fn]
        }
    }
    res.prototype = Object.create(this.prototype)
    return res
}
Copy the code

apply

(⭐⭐⭐⭐)

Function.prototype.myApply = function (thisArg, arr) {
    thisArg = thisArg || window;
    thisArg.func = this;
    const args = []
    for (let i = 0; i<arr.length; i++) {
        args.push('arr['+ i + '] ')}const result = eval('thisArg.func(' + args +') ')
    delete thisArg.func;
    return result;
}
Copy the code

Implement creefaction

(⭐⭐⭐)

Reference code

Implement chain calls

Reference code

Partial function

Reference code

🌍 ajax and json

(⭐⭐⭐)

Implementing ajax

function ajax({
    url= null,
	method = 'GET',
	dataType = 'JSON'.async = true}){
	return new Promise((resolve, reject) = > {
		let xhr = new XMLHttpRequest()
		xhr.open(method, url, async)
		xhr.responseType = dataType
		xhr.onreadystatechange = () = > {
			if(!/^[23]\d{2}$/.test(xhr.status)) return;
			if(xhr.readyState === 4) {
				let result = xhr.responseText
				resolve(result)
			}
		}
		xhr.onerror = (err) = > {
			reject(err)
		}
		xhr.send()
	})
}
Copy the code

To realize the json

const jsonp = ({ url, params, callbackName }) = > {
    const generateUrl = () = > {
        let dataSrc = ' '
        for (let key in params) {
            if (params.hasOwnProperty(key)) {
                dataSrc += `${key}=${params[key]}& `
            }
        }
        dataSrc += `callback=${callbackName}`
        return `${url}?${dataSrc}`
    }
    return new Promise((resolve, reject) = > {
        const scriptEle = document.createElement('script')
        scriptEle.src = generateUrl()
        document.body.appendChild(scriptEle)
        window[callbackName] = data= > {
            resolve(data)
            document.removeChild(scriptEle)
        }
    })
}
Copy the code

🛫 ES6 article

To achieve the set

class Set {
  constructor() {
    this.items = {};
    this.size = 0;
  }

  has(element) {
    return element in this.items;
  }

  add(element) {
    if(! this.has(element)) {
      this.items[element] = element;
      this.size++;
    }
    return this;
  }

  delete(element) {
    if (this.has(element)) {
      delete this.items[element];
      this.size--;
    }
    return this;
  }

  clear() {
    this.items = {}
    this.size = 0;
  }

  values() {
    let values = [];
    for(let key in this.items) {
      if(this.items.hasOwnProperty(key)) { values.push(key); }}returnvalues; }}Copy the code

To realize the map

function defaultToString(key) {
  if(key === null) {
    return 'NULL';
  } else if (key === undefined) {
    return 'UNDEFINED'
  } else if (Object.prototype.toString.call(key) === '[object Object]' || Object.prototype.toString.call(key) === '[object Array]') {
    return JSON.stringify(key);
  }
  return key.toString();
}

class Map {
  constructor() {
    this.items = {};
    this.size = 0;
  }

  set(key, value) {
    if(!this.has(key)) {
      this.items[defaultToString(key)] = value;
      this.size++;
    }
    return this;
  }

  get(key) {
    return this.items[defaultToString(key)];
  }

  has(key) {
    return this.items[defaultToString(key)] ! = =undefined;
  }

  delete(key) {
    if (this.has(key)) {
      delete this.items[key];
      this.size--;
    }
    return this;
  }

  clear() {
    this.items = {}
    this.size = 0;
  }

  keys() {
    let keys = [];
    for(let key in this.items) {
      if(this.has(key)) {
        keys.push(key)
      }
    }
    return keys;
  }

  values() {
    let values = [];
    for(let key in this.items) {
      if(this.has(key)) {
        values.push(this.items[key]); }}returnvalues; }}Copy the code

Implement es6 class

Reference code

🦉 other

instanceof

(⭐⭐⭐⭐)

function instance_of(Case, Constructor) {
    // Base data type returns false
    // Make it compatible with function objects
    if ((typeof(Case) ! ='object' && typeof(Case) ! ='function') || Case == 'null') return false;
    let CaseProto = Object.getPrototypeOf(Case);
    while (true) {
        // Find the top of the prototype chain, still not found, return false
        if (CaseProto == null) return false;
        // Find the same prototype
        if (CaseProto === Constructor.prototype) return true;
        CaseProto = Object.getPrototypeOf(CaseProto); }}Copy the code

Implement thousandth delimiters

(⭐⭐⭐)

var str = "100000000000",
    reg = / (? =(\B\d{3})+$)/g;
str.replace(reg, ",")
Copy the code

Convert the key of a JSON object from underscore (Pascal) to Camel

(⭐⭐⭐)

Reference code

Implement data type judge function

function myTypeof(obj) {
   return Object.prototype.toString.call(obj).slice(8, -1).toLowerCase() 
}
Copy the code

Implement array to tree

Reference code

Implementing the sleep function

// promise
const sleep = time= > {
  return new Promise(resolve= > setTimeout(resolve,time))
}
sleep(1000).then(() = >{
  console.log(1)})// ES5
function sleep(callback,time) {
  if(typeof callback === 'function')
    setTimeout(callback,time)
}

function output(){
  console.log(1);
}
sleep(output,1000);

Copy the code

Implement the publish and subscribe model

class EventEmitter {
    constructor() {
        this.cache = {}
    }
    on(name, fn) {
        if (this.cache[name]) {
            this.cache[name].push(fn)
        } else {
            this.cache[name] = [fn]
        }
    }
    off(name, fn) {
        let tasks = this.cache[name]
        if (tasks) {
            const index = tasks.findIndex(f= > f === fn || f.callback === fn)
            if (index >= 0) {
                tasks.splice(index, 1)}}}emit(name, once = false. args) {
        if (this.cache[name]) {
            // Create a copy. If the same event continues to be registered within the callback function, an infinite loop will occur
            let tasks = this.cache[name].slice()
            for (let fn oftasks) { fn(... args) }if (once) {
                delete this.cache[name]
            }
        }
    }
}
Copy the code

🛕 More topics

Portal: Front end topic

If you feel helpful, don’t forget to give the small bag a ⭐.

💘 previous excellent articles

  • Cow guest latest front-end JS written test 100 questions
  • The latest front end of the interview questions summary (including analysis)
  • Grab the latest front end test five hundred data analysis JS interview hot spots
  • Happy cat stroking for VSCode and website adoptive cats
  • Native JavaScript soul Test (1), how much can you answer?
  • A thorough understanding of prototypes and prototype chains in JavaScript
  • Complete understanding of EventLoop in JavaScript
  • “2W word big chapter 38 interview questions” completely clear JS this pointing to the problem

After 💥 language

Guys, if you find this article helpful, give a like to 👍 or follow ➕ to support me.

In addition, if this article has a question, or do not understand part of the article, you can reply to me in the comment section, we come to discuss, learn together, progress together!

If you feel that the comment section does not understand, you can also add my wechat (li444186976) or QQ (3315161861) for detailed communication, the name is battlefield small bag.