一、插件化

1.1、需要立即执行的插件「比如轮播图」

  1. // 插件化
  2. // 需要立即执行的插件,比如轮播图
  3. ;(functin(){
  4. var Slider = function(){};
  5. Slider.prototype = {
  6. }
  7. window.Slider = Slider;
  8. })();

1.2、不需要立即执行的插件

不需要立即执行的插件,我们在全局声明一个变量将其保存起来,需要执行的时候再随时调用即可

  1. // 插件化
  2. // 不需要立即执行的插件,只需要在全局声明一个变量将其保存起来;后期什么时候需要执行再调用即可
  3. var inherit = (function(){
  4. var Buffer = function(){};
  5. return function(origin, target){
  6. Buffer.prototype = origin.prototype;
  7. target.prototype = new Buffer();
  8. target.prototype.constructor = origin;
  9. target.prototype.supper_class = origin;
  10. }
  11. })();

二、三目运算符「三元运算符」

  • 基本语法: 条件判断 ? 条件成立要做的事情 条件不成立要做的事情;

    1. var a = 5;
    2. if(a > 0){
    3. console.log('大于0');
    4. }else{
    5. console.log('小于0');
    6. }
    7. // 改为三目运算符
    8. var a = 5;
    9. a > 0 ? console.log('大于0')
    10. : console.log('小于0');
  • 三元运算符有return的作用

    1. // 三元运算符有return的作用
    2. var a = 5,
    3. str;
    4. if(a > 0){
    5. str = '大于0';
    6. }else{
    7. str = '小于0'
    8. }
    9. // 改为三目运算符
    10. var a = 5;
    11. var str = a > 0 ? str = '大于0'
    12. : str = '小于0';
    13. console.log(str);

    三元运算符练习

    1. // 三元运算符的练习
    2. var a = 5,
    3. str;
    4. if(a > 0){
    5. if(a > 3){
    6. str = '大于3';
    7. }else{
    8. str = '小于等于3';
    9. }
    10. }else{
    11. str = '小于等于0'
    12. }
    13. console.log(str);
    14. // 改为三目运算符
    15. var a = 5;
    16. var str = a > 0 ? (a > 3 ? str = '大于3'
    17. : str = '小于等于3')
    18. : str = '小于等于0';
    19. console.log(str);

    三、关于字符串比较的面试题

    字符串和字符换比较,是逐位比较字符串对应的ASCII码所对应的十进制值的大小

  1. // 一道关于字符串的面试题
  2. // 字符串和字符换比较,是逐位比较字符串对应的ASCII码所对应的十进制值的大小
  3. var str = 89 > 9 ? ('89' > '9' ? '内层通过了'
  4. : '内层未通过')
  5. : '外层通过了' ;
  6. console.log(str);

四、对象的浅克隆

