共计 5249 个字符,预计需要花费 14 分钟才能阅读完成。
1. 如何对一个数组进行去重 / 排序?
去重:
除了罕用的双重循环,还有两种办法
办法一:遍历该数组,利用 indexOf()办法判断新数组中是否存在,不存在就 push 到新驻足中,代码如下:
1. var arr = ['a', 'b', 'b', 'c', 'c', 'd'];
2. var newArr = [];
3. for (var i = 0; i < arr.length; i++) {4. if (newArr.indexOf(arr[i]) == -1) {5. newArr.push(arr[i]);
6. }
7. }
办法二:通过 es6 中的 set 数据结构,对数组去重
1. var setNum = new Set(arr);
2. Array.from(setNum);
4. // 或者用 rest 参数
5. [...setNum]
排序:
办法一:利用数组的 sort()办法排序,如果调用该办法时没有应用参数,是依照字符编码的程序进行排序,并不是数字大小排序。
1. var arr = [5, 1, 3, 6, 8, 12];
2. arr.sort(); //[1, 12, 3, 5, 6, 8]
4. arr.sort(function (a, b) {
5. return a - b;
6. });
7. console.log(arr); //[1, 3, 5, 6, 8, 12]
办法二:双重循环,冒泡排序
1. var arr2 = [5, 1, 3, 6, 8, 2, 14, 17];
2. for(var i = 0; i < arr2.length - 1; i++) {3. for(var j = 0; j < arr2.length - 1 - i; j++) {4. if (arr2[j] > arr2[j + 1]) {5. var item = arr2[j];
6. arr2[j] = arr2[j + 1];
7. arr2[j + 1] = item;
8. }
9. }
10. }
11. console.log(arr2); //[1, 2, 3, 5, 6, 8, 14, 17]
还有数组排序的其余几种算法,能够参考:https://www.cnblogs.com/real-me/p/7103375.html
2. 什么是简略类型(原始类型 primitive type),什么是简单类型(合成类型 complex type 或援用类型)。
原始类型就是间接存储在栈中的数据,是最根本的数据类型,不能够再分了。
- 数值(number):整数和小数(比方
1
和3.14
) - 字符串(string):文本(比方
Hello World
)。 - 布尔值(boolean):示意真伪的两个非凡值,即
true
(真)和false
(假) undefined
:示意“未定义”或不存在,即因为目前没有定义,所以此处临时没有任何值null
:示意空值,即此处的值为空。- Symbol:示意举世无双的,是 es6 中新增的类型
简单类型就是指存储在堆中的数据。罕用简单类型如下:
- 数组(Array): 存储一系列的值
- 日期(Date):用于解决日期和工夫
- 算数(Math):执行一般的算数工作
- 正则表达式(RegExp): 形容了字符的模式对象
3. 深拷贝与浅拷贝的区别,如何进行深拷贝?
深拷贝和浅拷贝都是针对简单类型的,简略类型没有深浅拷贝之分。
对于仅仅是复制了援用(地址),换句话说,复制了之后,原来的变量和新的变量指向同一个货色,彼此之间的操作会相互影响,为 浅拷贝。
而如果是在堆中从新分配内存,领有不同的地址,然而值是一样的,复制后的对象与原来的对象是齐全隔离,互不影响,为 深拷贝。
深浅拷贝 的次要区别就是:复制的是援用(地址) 还是复制的是实例。
那么如何进行深拷贝呢?
办法一:利用 jQuery 中的 extend()办法实现深拷贝
_$_.extend([deep], target, object1 [, objectN] )
deep:示意是否深度合并对象,为 true 是就是神拷贝
target Object 类型 指标对象,其余对象的成员属性将被附加到该对象上。
object1 objectN可选。Object 类型 第一个以及第 N 个被合并的对象。
1. var obj = {name:'ming',age:19,company : { name : 'RNG', address : '北京'} };
2. var obj_extend = $.extend(true,{}, obj);
3. console.log(obj === obj_extend); //false
extend()办法能够参考菜鸟教程:http://www.runoob.com/jquery/misc-extend.html
办法二:利用 JSON 对象的 parse 和 stringify 办法
1. var obj = {name:'xixi',age:20,company : { name : '腾讯', address : '深圳'} };
2. var obj_json = JSON.parse(JSON.stringify(obj));
3. console.log(obj === obj_json); //false
办法三:es6 中的 rest 参数
var aa = [...array]; //es6
办法四:利用 递归 来实现深复制,对属性中所有援用类型的值,遍历到是根本类型的值为止。
1. function deepClone(source){2. if(!source && typeof source !== 'object'){3. throw new Error('error arguments', 'shallowClone');
4. }
5. var targetObj = Array.isArray(source) ? [] : {};
6. for(var keys in source){7. if(source.hasOwnProperty(keys)){8. if(source[keys] && typeof source[keys] === 'object'){9. targetObj[keys] = deepClone(source[keys]); // 递归
10. }else{11. targetObj[keys] = source[keys];
12. }
13. }
14. }
15. return targetObj;
16. }
留神 :Array 对象的 slice() 和 concat()办法不是真正的深拷贝。
参考自知乎:https://zhuanlan.zhihu.com/p/26282765(这里具体写了深浅拷贝的原理,此处不再赘述)
4. 说几个罕用的数组 / 字符串的原生办法
数组:
- splice() 办法可删除从 index 处开始的零个或多个元素,并且用参数列表中申明的一个或多个值来替换那些被删除的元素。如果从 arrayObject 中删除了元素,则返回的是含有被删除的元素的数组。
- reverse() 办法用于颠倒数组中元素的程序。该办法会扭转原有数组。
- slice()办法 返回一个新的数组,蕴含从 start 到 end(不包含该元素)的 arrayObject 中的元素。
- join() 办法用于把数组中的所有元素放入一个字符串。元素是通过指定的分隔符进行分隔的。
字符串:
- indexOf() 办法可返回某个指定的字符串值在字符串中首次呈现的地位。没有则返回 -1。
- split() 办法用于把一个字符串宰割成字符串数组。
- slice() 办法可提取字符串的某个局部,并以新的字符串返回被提取的局部。
- substring() 办法用于提取字符串中介于两个指定下标之间的字符。
5. 面向对象的继承有几种形式?
形式一:原型链继承
批改子类的 prototype 为父类,这样会使子类的原型对象的 constructor 变成了父类,也能够手动批改回来
子类.prototype=new 父类 ();
子类.prototype.constructor= 子类;
特点:
(1)十分纯正的继承关系,实例是子类的实例,也是父类的实例
(2) 继承父类自身的属性 / 办法、父类原型属性 / 办法、父类新增原型办法 / 原型属性
(3) 无奈实现多继承
(4) 创立子类实例时,无奈向父类构造函数传参
(5) 子类的一个实例属性值扭转时,会影响所有子类的实例属性。因为所有子类的 prototype 指向父类(new 父类),所有没有设置本人的属性的子类的实例属性都会扭转。
然而如果是子类的一个实例属性从新赋值(子类的实例设置了本人的属性),则不会影响其余实例的属性。
1. function A(){
2. this.aNum=1;
3. }
4. A.prototype.getaNum= function () {5. console.log(this.aNum);
6. }
8. B.prototype=new A();
9. var b=new B();
10. console.log(b.aNum); // 父类自身的属性和办法
11. b.getaNum(); // 原型链上的属性和办法
形式二:构造函数继承(对象假冒)
子类调用父类的构造函数,并且把 this 传进去,
子类函数中:父类.call(this);
子类函数中:父类.apply(this);
特点:
(1)只继承父类构造函数中的属性和办法, 不能继承原型属性 / 办法。
(2)能够实现多重继承(call/apply 多个父类对象)
(3)实例只是子类的实例,不是父类的实例。
(4)创立子类实例时,能够向父类传递参数
(5) 无奈实现函数复用,每个子类都有父类实例函数的正本,影响性能
1. function E(num){
2. this.eNum = num;
3. this.geteNum = function () {4. alert(this.eNum);
5. }
6. }
8. function F(num){9. E.call(this, num);
10. }
12. var f=new F(5);
13. f.geteNum();
形式三:组合式继承
通过调用父类结构,继承父类的属性并保留传参的长处,而后通过将父类实例作为子类原型,实现函数复用
特点:
(1)既能够继承父类自身的属性 / 办法,也能够继承原型属性 / 办法
(2) 既是子类的实例,也是父类的实例
(3) 不存在子类的一个实例属性值扭转时,会影响所有子类的实例属性的问题。
每创立一个子类对象实例,就调用父类的构造函数并且将实例对象作为 this 值传过来,所以每个实例对象都有本人的属性值。
(4)可传参
(5) 函数可复用
(6) 调用了两次父类构造函数,生成了两份实例(子类实例将子类原型上的那份屏蔽了)
1. function G(){
2. this.gNum = 6;
3. }
4. G.prototype.getgNum = function () {5. console.log(this.gNum);
6. }
8. function H(){9. G.call(this);
10. }
11. H.prototype = new G();
13. var h = new H();
14. console.log(h.gNum);
15. h.getgNum();
6. 面向对象中的 this 代表什么,可否举例说明?
this 是一个指针,this 总是指向调用办法的对象,作为办法调用,那么 this 就是指实例化的对象。
举例说明:jQuery 中的链式调用,就是 this 对象的利用。
*7.说一下 事件委派(事件委托)的原理*
通事件委派的原理是事件冒泡机制,通过给父标签绑定事件,而后利用事件冒泡的景象使得点击子元素的时候,能够触发事件达到给子元素绑定事件的成果。
Event 对象提供了一个属性叫 target,示意为以后的事件操作的 dom,这个属性是有兼容性的,规范浏览器用 event.target,IE 浏览器用 event.srcElement。
长处:1. 能够大量节俭内存占用,缩小事件注册。比方 ul 上代理所有 li 的 click 事件。
2. 能够实现当新增子对象时,无需再对其进行事件绑定,对于动静内容局部尤为适合。
8.window 的 ready 与 onload 事件的区别,执行的先后顺序是什么?**
ready,示意文档构造(DOM 构造)曾经加载实现(不蕴含图片等非文字媒体文件),
onload,批示页面蕴含图片等文件在内的所有元素都加载实现。
能够说:ready 在 onload 前加载!!!
9. 如何判断一个数据是不是数组?
通过 typeof 检测数组,失去的构造是 object,并不能辨别是不是数组,咱们能够通过以下几种办法来判断一个数据是不是数组。
办法一:instanceof 用来判断一个对象是否存在于另一个对象的原型链上。
1. var str=["aa", "bb", "cc"];
2. console.log(str instanceof Array); //true
办法二:isArray 函数
1. var arr=["aa", "bb", "cc"];
2. console.log(Array.isArray(arr)); //true
办法三:constructor 属性返回对创立此对象的函数的援用, 应用此属性能够检测数组类型。
1. var arr=["aa", "bb", "cc"];
2. if(arr.constructor===Array){3. console.log('array');
4. }
5. //array