js 面试记录,偏原生js基础,js基本功

170 阅读4分钟

记录有如下问题

// 1. 判断对象是否为空
// 2. typeof 返回值有哪些
// 3. typeof 和 instanceOf的区别
// 4. 深拷贝、浅拷贝
// 5. 获取一个字符串的后十位 
// 6. lodash 性能问题  
// 7. 空对象和空数组 的布尔类型
// 8. 判断一个变量是否为数组或者对象
// 9. 前端如何设置cookie,让别人无法读取?

1. 判断对象是否为空


const data = {};
const result = JSON.stringify(data) === '{}';
console.log('result', result); // === true

class Person {
    state = {};
}

Person.prototype.getting = function () {
    console.log('1', 1);
};

const p1 = new Person();

console.log('p1', p1);
console.log('p1', JSON.stringify(p1) === '{}');
// p1 Person {}
// p1 false

// ---

for (let key in p1) {
    console.log('key:', key);
    // key: state
    // key: getting
}

for (const key of Object.keys(p1)) {
    // Object.key: state
    console.log('Object.key:', key);
}

console.log('Object.getOwnPropertyNames(p1):', Object.getOwnPropertyNames(p1));
// Object.getOwnPropertyNames(p1): [ 'state' ]

2. typeof 返回值有哪些

console.log('typeof true ===', typeof true);
console.log('typeof undefined === ', typeof undefined);
console.log('typeof "a" === ', typeof 'a');
console.log('typeof 1 === ', typeof 1);
console.log('typeof null === ', typeof null);
console.log('typeof {} === ', typeof {});
console.log('typeof [] === ', typeof []);
console.log('typeof function() {} === ', typeof function () {});
console.log('typeof class A {} ===', typeof class A {});
console.log('typeof new Set() === ', new Set());
console.log('typeof new Map() === ', new Map());
console.log('typeof Symbol() === ', Symbol());
console.log('typeof Date ===', typeof Date);
console.log('typeof new Date() ===', typeof new Date());

const test1 = Symbol(1);
const test2 = Symbol(1);

console.log('test1 === test2', test1 === test2); // false

// typeof true ===  'boolean'
// typeof undefined ===  'undefined'
// typeof "a" ===  'string'
// typeof 1 ===  'number'
// typeof null ===  'object'
// typeof {} ===  'object'
// typeof [] ===  'object'
// typeof function() {} ===  'function'
// typeof class A {} === 'function'
// typeof new Set() ===  'object'
// typeof new Map() ===  'object'
// typeof Symbol() ===  'symbol'
// typeof Date === 'function'
// typeof new Date() === 'object'

console.log('typeof new Set() === "object"', typeof new Set() === 'object'); // true

3. typeof 和 instanceOf的区别


// typeof 和 instanceof的区别
// 1. typeof 是xxx的类型
// instanceof 是xxx的实例

// 2. typeof 的返回值有"number","boolean","string","function","object","undefined"
// instanceof 返回值是 true OR false

// 3. typeof(X) X可以不定义,但是不会报错,返回值是"undefined"字符串
// instanceof 左边的值必须先定义,右边必须为对象或者function否则会报错

// 4. instanceof 可以对不同的对象实例进行判断,
// 判断的方法是根据对象的原型链一次向下查询
// 如果原型链存在那么 返回true 否则返回false
// 5. instanceof 返回的值true false 在特殊情况下不可靠
// 原因是 instance可以被自定义
// 这个在 es6 阮一峰老师的书上有讲到
// 具体这么写:
// class PersonInstance {
//     // 直接对PersonInstance使用 instanceof 时被调用
//     static [Symbol.hasInstance](x) {
//         return typeof x === 'xxx';
//     }
//     // 对PersonInstance实例 使用instanceof时被调用
//     [Symbol.hasInstance](y) {
//         return typeof y === 'xxxx';
//     }
// }

class PrimitiveString {
    static [Symbol.hasInstance](x) {
        console.log('x: ', x); // x: hello
        return typeof x === 'string';
    }
}
console.log(
    '"hello" instanceof PrimitiveString',
    'hello' instanceof PrimitiveString
); // true

// hasInstance是 可以自定义 instanceof行为
class PrimitiveString2 {
    // 静态方法
    static [Symbol.hasInstance](x) {
        console.log('x: ', x); // x: hello
        return typeof x === 'object';
    }

