javascript高级进阶,带你体验js高级语法

本文深入探讨JavaScript的面向对象编程思想,包括构造函数、原型链、继承方式、闭包及高阶函数等核心概念。解析如何通过面向对象设计解决实际问题,提高代码复用性和维护性。

javascripe高级

**面向对象:**面向对象是一种思想,是解决问题的一种思路,即把一个大型的项目分解为对象进行完成,当把分解的每个对象完成后,进行串接,整个项目也就完成了。针对的是对象,针对对象进行问题处理

  • JavaScript的组成:

ECMAscript组成:变量、数据类型、类型转换、操作符
流程控制、判断、循环语句
数组、函数、作用域、预解析
对象、属性、方法、简单数据类型、复杂数据类型、以及他们的区别
内置对象:Math、Date、Array、基本包装类型String、Number、布尔
DOM:onload页面加载事件、window顶级对象
定时器
location、history
BOM:获取页面元素、注册事件
属性操作、样式操作
节点操作、节点层级
动态创建元素
事件:注册事件的方式、事件的三个阶段、事件对象
JavaScript的执行过程:
全局预解析:变量和函数声明会被提升,变量和函数同名,函数的有优先级最高
函数内部预解析(函数、形参、普通变量都会参与预解析)

  • 面向对象的设计思想:

1、抽象出构造函数(Class)
2、根据构造函数创建对象实例(Instance)
3、指挥Instance得出结果

  • 创建对象:

1、通过new Obiect()创建对象

var person = new Object()
person.name = 'Jack'
person.age = 18
person.sayName = function () {
  console.log(this.name)
}

2、通过对象字面量创建对象

var person = {
  name: 'Jack',
  age: 18,
  sayName: function () {
    console.log(this.name)
  }
}
3

、通过上面的方法,如果要生成多个对象,需要多次创建,显得代码太过冗余,此时我们可以使用工厂函数进行对象实例化

function createPerson (name, age) {
  return {
    name: name,
    age: age,
    sayName: function () {
      console.log(this.name)
    }
  }
}

4、虽然使用工厂函数解决了代码冗余的问题,但是还是无法解决对象识别的问题,此时需要使用构造函数来完成解决我们的问题

function Person (name, age) {
  this.name = name
  this.age = age
  this.sayName = function () {
    console.log(this.name)
  }
}

var p1 = new Person('Jack', 18)
p1.sayName() // => Jack

var p2 = new Person('Mike', 23)
p2.sayName() // => Mike
  • 构造函数解析:

1、会在内存中创建一个空对象
2、设置构造函数的this,让this指向刚刚new创建的对象
3、执行构造函数中的代码
4、返回对象

  • constructor:构造器

在每个实例对象中同时都有一个constructor属性,该属性指向创建该实例的构造函数
instanceof操作符:判断 检测对象的类型

  • 实例对象/静态成员

实例对象:和对象相关的成员,将来使用对象的方式调用
静态成员:直接构造函数添加的成员,将来调用要使用构造函数来调用

  • 原型:

由于对象中我们多次调用可能有时会存在属性和方法重复的问题,这样就会造成内存浪费,针对这个问题,我们提出了原型的概念,因为原型在每个对象中都是公共存在的,我们只需要把相同的属性和方法拿出来放到公共存在的原型中,让大家用到的时候都可以去里面调用,这样就大大的节约了空间,减少了内存浪费。
每一个构造函数都有一个属性:原型/原型对象

prototype:构造函数的原型对象,是一个对象。
function Student (name, age) {
  this.name = name
  this.age = age
}
Student .prototype.type = 'human'

Student .prototype.sayName = function () {
  console.log(this.name)
}

我们通过Student构造函数创建的对象,可以访问Student.prototype中的成员
即此时type属性和sayName()方法都是prototype对象
var s1 = new Student(‘lilei’, 18, ‘男’);
var s2 = new Student(‘hmm’, 18, ‘女’);
当我们调用对象的属性和方法的时候,先去找对象本身的属性和方法,如果对象本身没有此属性和方法,再去调用原型对象中的属性和方法。如果对象本身没有此属性和方法,原型对象中也没有此属性和方法,此时就会报错
s1.proto 就等价于Student.prototype 都是原型对象
在原型对象prototype中有都一个属性constructor 构造函数 指向构造函数本身
constructor记录创建该对象的构造函数,记录了创建该对象的构造函数
s1.constructor===Student

构造函数 实例 原型 三者之间的关系
实例是通过构造函数new出来的实例对象 — 实例对象的__proto__的原型对象就是构造函数的prototype,他们之间呈现三角关系
通过构造函数得到的实例对象内部都会包含一个 指向构造函数的prototype对象的指针__proto__
所有实例对象都直接或者间接继承了原型对象的成员

  • 原型链的概念:

