Skip to content

Latest commit

 

History

History
573 lines (416 loc) · 10.7 KB

File metadata and controls

573 lines (416 loc) · 10.7 KB

ES

undefined和null的区别?

语义:

  • undefined 逻辑上不存在

  • null 存在但是为空

产生:

  • undefined 由语言引擎自动分配

  • null 由开发者显式赋值

相同:都是独立原始类型

ECMA-262:

  • undefined 未初始化的变量值

  • null 空引用指针

比喻:

  • undefined 不存在的文件夹

  • null 存在但为空的文件夹

应用场景:

  • undefined 默认占位、函数默认返回值

    // 默认占位
    function greet(name = "陌生人") {
        return console.log(`你好,${name}`);
    }
    
    
    greet(); // 你好,陌生人
    greet(undefined); // 你好,陌生人
    
    
    function fn(a = "陌生人", b) {
        console.log(a);
        console.log(b);
    }
    
    fn(undefined, "你好"); // 陌生人; 你好;
    
    // 函数默认返回值
    function emptyReturn() {
        return;
    }
    
    console.log(emptyReturn()); // undefined
  • null 初始化引用类型变量、函数返回无有效结果、释放对象引用、JSON序列化时保留空值字段

    // 初始化引用类型
    let user = null;
    let todoList = null;
    
    
    user = fetchUser();
    todoList = getTodos();
    
    // 返回无有效结果
    function getUserById(id) {
        const user = users.find(u => u.id === id);
        return user || null;
    }
    
    // 释放引用
    user = null
    
    
    // JSON序列化保留空值字段
    const user = {
        name: "张三",
        age: 18,
        address: null // 如果是undefined,序列化时会被忽略
    }

附加信息:=====的区别

赠送信息:??是什么?


String和string的区别?

语义:

  • String JS内置的构造函数,用于创建字符串包装对象,转换数据类型;new String()创建的引用类型,本质是对象

  • string JS层面是字符串原始类型,代表字符串数据;TS层面是类型注解,用于限制变量必须是字符串原始类型

产生:

  • String 两种核心方式,区别在于是否使用new关键字

    const strObj = new String('hello');
    console.log(strObj); // String {"hello"}
    console.log(typeof strObj); // object
    
    
    const strPrim = String(123);
    console.log(strPrim); // "123"
    console.log(typeof strPrim); // string
  • string 直接给变量赋值字符串即可;用于类型声明

    let name: string = "张三";

相同:都能调用String.prototype 上的方法,因为string会自动触发装箱,即临时转换成String包装对象。

ECMA-262:

  • String 内置对象,用于创建字符串对象;使用new时返回一个包含变量值的对象,不使用new时做类型转换

  • string JS6种原始类型之一,不可变的,无法添加自定义属性;typeof 是它的身份验证器

比喻:

  • String 装着纸条的袋子

  • string 纸条

类似比较:number/Numberboolean/Boolean

String.prototype上的方法(还有Number和Boolean):(toString()和toLocalString()的区别和用法?)

// String.pototype
const str = "abcdef";

str.slice(1, 4); // "bcd"
str.slice(-2); // "ef"
str.subString(4, 1); // "bcd" 自动修正索引顺序
str.indexOf('c'); // 2
str.include('de'); // true
str.chatAt(1); // "b"
str.startWith('abc'); // true endWith同理
str.charCodeAt(1); // 查询“b”的Unicode编码

// 还可以查询表情和符号的Unicode码点
'😀'.codePointAt(0); // 128512

// 字符串替换/修改

同理:Array上的方法:

附加信息:

  • BigIntNumber的区别

  • 原始值和引用值的区别

  • typeof和instanceof的区别

赠送信息:

  • Unicode编码是什么?

  • Symbol的应用场景?

  • Symbol为什么有那么多属性?

  • Infinity的应用场景?

  • 普通函数和箭头函数的区别?

  • 虽然JS有自己的垃圾回收机制,但是我们在编写代码时还是要注意什么?

  • delete有什么作用?

  • 对于V8引擎来说,隐藏类是什么?

  • 什么是闭包?

  • 什么是原型?

  • 什么是Promise?

  • 对象池的实现对性能提升有什么帮助?

  • 构造函数的作用?

  • Date()详解

  • 正则表达式详解

  • 连个单例内置对象Global()和Math()都有哪些方法和应用场景?

  • Map()和Set()的区别?

  • WeakMap()和Map()的区别?

  • 生成器是什么?

  • JavaScript面向对象编程

  • JavaScript函数式编程

  • 代理与反射

  • 代理的不足

  • 解释...arguments的作用

  • ...的作用

  • 函数名大写与小写有什么区别?

  • JS函数内部有什么方法和规范?

  • 函数的递归应用

  • 函数表达式的立即调用

  • 异步编程

  • Promise和async有什么关系/联系

PRIMITIVE AND REFERENCE VALUES