    // 实例访问的方法
    [Symbol.hasInstance](y) {
        console.log('y', y); // hello2
        return typeof y === 'hello';
    }
}

console.log(
    '"hello" instanceof PrimitiveString2',
    {} instanceof PrimitiveString2
); // true
console.log(
    '"hello" instanceof PrimitiveString2',
    'hello' instanceof PrimitiveString2
); // false
console.log(
    '"hello2" instanceof new PrimitiveString2()',
    'hello2' instanceof new PrimitiveString2()
); // false
console.log(
    '"hello" instanceof new PrimitiveString2()',
    'hello' instanceof new PrimitiveString2()
); // true

// ----
console.log('p1 instanceof Person:', p1 instanceof Person);
// p1 instanceof Person: true
console.log('p1 instanceof PrimitiveString2:', p1 instanceof PrimitiveString2);
// p1 instanceof PrimitiveString2: true

// 说明 instanceof 不是百分百准确的

4. 深拷贝(考虑Date, RegExp, Error)、浅拷贝

function deepCopy(obj, cache = []) {
    if (obj === null || typeof obj !== 'object') {
        return obj;
    }
    
    const objType = Object.prototype.toString.call(obj).slice(8, -1);

    
    // 考虑 正则对象的copy
    if (objType === 'RegExp') {
        return new RegExp(obj);
    }

    // 考虑 Date 实例 copy
    if (objType === 'Date') {
        return new Date(obj);
    }

    // 考虑 Error 实例 copy
    if (objType === 'Error') {
        return new Error(obj);
    }

    const hit = cache.filter((c) => c.original === obj)[0];

    if (hit) {
        return hit.copy;
    }

    const copy = Array.isArray(obj) ? [] : {};

    cache.push({original: obj, copy});

    Object.keys(obj).forEach((key) => {
        copy[key] = deepCopy(obj[key], cache);
    });

    return copy;
}

// JSON.parse(JSON.stringify())
// 1. 循环引用的问题,会直接报错
// 2. 函数,undefined,则序列化的结果会把函数或 undefined丢失
// 3. RegExp、Error对象会被转换成'{}'空对象 
// 4. 如果obj里面有时间对象,则JSON.stringify后再JSON.parse的结果,时间将只是字符串的形式。而不是时间对象;
// 5. 如果obj里有NaN、Infinity和-Infinity,则序列化的结果会变成null
// 6. JSON.stringify()只能序列化对象的可枚举的自有属性,
// 例如 如果obj中的对象是有构造函数生成的,
// 则使用JSON.parse(JSON.stringify(obj))深拷贝后,
// 会丢弃对象的constructor;
// 7. 原型链丢失

//
// 浅拷贝
// 1. Object.assign({a: 1}, {b: 1}, {c: 1}) === "{a: 1, b: 1, c: 1}"
// 2. 可扩展运算符 [...[{}, {}]], {...{a: 1, b: 1}}
// 3. 数组的 concat, slice 返回值
// 4. 函数参数赋值((obj) => console.log(obj))(myobj)
// 5. 数组,对象的解构赋值等

5. 获取一个字符串的后十位

主要时slice方法的熟练程度

// str = '012345678954321';
// str.slice(-10); // => '5678954321'

6. lodash 性能问题

7. 空对象和空数组 的布尔类型

console.log('null == false', null == false); // flase
console.log('[] == false', [] == false); // true
console.log('{} == false', {} == false); // false
console.log(`[] + ''`, [] + ''); // ''
console.log(`{} + ''`, {} + ''); // [object Object]

8. 判断一个变量是否为数组或者对象


// Object.prototype.toString.call({})
// "[object Object]"
// Object.prototype.toString.call([])
// "[object Array]"
// Object.prototype.toString.call(null)
// "[object Null]"
// Object.prototype.toString.call(undefined)
// "[object Undefined]"
// Object.prototype.toString.call(1)
// "[object Number]"
// Object.prototype.toString.call(Number)
// "[object Function]"
// Object.prototype.toString.call(() =>{})
// "[object Function]"
// Object.prototype.toString.call('a')
// "[object String]"
// Object.prototype.toString.call(true)
// "[object Boolean]"
// Object.prototype.toString.call(new Set())
// "[object Set]"
// Object.prototype.toString.call(new Map())
// "[object Map]"
// Object.prototype.toString.call(Symbol())
// "[object Symbol]"

9. 如何设置cookie,防止前端写入

// 服务端接口设置
// http httpOnly: true
// https secure: true