语义:
-
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,序列化时会被忽略 }
附加信息:==和===的区别
赠送信息:??是什么?
语义:
-
StringJS内置的构造函数,用于创建字符串包装对象,转换数据类型;new String()创建的引用类型,本质是对象 -
stringJS层面是字符串原始类型,代表字符串数据;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时做类型转换 -
stringJS6种原始类型之一,不可变的,无法添加自定义属性;typeof是它的身份验证器
比喻:
-
String装着纸条的袋子 -
string纸条
类似比较:number/Number,boolean/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上的方法:
附加信息:
-
BigInt和Number的区别 -
原始值和引用值的区别
-
typeof和instanceof的区别
赠送信息:
- Unicode编码是什么?
-
Symbol的应用场景?
-
Symbol为什么有那么多属性?
-
Infinity的应用场景?
-
普通函数和箭头函数的区别?
-
虽然JS有自己的垃圾回收机制,但是我们在编写代码时还是要注意什么?
-
delete有什么作用?
-
对于V8引擎来说,隐藏类是什么?
-
什么是闭包?
-
什么是原型?
-
什么是Promise?
-
对象池的实现对性能提升有什么帮助?
-
构造函数的作用?
-
Date()详解
-
正则表达式详解
-
连个单例内置对象Global()和Math()都有哪些方法和应用场景?
-
Map()和Set()的区别?
-
WeakMap()和Map()的区别?
-
生成器是什么?
-
JavaScript面向对象编程
-
JavaScript函数式编程
-
代理与反射
-
代理的不足
-
解释
...arguments的作用 -
...的作用 -
函数名大写与小写有什么区别?
-
JS函数内部有什么方法和规范?
-
函数的递归应用
-
函数表达式的立即调用
-
异步编程
-
Promise和async有什么关系/联系
let person = new Object();
person.name = "Alice";
console.log(person.name); // Alicelet name = "Alice";
name.age = 27;
console.log(name.age); // undefined
console.log(typeof name); // stringlet name2 = new String("Bob");
name2.age = 18;
console.log(name2.age); // 18
console.log(typeof name2); // objectlet num1 = 5;
let num2 = num1;
num1 = 4;
console.log(num2); // 5let obj1 = new Object();
let obj2 = obj1;
obj1.name = "Alice";
console.log(obj2.name); // Alicefunction addTen(num) {
num += 10;
return num;
}
let count = 20;
let result = addTen(count);
console.log(count); // 20 - no change
console.log(result); // 30function 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本身的引用性,值会改变。
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); // truelet falseValue = false;
let result = falseValue && true;
console.log(result); // falseconst 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); // falseconst 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 overrideconst 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
// trueconst target = {
foo: 'bar'
}
const proxy = new Proxy(target, Reflect);
console.log(target.foo); // bar
console.log(proxy.foo); // barconst 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
// barwindow.color = 'red';
let o = {
color: 'blue';
}
function sayColor() {
console.log(this.color);
}
sayColor(); // red
o.sayColor = sayColor;
o.sayColor(); // bluewindow.color = 'red';
let o = {
color: 'blue';
}
let sayColor = () => {
console.log(this.color);
}
sayColor(); // red
o.sayColor = sayColor;
o.sayColor(); // redfunction 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闭包是能够访问另一个函数作用域内变量的函数。即函数套函数
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'这又怎么解释?
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