let person = new Object();
person.name = "Alice";
console.log(person.name); // Alice
let name = "Alice";
name.age = 27;
console.log(name.age); // undefined
console.log(typeof name); // string
let name2 = new String("Bob");
name2.age = 18;
console.log(name2.age); // 18
console.log(typeof name2); // object
let num1 = 5;
let num2 = num1;
num1 = 4;
console.log(num2); // 5
let obj1 = new Object();
let obj2 = obj1;
obj1.name = "Alice";
console.log(obj2.name); // Alice
function addTen(num) {
  num += 10;
  return num;
}
let count = 20;
let result = addTen(count);
console.log(count); // 20 - no change
console.log(result); // 30
function setName(obj) {
  obj.name = "Alice";
}
let person = new Object();
setName(person);
console.log(person.name); // "Alice"
function setName(obj) {
  obj.name = "Alice";
  obj = new Object();
  obj.name = "Greg";
}
let person = new Object();
setName(person);
console.log(person.name); // "Alice"

由此可见,即使是object类型,在函数内也是按值传递的,而不是按引用,不然打印的就是Greg了,不过由于object本身的引用性,值会改变。

Basic Reference Types

let value = "25";
let number = Number(value);
console.log(typeof number); // "number"
let value = "25";
let obj = new Number(value);
console.log(typeof obj); // "object"
let falseObject = new Boolean(false);
let result = falseObject && true;
console.log(result); // true
let falseValue = false;
let result = falseValue && true;
console.log(result); // false

Proxies and Reflect

const target = {
    id: 'target'
}
const handler = {};
const proxy = new Proxy(target, handler);
console.log(target.id); // target
console.log(proxy.id); // target
target.id = 'foo';
console.log(target.id); // foo
console.log(proxy.id); // foo
proxy.id = 'bar';
console.log(target.id); // bar
console.log(proxy.id); // bar
console.log(target.hasOwnProperty('id')); // true
console.log(proxy.hasOwnProperty('id')); // true
console.log(target === proxy); // false
const target = {
    foo: 'bar'
};
const handler = {
    get() {
        return 'handler override';
    }
};
const proxy = new Proxy(target, handler);
console.log(target.foo); // foo
console.log(proxy.foo); // handler override
const target = {
    foo: 'bar'
};
const handler = {
    get(trapTarget, property, receiver) {
        console.log(trapTarget === target);
        console.log(property);
        consolr.log(receiver === proxy);
    }
}
const proxy = new Proxy(target, handler);
proxy.foo;
// true
// foo
// true
const target = {
    foo: 'bar'
}
const proxy = new Proxy(target, Reflect);
console.log(target.foo); // bar
console.log(proxy.foo); // bar
const target = {
    foo: 'bar',
    baz: 'qux',
}

const handler = {
    get(trapTarget, property, receiver) {
        let decoration = '';
        if (property === 'foo') {
            decoration = '!!!';
        }
        return Reflect.get(...arguments) + decoration;
    }
}
const proxy = new Proxy(target, handler);
console.log(proxy.foo); // bar!!!
console.log(target.foo); // bar
console.log(proxy.baz); // qux
console.log(target.baz); // qux

在外部的改变target和proxy是同步的,说明它们是相同的引用,但是proxy内部的返回值改变了,只能改变proxy本身。

handler是一个陷阱函数,proxy的意义是拦截target,对target的值进行处理。如果target不可写,那么proxy就会报错。

const target = {
    foo: 'bar'
};
const firstProxy = new Proxy(target, {
    get() {
        console.log('first proxy');
        retrun Reflect.get(...arguments);
    }
});
const secondProxy = new Proxy(firstProxy, {
    get() {
        console.log('second proxy');
        return Reflect.get(...arguments);
    }
})
console.log(secondProxy.foo);
// second proxy
// first proxy
// bar

this

window.color = 'red';
let o = {
    color: 'blue';
}
function sayColor() {
    console.log(this.color);
}
sayColor(); // red
o.sayColor = sayColor;
o.sayColor(); // blue
window.color = 'red';
let o = {
    color: 'blue';
}
let sayColor = () => {
    console.log(this.color);
}
sayColor(); // red
o.sayColor = sayColor;
o.sayColor(); // red
function King() {
    this.royaltyName = 'Henry';
    setTimeout(() => console.log(this.royaltyName), 1000);
}


function Queen() {
    this.royaltyName = 'Elizabeth';
    setTimeout(function() {console.log(this.royaltyName)}, 1000);
}


new King(); // Henry
new Queen(); // undefined

CLOSURES

闭包是能够访问另一个函数作用域内变量的函数。即函数套函数

window.identity = 'The Window';
let object = {            
    identity: 'My Object',
    getIdentityFunc() {
        return function() {
            return this.identity;
        };
    }
};
console.log(object.getIdentityFunc()()); // 'The Window'

这怎么解释?

window.identity = 'The Window';
let object = {    
    identity: 'My Object',
    getIdentityFunc() {
        let that = this;
        return function() {
            return that.identity;
        };    
    }
};
console.log(object.getIdentityFunc()()); // 'My Object'

这又怎么解释?

Promises and Async/Await

function double(value, callback) {
    callback(value * 2);
}

double(3, (x) => console.log(x));
function double(value, success, failure) {
    try {
        success(2 * value);
    } catch (e) {
        failure(e);
    }
}

const successCallback = (x) => console.log(`Success: ${x}`);
const failureCallback = (e) => console.log(`Failure: ${e}`);

一个函数只需要做好自己的函数名应该完成的功能即可,至于如何处理完成后的结果,交给其他函数。

不过上述操作不够线性,来来回回的,使用Promise会简单很多。

async function foo() {
    console.log(1);
    return 3;
} 
foo().then(console.log);
console.log(2);
// 1
// 2
// 3