文章目录
- 面试版
-
- [1. 与Java语言对比](#1. 与Java语言对比)
-
- [1.1 请对比 JavaScript 和 Java 的类型系统差异,以及这种差异在 RN+Android 开发中的实际影响?](#1.1 请对比 JavaScript 和 Java 的类型系统差异,以及这种差异在 RN+Android 开发中的实际影响?)
- [1.2 谈谈 JavaScript 单线程和 Java 多线程的核心区别,以及在 RN 开发中如何利用这种差异做优化?](#1.2 谈谈 JavaScript 单线程和 Java 多线程的核心区别,以及在 RN 开发中如何利用这种差异做优化?)
- [1.3 JavaScript 的原型式面向对象和 Java 的类式面向对象有什么本质区别?在 RN 混合开发中如何体现?](#1.3 JavaScript 的原型式面向对象和 Java 的类式面向对象有什么本质区别?在 RN 混合开发中如何体现?)
- [2. 数据类型](#2. 数据类型)
- [3. 作用域与变量](#3. 作用域与变量)
-
- [3.1 var/let/const 区别](#3.1 var/let/const 区别)
- [3.2 什么是变量提升](#3.2 什么是变量提升)
- [3.3 什么是暂时性死区](#3.3 什么是暂时性死区)
- 学习版
-
- [1. 变量与作用域](#1. 变量与作用域)
-
- [1.1 let和var的区别](#1.1 let和var的区别)
- [1.2 变量提升(Hoisting)](#1.2 变量提升(Hoisting))
面试版
1. 与Java语言对比
1.1 请对比 JavaScript 和 Java 的类型系统差异,以及这种差异在 RN+Android 开发中的实际影响?
- 核心差异
JS:弱类型、动态类型 → 声明变量无需指定类型,运行时可随意修改类型(如 let a=1; a='RN' 合法),类型检查在运行时。
Java:强类型、静态类型 → 声明变量必须指定类型(如 int a=1),类型不可随意修改,编译期就做类型校验,不通过直接报错。 - 实际影响(结合 RN+Android)
开发效率 :JS 灵活,RN 业务迭代快(无需编译,热更新);Java 严谨,Android 原生模块(如 Native Module)类型安全,减少运行时崩溃。
问题排查 :JS 类型错误只有运行时才暴露(如 RN 传参类型错,App 运行才崩);Java 编译期就能发现类型问题,原生模块更稳定。
工程实践 :RN 中会用 TypeScript 弥补 JS 弱类型缺陷(接近 Java 的静态类型),既保留 JS 灵活,又降低线上问题。
1.2 谈谈 JavaScript 单线程和 Java 多线程的核心区别,以及在 RN 开发中如何利用这种差异做优化?
- 核心差异
JS:单线程 → 基于「事件循环 + 异步任务队列」实现异步 ,无并发问题,但主线程阻塞会导致页面卡顿(RN 中 JS 线程阻塞会让 UI 无响应)。
Java:多线程 → 支持真正的并行执行,可创建多线程处理耗时任务(如 Android 子线程请求网络),但需处理同步、锁、死锁问题。 - RN 优化实践
耗时操作隔离 :RN 中 JS 侧的复杂计算 / 大数据处理,丢给 Android 原生(Java 多线程)处理,避免阻塞 JS 线程。
异步通信 :JS 调用原生模块(如扫码、定位)用 Promise 异步回调,不阻塞 JS 主线程;原生侧用 Handler / 线程池处理耗时任务。
线程分工:RN 中 JS 线程处理业务逻辑,Android 主线程处理 UI 渲染,原生子线程处理耗时操作,各司其职。
1.3 JavaScript 的原型式面向对象和 Java 的类式面向对象有什么本质区别?在 RN 混合开发中如何体现?
- 核心差异
JS:原型式 OOP → 无「类」的概念 (ES6 class 是语法糖),通过「原型链 」实现继承,对象直接继承另一个对象的属性 / 方法,灵活但松散。
Java:类式 OOP → 严格的「类 - 对象」体系,先定义类(模板),再实例化对象,继承基于类的 extends,规则严谨、结构清晰。 - RN 混合开发体现
JS 侧:RN 组件(如 FunctionComponent/ClassComponent)基于 JS 原型机制,组件复用 / 扩展靠原型链或组合(而非继承),灵活适配多变的业务。
原生侧:Android 原生模块(如自定义 Native Module)基于 Java 类继承(如继承 ReactContextBaseJavaModule),结构固定、规范统一,保证桥接稳定性。
桥接层:JS 侧通过原型扩展的方法调用 Java 类实例的方法,两种 OOP 模型通过 RN 桥接机制无缝协作。
2. 数据类型
3. 作用域与变量
3.1 var/let/const 区别
var:函数作用域、变量提升、可重复声明;
let/const:块级作用域、无提升、不可重复声明;
const:声明必赋值,不能改引用(对象内容可改)
3.2 什么是变量提升
JS 编译期将变量 / 函数声明提升到作用域顶部;
var 提升声明,函数提升整个函数体;
let/const 有「暂时性死区」,无变量提升
3.3 什么是暂时性死区
JavaScript 中的 "暂时性死区"(Temporal Dead Zone, 简称 TDZ) 是指在代码中使用 let 或 const 声明变量时,从当前代码块(block)的开始到变量实际声明语句之间的区域。在这个区域内访问该变量会抛出 ReferenceError,因为变量虽然被提升了声明,但尚未被初始化。
学习版
1. 变量与作用域
1.1 let和var的区别
-
作用域(Scope):
var声明的变量是函数作用域(function-scoped),即变量在它被声明的函数内部都是可见的。let声明的变量是块作用域(block-scoped) ,即变量只在它被声明的代码块{}内可见。
-
变量提升(Hoisting):
var声明的变量会被提升(变量声明会被提升到函数或全局作用域的顶部),但其赋值不会被提升。let声明的变量也会被提升,但不会被初始化,因此在声明之前访问该变量会导致ReferenceError(称为"暂时性死区")。
-
重复声明:
- 使用
var可以在同一个作用域内多次声明同一个变量。 - 使用
let则不能在同一个作用域内重复声明同一个变量,否则会抛出错误。
- 使用
-
全局对象属性:
- 在全局作用域中使用
var声明的变量会成为window对象(浏览器环境)的属性。 - 使用
let声明的变量则不会成为window对象的属性。
- 在全局作用域中使用
示例代码
javascript
function example() {
if (true) {
var varVar = "var variable";
let letVar = "let variable";
}
console.log(varVar); // 输出 "var variable"
console.log(letVar); // 报错:letVar is not defined
}
example();
javascript
console.log(varVar); // 输出 undefined(变量提升)
var varVar = "I am var";
console.log(letVar); // 报错:Cannot access 'letVar' before initialization
let letVar = "I am let";
1.2 变量提升(Hoisting)
变量提升(Hoisting)是 JavaScript 中一种默认的行为,它将 变量和函数的声明 自动移动到当前作用域(全局作用域或函数作用域)的顶部。需要注意的是,只有声明会被提升,赋值或初始化不会被提升。
- 通俗理解:
你可以把它想象成:JavaScript 引擎在执行代码之前,会先扫描当前作用域内的所有变量和函数声明,并将它们的声明"提前"到当前作用域的顶部,然后再按顺序执行代码
var声明的变量提升
javascript
console.log(a); // 输出 undefined
var a = 10;
等价于:
javascript
var a;
console.log(a); // undefined
a = 10;
let和const的变量提升(但有"暂时性死区")
javascript
console.log(b); // 报错:Cannot access 'b' before initialization
let b = 20;
虽然 let b 也会被提升,但它不会被初始化,因此在声明之前访问会抛出错误,这个区域称为"暂时性死区(Temporal Dead Zone, TDZ)"。
- 函数声明提升
javascript
sayHello(); // 输出 "Hello"
function sayHello() {
console.log("Hello");
}
函数声明会被完整地提升,包括函数体。
- 函数表达式不会被完整提升
javascript
sayHi(); // 报错:sayHi is not a function
var sayHi = function() {
console.log("Hi");
};
这里 sayHi 是一个变量,其声明被提升,但赋值(函数表达式)不会被提升。
总结:
var声明的变量会被提升,并初始化为undefined。let和const也会被提升,但不会被初始化,访问它们会进入"暂时性死区"。- 函数声明会被完整提升,可以在声明前调用。
- 函数表达式不会被完整提升,只能在赋值后调用。