JS高级
1、面向过程 / 面向对象
面向过程就是分析出解决问题所需要的步骤,然后用函数把这些步骤一步一步实现,使用的时候再一个一个的依次调用就可以了。 冰箱打开->大象进去->冰箱关闭
优点︰性能比面向对象高,适合跟硬件联系很紧密的东西,例如单片机就采用的面向过程编程。
缺点:没有面向对象易维护、易复用、易扩展
面向对象是把事务分解成为一个个对象,然后由对象之间分工与合作。 大象:1进去;冰箱:2打开、3关闭: 2->1->3
面向对象特性:封装性、继承性、多态性。
优点:易维护、易复用、易扩展,由于面向对象有封装、继承、多态性的特性,可以设计出低耦合的系统,使系统更加灵淞更加易于维护
缺点∶性能比面向过程低
2、ES6中的类和对象
面向对象的思维特点:
1.抽取(抽象)对象共用的属性和行为组织(封装)成一个类(模板)
2.对类进行实例化,获取类的对象
面向对象编程我们考虑的是有哪些对象,按照面向对象的思维特点,不断的创建对象,使用对象指挥对象做事情
在JavaScript中,对象是一组无序的相关属性和方法的集合,所有的事物都是对象,例如字符串、数值、数组、函数等。对象由属性和方法构成。
ES6中类没有变量提升,所以必须先定义类,然后再实例化。类里面共有属性和方法都要加this指向类内
3、创建类/封装
        class Star {           //构造
            constructor(uname) {
                this.name = uname;    //this指向实例对象ldh
            }
       say(song){
          console.log(this);      //这里this指向调用者ldh
          console.log(song);
       }
        }
        var ldh = new Star('ldh');   //new调用
        console.log(ldh);
      ldh.say('by');
4、继承
class F { constructor(x, y) { this.x = x; this.y = y; } sum() { console.log(this.x + this.y); } } class S extends F { constructor(x, y) { this.x = x; this.y = y; } } var ldh = new F(1, 2); ldh.sum(); var zxy = new S(1, 2); zxy.sum(); //调用父类内的子类时,其this的指向为子类constructor,调用的方法采用就近原则,先搜索子类内有无,在搜索父类。此处的this指向为父类,会报错
修订后的子类:
class S extends F {
            constructor(x, y) {
                super();    //super调用父类constructor。若想拓展子类,即子类有父类属性,也有自己属性,得先super父类,再设置自己的属性    
          this.x = x;
          this.y = y;    //先super父类才不会报错
            }
      say(){
         super();     //也可调用父类的函数
      }
        }
5、ES5中构造函数和原型
A、构造函数是一种特殊的函数,主要用来初始化对象,即为对象成员变量赋初始值,它总与new一起使用。我们可以把对象中一些公共的属性和方法抽取出来,然后封装到这个函数里面。
new在执行时会做四件事情:
  1、在内存中创建一个新的空对象。
  2、让this指向这个新的对象。
  3、执行构造函数里面的代码,给这个新对象添加属性和方法。
  4、返回这个新对象(所以构造函数里面不需要return )。
B、构造函数内成员:
1、构造函数内的实例成员是通过this添加的成员,只能由实例化的对象来访问。
2、在构造函数本身添加的成员叫静态成员,只能用过构造函数访问;
C、构造函数:浪费内存,不同对象相同方法需要开辟不同的新内存空间;
解决方法:prototype。JavaScript规定,每一个构造函数都有一个prototype属性,指向另一个对象。注意这个prototype就是一个对象,这个对象的所有属性和方法都会被构造函数所拥有,共享。
方法一般放到原型对象内
        class Star {       
            constructor(uname) {
                this.name = uname;  
            }
        }
        
        Star.prototype.say = function(song){    //共享方法
          console.log(song);
       }