就是实例对象的原型的原型,就一直往上原型,形成的一个链子,当找到最后没有找到就会返回undefined
属性设置一般情况设置在构造函数的本身
方法设置一般情况设置在构造函数的原型对象中

当我们重新改变原型对象prototype的时候,需要重新设置constructor属性。因为重新改变原型对象,相当于赋值,会把之前对象中的属性都会清空覆盖,此时就需要重新设置给constructor属性
正确设置原型属性

function Person (name, age) {
  this.name = name
  this.age = age
}

Person.prototype = {
  constructor: Person, // => 手动将 constructor 指向正确的构造函数
  type: 'human',
  sayHello: function () {
    console.log('我叫' + this.name + ',我今年' + this.age + '岁了')
  }
}

所有函数都有prototype属性对象,但是数组或者String中的prototype是不可修改的

贪吃蛇案例:旨在体会面向对象思想
我们创建三个对象进行
食物对象
蛇对象
游戏对象
每个对象中又对应不同的属性和方法

在开发过程中会涉及到自调用函数:目的是新开辟一个新的作用域,防止命名冲突
有时可能出现报错,是由于自调用函数之间没有写 ; 导致的,解决办法 在自调用函数前面加上 ; 即可
如果使用了自调用函数,在函数的最后需要把外部用到的构造函数暴露出去,通过window暴露构造函数给外部,自调用函数的参数window和undefined,传入window的目的,是让变量名可以被压缩;传入undefined的目的,可以被重新赋值

**bind()方法:**bind可以新建一个方法,bind中的第一个参数可以改变函数中的this指向
bind可以返回一个新的函数 没有调用方法, 需要用变量接收,然后在调用
**call()**改变函数中的this直接调用函数

  • 继承:

构造函数的属性继承:借用构造函数:利用call()方法,让子类型借用父类型的构造函数

function Person (name, age) {
  this.type = 'human'
  this.name = name
  this.age = age
}
function Student (name, age) {
  // 借用构造函数继承属性成员
  Person.call(this, name, age)
}
var s1 = Student('张三', 18)
console.log(s1.type, s1.name, s1.age) // => human 张三 18
构造函数的原型方法继承:拷贝继承
function Person (name, age) {
  this.type = 'human'
  this.name = name
  this.age = age
}
Person.prototype.sayName = function () {
  console.log('hello ' + this.name)
}
function Student (name, age) {
  Person.call(this, name, age)
}
// 原型对象拷贝继承原型对象成员
for(var key in Person.prototype) {
  Student.prototype[key] = Person.prototype[key]
}
var s1 = Student('张三', 18)
s1.sayName() // => hello 张三

原型继承:

function Person (name, age) {
  this.type = 'human'
  this.name = name
  this.age = age
}

Person.prototype.sayName = function () {
  console.log('hello ' + this.name)
}

function Student (name, age) {
  Person.call(this, name, age)
}

// 利用原型的特性实现继承
Student.prototype = new Person()

var s1 = Student('张三', 18)

console.log(s1.type) // => human

s1.sayName() // => hello 张三

继承目的:把子类型中共同的成员提取到父类型中
原型继承:无法设置构造函数中的参数
组合继承:借用构造函数 + 原型继承
通过借用构造函数让子类型继承父类型的属性 通过原型继承的方式让子类型继承父类型的方法实现组合继承

函数 : 函数也是对象 new Function()
函数声明:
function foo () {

}
函数表达式:
var foo = function () {

}
函数声明和函数表达式的区别:
1、函数声明必须 有名字
2、函数声明会函数提升,在预解析阶段就已经创建,声明前后都可以调用
3、函数表达式类似于变量赋值
4、函数表达式可以没有名字 例如匿名函数
5、函数表达式没有变量提升,在执行阶段创建,必须在表达式执行之后才可以调用

函数的调用方式: this的指向
普通函数调用 – this指向是window
方法调用 – this指向是调用该方法的对象
构造函数调用 – 由该构造函数创建的实例对象
作为事件处理函数 – 触发该事件的对象
定时器的函数 – this指向是window
总之,谁调用指向谁

call bind apply方法总结 :如果第一个参数指定了null或undefined,内部this指向window
call:
1、自身可以调用函数,改变函数中this的指向
2、第一个参数,设置函数内部this的指向,其他参数,对应函数的参数
3、call的返回值就是函数的返回值

apply:
1、自身可以调用函数,改变函数中this的指向
2、只有两个参数,参数1设置函数内部this的指向,参数2是数组
3、apply的返回值就是函数的返回值

