面试宝典. jpeg
本系列文章针对目前常见的面试题, 仅提供了相应的核心原理及思路, 部分边界细节未处理. 后续会持续更新, 希望对你有所帮助.
这是今天的题目, 你可以先思考一下, 然后重点关注不熟悉的~
JS 中基本数据类型有哪几种? 基本数据和复杂数据类型有什么区别?
JavaScript 中什么是闭包? 写出一个例子
如何正确判断 this 的指向?(注意区分严格模式和非严格模式)?
说一下对 call,apply,bind 三个函数的认识? 自己实现一下 bind 方法
JavaScript 实现一个继承方法
逐个击破
1.JS 中数据类型有哪几种? 有什么区别?
最新的 ECMAScript 标准定义了 7 种数据类型:
简单 (基本) 数据类型 Undefined,Null,Boolean,Number,String, Symbol 类型(ES6 新增)
复杂数据类型: Object
注意一下两种特殊类型:
Unndefined 类型: 该类型只有一个值, 即特殊的 undefined. 在使用 var 声明变量但未对其加以初始化时, 这个变量的值就是 undefined. 无论在什么情况下都没有必要把一个变量的值显式地设置为 undefined.
Null 类型: 该类型同样只有一个值, 即 null. 从逻辑角度来看, null 表示一个空指针对象, 而这也正式使用 typeof 操作符检测 null 值时会返回 object 的原因. 事实上, undefined 值是派生自 null 值的.
基本数据和复杂数据类型的区别
基本类型值: 指的是保存在栈内存中的简单数据段;
引用类型值(复杂数据): 指的是那些保存在堆内存中的对象, 意思是, 变量中保存的实际上只是一个指针, 这个指针指向内存堆中实际的值;
两种访问方式的区别
基本类型值: 按值访问, 操作的是他们实际保存的值;
引用类型值: 按引用访问, 当查询时, 我们需要先从栈中读取内存地址, 然后再顺藤摸瓜地找到保存在堆内存中的值;
栈和堆. jpeg
两种类型复制的区别
基本类型变量的复制:
从一个变量向一个变量复制时, 会在栈中创建一个新值, 然后把值复制到为新变量分配的位置上, 改变源数据不会影响到新的变量(互不干涉);
引用类型变量的复制:
复制的是存储在栈中的指针, 将指针复制到栈中为新变量分配的空间中, 而这个指针副本和原指针执行存储在堆中的同一个对象, 复制操作结束后, 两个变量实际上将引用同一个对象; 因此改变其中的一个, 将影响另一个;
2.JavaScript 中什么是闭包? 写出一个例子?
闭包就是定义在函数内部, 能够读取其他函数内部变量的函数.
举例: 用闭包实现一个计数器
- function createCounter() {
- let counter = 0;
- return function () {
- counter = counter + 1;
- return counter
- };
- }
- const increment = createCounter();
- const c1 = increment();
- const c2 = increment();
- const c3 = increment();
- console.log('example increment', c1, c2, c3);//1,2,3
闭包的用途:
可以读取函数内部的变量,
让这些变量的值始终保持在内存中.
使用闭包注意点
由于闭包会使得函数中的变量都被保存在内存中, 内存消耗很大
闭包会在父函数外部, 注意不能随便改变父函数内部变量的值
还有疑问的话可以查看我这篇文章[JS 基础系列] 带你深入理解闭包
3. 如何正确判断 this 的指向(注意区分严格模式和非严格模式)?
this 的指向总共可以分为五种:
默认绑定(非严格模式 - Windows, 严格模式 - undefined)
隐式绑定(一般是上下文, 特殊情况指向 Windows 或者 undefined)
显式绑定(指向绑定的对象, 特殊情况指向 Windows 或者 undefined)
new 绑定(一般指向新对象, 但是返回 function 或 object 时, 指向返回的对象)
箭头函数绑定(指向上下文中的 this)
还有疑问的话可以查看我这篇文章[JS 基础系列] 如何正确判断 this 的指向?
4. 说一下对 call,apply,bind 三个区别? 自己实现一下 bind 方法
在 JS 中, call,apply 和 bind 是 Function 对象自带的三个方法, 这三个方法的主要作用是改变函数中的 this 指向.
call,apply,bind 方法的共同点和区别:
三者都是用来改变函数的 this 对象的指向的;
三者第一个参数都是 this 要指向的对象, 也就是想指定的上下文(函数的每次调用都会拥有一个特殊值 -- 本次调用的上下文(context)-- 这就是 this 关键字的值.);
三者都可以利用后续参数传参;
bind 是返回对应函数, 便于稍后调用; apply ,call 则是立即调用 .
apply,call 二者而言, 作用完全一样, 只是接受参数的方式不太一样.
- var func = function(arg1, arg2) {
- };
- func.call(this, arg1, arg2);
- func.apply(this, [arg1, arg2])
- func.bind(this, arg1, arg2)()
其中 this 是你想指定的上下文, 他可以是任何一个 JavaScript 对象(JavaScript 中一切皆对象),call 需要把参数按顺序传递进去, 而 apply 则是把参数放在数组里.
下面自己实现一个 bind 方法:
- Function.prototype.bind2 = function (context) {
- if (typeof this !== "function") {
- throw new Error("Function.prototype.bind - what is trying to be bound is not callable");
- }
- var self = this;
- var args = Array.prototype.slice.call(arguments, 1);
- var fNOP = function () {};
- var fBound = function () {
- var bindArgs = Array.prototype.slice.call(arguments);
- return self.apply(this instanceof fNOP ? this : context, args.concat(bindArgs));
- }
- fNOP.prototype = this.prototype;
- fBound.prototype = new fNOP();
- return fBound;
- }
还有疑问的话可以查看我这篇文章[JS 基础系列] bind 方法的模拟实现
5.JS 实现一个继承方法
- // 借用构造函数继承实例属性
- function Child () {
- Parent.call(this)
- }
- // 寄生继承原型属性
- (function () {
- let Super = function () {}
- Super.prototype = Parent.prototype
- Child.prototype = new Super()
- })()
恭喜你, 又掌握了一个新技能~
喜欢就点个关注吧~
来源: http://www.jianshu.com/p/b3780dfd60a2