4.1、浅克隆之对象赋值

  • 对象浅克隆之对象赋值,这种方式严格来说不叫克隆
  • 使用对象赋值的方法,两个对象共用的是同一个堆内存地址

    1. // 对象的浅克隆和深克隆 clone
    2. // 对象的浅克隆
    3. // 对象的赋值,不叫克隆
    4. var person1 = {
    5. name: '良雨',
    6. age: 10,
    7. sex: 'male',
    8. }
    9. // 对象的赋值,共用同一个堆内存地址
    10. var person2 = person1;
    11. console.log(person2);
    12. console.log(person1 == person2);
    13. person2.age = 20;
    14. console.log(person1, person2);

    4.2、浅克隆之循环「for in」

  • 先创建一个空对象,然后把原始对象进行循环,把属性赋值给新对象

  • 注意:for in 循环会把原型及其原型链上的自定义属性或者是方法循环到 「 hasOwnProperty」
  • 浅拷贝只能处理第一层,而且并没有深层次的处理对象中的引用值

    1. // 浅克隆 for in循环的方式
    2. // 创建一个空对象,用for in循环原始对象,然后将属性名和值存入到新的对象之中
    3. // 注意:for in循环是会把原型及其原型链上的自定义的属性和方法都循环出来的
    4. var obj1 = {
    5. name: 'kola',
    6. age: 10,
    7. sex: 'male'
    8. }
    9. var obj2 = {};
    10. for(var key in obj1){
    11. obj2[key] = obj1[key];
    12. }
    13. console.log(obj2);
    14. obj2.name = 'Lucy';
    15. console.log(obj1, obj2);
  • 浅拷贝只能处理第一层,而且不能深层次处理引用值;在用for in循环的时候,会把原型及其原型链上的自定义属性和方法循环到

    1. // 浅克隆 for in循环的方式
    2. // 创建一个空对象,用for in循环原始对象,然后将属性名和值存入到新的对象之中
    3. // 注意:for in循环是会把原型及其原型链上的自定义的属性和方法都循环出来的
    4. var obj1 = {
    5. name: 'kola',
    6. age: 10,
    7. sex: 'male'
    8. }
    9. // 可能会多次用到,进行封装
    10. var obj2 = {};
    11. // for(var key in obj1){
    12. // obj2[key] = obj1[key];
    13. // }
    14. // 执行封装的clone方法
    15. clone(obj1, obj2);
    16. console.log(obj2);
    17. obj2.name = 'Lucy';
    18. console.log(obj1, obj2);
    19. // 对象浅拷贝 第一版封装
    20. // 没有考虑用户不新建空对象的情况,也没有考虑到for in的缺陷
    21. function clone(origin, target){
    22. for(var key in origin){
    23. target[key] = origin[key]
    24. }
    25. }
    26. // 浅克隆第二版封装
    27. function clone(origin, target){
    28. var target = target || {};
    29. for(var key in origin){
    30. // 提出原型及其原型链上的自定义属性和方法
    31. if(origin.hasOwnProperty(key)){
    32. target[key] = origin[key];
    33. }
    34. }
    35. return target;
    36. }

    4.3、浅克隆封装

    1. function clone(origin, target){
    2. var target = target || {};
    3. for(var key in origin){
    4. if(origin.hasOwnProperty(key)){
    5. target[key] = origin[key];
    6. }
    7. }
    8. return target;
    9. }

    4.4、浅克隆存在的问题

  • 不能深层次处理引用值

  • 只能处理第一层,出现对象嵌套的情况就无法处理了 ```javascript

    1. // 浅拷贝的问题:
    2. // + 不能深层次处理引用值
    3. // + 只能处理第一层,出现对象嵌套的情况就无法处理了
    4. Object.prototype.num = '11';
    5. var person1 = {
    6. name: 'kola',
    7. age: 18,
    8. sex: 'male',
    9. son: {
    10. first: 'Jenny',
    11. second: 'Lucy',
    12. third: 'Tone'
    13. }
    14. }
    15. // 浅克隆封装
    16. function clone(origin, target){
    17. var target = target || {};
    18. for(var key in origin){
    19. if(origin.hasOwnProperty(key)){
    20. target[key] = origin[key];
    21. }
    22. }
    23. return target;
    24. }
  1. // 调用封装好的浅克隆方法
  2. var person2 = clone(person1);
  3. console.log(person1, person2);
  4. // 浅克隆无法处理深层次的引用值
  5. person2.name = '李四';
  6. person2.son = {
  7. forth: '李小明',
  8. five: '李华'
  9. };
  10. console.log(person1, person2);
  1. <a name="Q5i7f"></a>
  2. # 五、对象的深克隆
  3. <a name="BFv2R"></a>
  4. ## 5.1、对象深克隆思路分析及其封装
  5. - 先处理用户体验 target = target || {}
  6. - 用for in遍历原始对象的属性
  7. - 在遍历原始对象属性的时候,要注意排除原型及其原型链上的自定义属性和方法「for in」会遍历到原型及其原型链上的自定义的属性和方法,可以用「hasOwnProperty」来解决
  8. - 排除完原型和原型链上的自定义方法以后,先判断对象的属性是否是引用数据类型「注意排除null」
  9. - 判断是对象之后,再看是不是数组,如果是数组就创建一个空数组,如果是对象就创建一个空对象
  10. - 使用递归,调用自己封装的这个深克隆的方法,来循环深层次的对象
  11. - 如果不是引用数据类型值,那就 target[key] = origin[key]
  12. - 最后将target返回出去
  13. ```javascript
  14. // 对象的深克隆
  15. // + 先处理用户体验 var target = target || {}
  16. // + 用for in循环原始对象,注意for in在循环的时候会把原型及其原型链上的自定义属性或者是方法循环出来,可以用hasOwnProperty来解决
  17. // + 循环完以后先判断其是否为对象,注意排除null
  18. // + 判断是否为对象以后,再判断是否是数组,如果是数组就创建一个空数组,如果是对象就创建一个空对象
  19. // + 递归循环深层次的对象 deepClone(origin[key], target[key])
  20. // + 如果不是对象就 target[key] = origin[key]
  21. // + 最后 return target
  22. // 深克隆方法封装
  23. function deepClone(origin, target){
  24. var target = target || {},
  25. toStr = Object.prototype.toString,
  26. arrType = '[object Array]';
  27. for(var key in origin){
  28. if(origin.hasOwnProperty(key)){
  29. if(typeof(origin[key]) === 'object' && origin[key] !== null){
  30. if(toStr.call(origin[key]) === arrType){
  31. target[key] = [];
  32. }else{
  33. target[key] = {};
  34. }
  35. deepClone(origin[key], target[key]);
  36. }else{
  37. target[key] = origin[key];
  38. }
  39. }
  40. }
  41. return target;
  42. }
  43. Object.prototype.num = '11';
  44. var person1 = {
  45. name: '张三',
  46. age: 18,
  47. sex: 'male',
  48. height: 180,
  49. children: {
  50. first: {
  51. name: '张一',
  52. age: 22
  53. },
  54. second: {
  55. name: '张二',
  56. age: 20
  57. },
  58. third: {
  59. name: '张三',
  60. age: 10
  61. },
  62. },
  63. car: ['Benz', 'Mazda']
  64. };
  65. var person2 = deepClone(person1);
  66. person2.name = '李四';
  67. person2.children.forth = {
  68. name: '李五',
  69. age: 8
  70. }
  71. person2.car.push('BYD');
  72. console.log(person1, person2);