bind:
1、改变函数中的this,不会调用函数,而是把函数赋值一份
2、第一个参数,设置函数内部this的指向,其他参数,对应函数的参数
3、bind的返回值就是函数的返回值
函数的其他成员:
arguments — 实参集合
caller — 函数的调用者
length — 形参的个数
name — 函数的名字

  • 高阶函数

什么是高阶函数:
1、函数可以作为参数

function eat (callback) {
  setTimeout(function () {
    console.log('吃完了')
    callback()
  }, 1000)
}

eat(function () {
  console.log('去唱歌')
})

2、函数可以作为返回值

function genFun (type) {
  return function (obj) {
    return Object.prototype.toString.call(obj) === type
  }
}

var isArray = genFun('[object Array]')
var isObject = genFun('[object Object]')

console.log(isArray([])) // => true
console.log(isArray({})) // => true
  • 函数闭包:

作用域有 全局作用域 函数作用域 没有快捷作用域 内层作用域可以访问外层作用域,反之不行

什么是闭包
闭包就是可以读取其他函数内部变量的函数(在一个作用域中可以访问另一个作用域中的变量) 延展了函数的作用域范围
闭包的用途:
可以在函数外部读取 函数内部成员
让函数内部成员始终存活在内存中

  • 递归:

函数自己调用函数
一般都要写结束条件
掌握递归思想

**深拷贝:**将对象中的属性和方法全部拷贝,且对新拷贝的对象操作不会对被拷贝的对象有任何影响
**浅拷贝:**只能拷贝对象中的一级属性和方法,如果内部再有新的对象将不能进行拷贝,对新拷贝的对象操作会影响被拷贝对象中的二级属性。

  • 递归思想遍历:

    1、 // 遍历指定元素下所有的子元素

    function loadTree(parent, callback) {
    for (var i = 0; i < parent.children.length; i++) {
    // 遍历第一级子元素
    var child = parent.children[i];
    // console.log(child);
    if (callback) {
    // 处理找到的子元素
    callback(child);
    }

    // 递归调用
    loadTree(child);
    }
    }

2、 // 深度优先

 function loadTree(parentElement) {



 var childElements = parentElement.children;
    for (var i = 0; i < childElements.length; i++) {
        var childElement = childElements[i];
        // 需要执行的操作
        console.log(childElement);

        // 输出子元素下的子元素节点
        loadTree(childElement);
    }
}

    loadTree(document.body);

3、 // 广度优先

  var elementList = [];

// 数组操作的4个方法 push  pop  unshift  shift

// 假设有一个方法,从数组中取出元素,进行打印,再进入这个元素继续打印下面所有的元素
function printElement() {
    // 如果数组中有元素,就继续执行
    while (elementList.length > 0) {
        var element = elementList.shift();
        // 执行的操作
        console.log(element);

        var childElements = element.children;
        for (var i = 0; i < childElements.length; i++) {
            var childElement = childElements[i];
            elementList.push(childElement);
        }
    }
}

elementList.push(document.body);
printElement();

相比较而言,广度优先性能最优

  • 正则表达式

就是通过一些规则制定功能,便于我们开发
正则表达式组成:普通字符 特殊字符(元字符)
常用元字符串:
\d — 匹配数字
\D — 匹配任意非数字的字符
\w — 匹配字母或数字或下划线
\W — 匹配任意不是字母 数字 下划线
\s — 匹配任意空白符
\S — 匹配任意不是空白符的字符
. — 匹配除换行符以外的任意单个字符
^ — 匹配行首的文本(以谁开始)
$ — 匹配行尾的文本(以谁结束)

限定符:

  • — 重复零次或者更多次
  • — 重复一次或者更多次
    ? — 重复零次或者一次
    {n} — 重复n次
    {n,}— 重复n 次或者更多次
    {n,m}— 重复n到m次

其它符号
[] – 字符串用中括号括起来,表示匹配其中任一字符,相当于或的意思
[^] – 匹配除中括号内的以外的内容
\ – 转义符
| – 选择两者的一个,注意 | 将内容分为两部分,而不管左右两边有多长多乱
()-- 从两个直接量中选择一个,分组eg:gr(a|e)y匹配gray和grey
[\u4e00-u9fa5] – 匹配汉字

案例:
验证手机号:^\d{11}$ — 11位数字开始 11位数字结束
验证邮编: ^\d{6}$ — 6位数字开始 6位数字结束
验证日期:^\d({4}-\d{1,2}-\d{1,2}$ 4位数字开始 中间两位 后面两位
验证邮箱:^\w+@\w+.\w$ 以字母或者数字开始 以字母或者数字结束
验证IP地址:^\d{1,3}(.\d{1,3}){3}$ 3位数字

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

码上登堂

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值