对象有对象原型__proto__:
对象都会有一个属性__proto_指向构造函数的prototype原型对象,之所以我们对象可以使用构造函数prototype原型对象的属性和方沙,就是因为对象有_proto_原型的存在。先看对象内有无,没有再去prototype
D、对象原型(__proto__)和构造函数( prototype ) 原型对象里面都有一个constructor属性,constructor我们称为构造函数,因为它可以指回构造函数本身。有时会手动指回
class Star { constructor(uname) { this.name = uname; } } Star.prototype = {
constructor: Star, //重新指回构造函数Star,如果没有这句,在调用下面两函数的时候指针会指向对象Object,而不是指向Star say: function(song){ //共享方法 console.log(song); } said: function(){ console.log(1); } }
构造函数、实例、原型对象之间的关系 原型链(注意,其实function也有其原型):

6、成员查找
当访问一个对象的属性(包括方法)时,首先查找这个对象自身有没有该属性。如果没有就查找它的原型(也就是_proto_指向的prototype原型对象)。如果还没有就查找原型对象的原型( Object的原型对象)。
依此类推一直找到Object为止 ( null )。_proto_对象原型的意义就在于为对象成员查找机制提供一个方向,或者说─条路线。
7、扩展内置对象
通过原型对象,对原来的内置对象进行自定义方法扩展,如对数组增加求和方法等
注意∶数组和字符串内置对象不能给原型对象覆盖操作Array.prototype = {},只能是Array.prototype.xxx= function(){}的方式。
8、ES5组合继承:构造函数+原型对象
1、call() 调用函数
function fn(){ console.log(this); //指向object,没人调用 } fn.call();
call改变this指向
function fn() { console.log(this); //指向o } var o = { name: 2 } fn.call(o,1,2); //第一个参数改变this指向,不参与形实转换
2、利用call把父类this指向子类,从而完成继承
function Father(uname, age) { this.name = uname; this.age = age; } function Son(uname, age) { return Father.call(this,uname,age); //父类指向子类uname,age } var son = new Son('jacky',18); console.log(son);
3、子类继承后,当需要修改子类方法且不影响父类方法时,需要实例化一个对象充当中间件,若直接子类原型对象等于父类原型对象,这是把地址赋值,当子类变换时,地址内容变换,则父类变换
function Father(uname, age) { this.name = uname; this.age = age; } Father.prototype = { // constructor:Father, //对方法继承无效 money:function(){ console.log(10000); } } function Son(uname, age) { return Father.call(this,uname,age); } // Son.prototype = Father.prototype; //对方法继承有效,但是该方式为直接的地址赋值,若子的内容修改,父也将修改,即父类也有exam Son.prototype = new Father(); //新建中间件实例对象 Son.prototype.constructor = Son; //利用对象修改了Son后需要用constructor指回原对象 Son.prototype.exam = function(){ console.log(100); } var son = new Son('jacky',18); console.log(son); //有exam console.log(Father.prototype); //无exam
9、ES5新增方法
1、数组
迭代(遍历):
遍历:无返回值 forEach(function(currentValue,index,arr)); 有返回值 map(function(currentValue,index,arr));
筛选:返回数组 filter(function(currentValue,index,arr));
判断:返回布尔值 some(function(currentValue,index,arr)) 找到即停止,或; every(function(currentValue,index,arr))全部遍历且满足,与;
注意,some下需要return true; 当找到后跳出,才能提高效率,否则会一直遍历,效率不高,和forEach没区别
2、字符串
str.trim(); 删除字符串的两端空白字符串,返回新字符串,不影响原字符串。可用在表单验证处,删除开头空格
3、对象方法
Object.keys(obj); 获取对象自身所有属性,类似for...in...,返回一个属性名组成的数组
Object.defineProperty(obj, prop, descriptor); 定义新属性或修改原属性
descriptor说明:以对象形式{}书写:
value:设置属性的值默认为undefined
writable:值是否可以重写。true | false 默认为false
enumerable:目标属性是否可以被枚举遍历。true | false 默认为false
configurable:目标属性是否可以被删除或是否可以再次修改特性true | false 默认为false
10、函数进阶
1、函数定义:
1.1:函数声明function(命名函数function fn、匿名函数var fn = function、new Function(参数1, 参数2, 函数体) 函数也属于对象)
  
1.2:函数的调用:普通函数、对象的方法、构造函数、绑定事件函数、定时器函数、立即执行函数
2、this指向,一般指向调用者。但也可以手动改变,bind(), call(), apply()
  
2.1:call(指向对象,参数1,参数...) 可以调用函数,可以改变函数内this指向,主要用来实现继承
2.2:apply(指向对象,参数数组) 可以调用函数,可以改变函数内this指向,传递数组,可以用来处理数组有关的数据,如数学Math内置对象使用,求最大值
Math.max.apply(null, arr) //null意思为不需要指向 var max = Math.max.apply(Math, arr) //此处指回Math
2.3:bind(指向对象,参数1,参数...) 不调用函数,所以返回值是一个改造this指向和参数后的原函数拷贝,多用于需要改变this指向且不需要立即调用的地方
var o = { name: 'Jakcy'; } function fn(){ console.log(this); } var f = fn.bind(o); //并不会直接执行,只是对其一个改变this的拷贝 f(); //加上才能执行
btn.onclick = function () { this.disabled = true; // var that = this; //传统用中间变量保存this,但会造成空间浪费 setTimeout(function () { // that.disabled = false; this.disabled = false; // }, 3000) }.bind(this), 3000) //此处函数绑定this,即btn,且不立即调用,还是由定时器管控 }
3、严格模式(IE10) 为整个脚本或者某一函数开启严格模式 use strict
1.消除了Javascript语法的一些不合理、不严谨之处,减少了一些怪异行为。
1.如变量必须规定、2.不能随意删除声明好的变量、3.全局函数this不指向window,而为undefined(定时器还是window)、4.因为undefined,所以构造函数必须new使用、5.函数不许有重名参数、6.函数要声明在函数代码块(js初始即为一个立即执行函数),不允许在非函数代码块(if, for)下声明
2.消除代码运行的一些不安全之处,保证代码运行的安全。
3.提高编译器效率,增加运行速度。
4.禁用了在ECMAScript的未来版本中可能会定义的一些语法,为未来新版本的Javascript做好铺垫。比如一些保留字如: class, enum, export, extends, import, super不能做变量名
4、高阶函数
高阶函数是对其他函数进行操作的函数,它接收函数作为参数或将函数作为返回值输出。典型例子callback&&callback();
5、闭包( closure )指有权访问另一个函数作用域中变量的函数,可以定义为一个函数内部的函数
作用域:局部变量和全局变量
1.函数内部可以使用全局变量。
2.函数外部不可以使用局部变量。
3.当函数执行完毕,本作用域内的局部变量会销毁。
function fn(){ //此处fn为闭包,被访问变量所在的函数为闭包 var num = 10; funciton fun(){ console.log(num); }
return fun; //返回一个fun,即var f接回一个fun函数,fun可以访问fn的num,所以f也可访问num } var f = fn();
f(); //外部访问num, 这一步我个人理解就是fun延迟执行了
常见闭包点击面试题:
var li = document.querySelectorAll('li'); for (var i = 0; i < li.length; i++) { console.log(i); (function(i){ //立即执行函数也称小闭包 li[i].addEventListener('click',function(){ console.log(i); }) })(i); }
6、递归:一个函数在内部调用自身。递归容易像循环一样产生死循环,称为栈溢出,所以需要加退出条件
7、深浅拷贝:
1.浅拷贝只是拷贝一层,更深层次对象级别的拷贝地址,如果修改拷贝对象的话,会将源对象修改
2.深拷贝拷贝多层,每一级别的数据都会拷贝
3. Object.assign( target, ..sources) es6新增方法可以浅拷贝
8、正则表达(Regular Expression )是用于匹配字符串中字符组合的模式。在JavaScript中,正则表达式也是对象。
三大功能:匹配、替换、提取
JS中:1、调用RegExp对象的构造函数创建;2、通过字面量创建。(可以用 regexobj.test (str) 检测是否符合表达规范)
正则表达符号:边界符^$、字符类[ ] (中括号里有^即取反)、范围符 - 、量词符 * + ? {n} {n,} {n,m}、预定义类 \d \D \w \W \s \S等、或者 | (一个竖线)
替换:stringObject.replace(regexp/substr,replacement) 返回值为新字符串
/表达式/[switch] :匹配模式:g(全局匹配)、i(忽略大小写)、gi:(全局匹配+忽略大小写)
字符串的正则方法有:match()、replace()、search()、split()
正则对象的方法有:exec()、test()

 
                     
                    
                 
                    
                
 
                
            
         
         浙公网安备 33010602011771号
浙公网安备 33010602011771号