5.2、对象深克隆封装的优化 「三目运算符版本」

  1. function deepClone(origin, target){
  2. var target = target || {},
  3. toStr = Object.prototype.toString,
  4. arrType = '[object Array]';
  5. for(var key in origin){
  6. if(origin.hasOwnProperty(key)){
  7. if(typeof(origin[key]) === 'object' && origin[key] !== null){
  8. toStr.call(origin[key]) === arrType ? target[key] = []
  9. : target[key] = {};
  10. deepClone(origin[key], target[key]);
  11. }
  12. }else{
  13. target[key] = origin[key];
  14. }
  15. }
  16. return target;
  17. }

5.3、利用JSON的方法

  • JSON方法是不能克隆对象上的方法的

    1. // 利用JSON的方法实现对象的克隆
    2. // JSON这个方法,是不能克隆对象上的方法的
    3. var str = JSON.stringify(person1);
    4. var person2 = JSON.perse(str);

    六、面试题

    1. // 面试题
    2. function test(){
    3. console.log(foo);
    4. var foo = 2;
    5. console.log(foo);
    6. console.log(a);
    7. }
    8. test();
    9. console.log(a);
    10. console.log(typeof(a));

    函数预编译

  • 寻找形参和变量声明

  • 统一形参和实参的值
  • 寻找函数声明并赋值
  • 执行

    1. // 面试题
    2. // 预编译阶段
    3. // + 寻找形参和变量声明
    4. // + 统一形参和实参的值
    5. // + 寻找函数声明并赋值
    6. // + 执行
    7. function a(){
    8. var test;
    9. test();
    10. function test(){
    11. console.log(1);
    12. }
    13. }
    14. a();

    this指向的面试题「做错两遍了重点注意」

    1. // 面试题
    2. var name = '222';
    3. var a = {
    4. name: '111',
    5. say: function(){
    6. console.log(this.name);
    7. }
    8. }
    9. var func = a.say;
    10. // say: function(){
    11. // console.log(this.name);
    12. // }
    13. func(); // '222'
    14. a.say(); // '111'
    15. var b = {
    16. name: '333',
    17. say: function(){
    18. func();
    19. }
    20. }
    21. b.say(a.say); // '333' 错的
    22. b.say = a.say;
    23. b.say(); // '333'

    this指向和call/apply面试题

    1. // this指向和call/apply面试题
    2. function test(){
    3. var marty = {
    4. name: 'marty',
    5. printName: function(){
    6. console.log(this.name);
    7. }
    8. }
    9. var test1 = {
    10. name: 'test1'
    11. };
    12. var test2 = {
    13. name: 'test2'
    14. };
    15. var test3 = {
    16. name: 'test'
    17. };
    18. test3.printName = marty.printName;
    19. marty.printName.call(test1);
    20. marty.printName.call(test2);
    21. marty.printName();
    22. test3.printName();
    23. }
    24. test();

    面试题「做错了留意一下」

    1. // 面试题
    2. var bar = {
    3. a: '1'
    4. };
    5. function test(){
    6. bar.a = 'a';
    7. Object.prototype.b = 'b';
    8. return function inner(){
    9. console.log(bar.a);
    10. console.log(bar.b);
    11. }
    12. }
    13. test()();

    七、一道超难的面试题

    做错了无数遍,需要留意 ```javascript

    1. // 作业:说出为什么
    2. function Foo(){
    3. getName = function(){
    4. console.log(1);
    5. };
    6. return this;
    7. }
    8. Foo.getName = function(){
    9. console.log(2);
    10. };
    11. Foo.prototype.getName = function(){
    12. console.log(3);
    13. };
    14. var getName = function(){
    15. console.log(4);
    16. };
    17. function getName(){
    18. console.log(5);
    19. }
  1. Foo.getName(); // 2
  2. getName(); // 4
  3. Foo().getName(); // 1
  4. getName(); // 1
  5. new Foo.getName(); // 2
  6. new Foo().getName(); // 3
  7. new new Foo().getName(); // 3
  8. // 1. 寻找变量声明
  9. // 2. 寻找函数声明并赋值
  10. // 3. 执行赋值
  11. // 优先级问题: () > . > new
  12. GO = {
  13. Foo: function(){...}
  14. getName: // undefined
  15. // function (){console.log(1)}
  16. }
  1. [JS运算符优先级](https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Operators/Operator_Precedence#%E6%B1%87%E6%80%BB%E8%A1%A8)
  2. <a name="vlkUQ"></a>
  3. # 八、作业
  4. window.prompt输入一个年份,判断其是否是闰年「请用三目运算符」
  5. ```javascript
  6. // 第十四课时作业:从wp输入一个年份,判断是否是闰年
  7. var year = window.prompt('请输入年份');
  8. function isLeapYear(year){
  9. var year = Number(year);
  10. if((year % 4 === 0 && year % 100 !== 0) || year % 400 === 0){
  11. return '闰年';
  12. }else{
  13. return '不是闰年';
  14. }
  15. }
  16. console.log(isLeapYear(year));
  17. // 三目运算符版
  18. var year = window.prompt('请输入年份');
  19. function isLeapYear(year){
  20. var year = Number(year);
  21. return year = ((year % 4 === 0 && year % 100 !== 0) || year % 400 === 0) ? '闰年'
  22. : '不是闰年';
  23. }
  24. console.log(isLeapYear(year));