怎么办一个网站,合肥瑶海区小学排名,做漂亮的二维码网站,微信开放平台个人申请JavaScript基础 面向对象面向过程函数式编程命令式编程函数式编程特性副作用透明引用不可变变量函数是一等公民 常见的函数式编程模型 面向对象为什么要使用面向对象封装继承多态 对比面向过程函数式编程面向对象 构造函数原型constructor使用场景 对象原型 面向对象
面向过程… JavaScript基础 面向对象面向过程函数式编程命令式编程函数式编程特性副作用透明引用不可变变量函数是一等公民 常见的函数式编程模型 面向对象为什么要使用面向对象封装继承多态 对比面向过程函数式编程面向对象 构造函数原型constructor使用场景 对象原型 面向对象
面向过程
按照我们分析好了的步骤按照步骤解决问题 步骤:函数 函数的调用
函数式编程
编写程序的方法论 利用函数把运算结果包装 复杂的功能可以通过组合各种函数计算结果
命令式编程
例如对数组每一个数字平方变化
var arr [0,1,2,3,4]
for (let i 0; i arr.length; i) {arr[i] Math.pow(arr[i],2)
}命令式编程 可读性不强 变量声明多。很难排查
函数式编程
[0,1, 2, 3, 4].map(num ⇒ Math.pow(num,2))通过函数对数据进行转换
特定:
通过函数对数据进行转换通过串联多个函数来求结果
特性
副作用
//有副作用 修改了外部变量a
var a 1
function test1() {areturn a
}// 无副作用 没有修改外部状态
// 多次调用结果都是一样的
function test2(a){
return a 1
}透明引用
// 有副作用 修改了外部变量a
// 函数内容使用的变量并不属于他的作用域
var a 1
var b 2
function test1() {
return a b
}// 无副作用 没有修改外部状态
// 多次调用结果都是一样的
// 函数内部使用的变量是显式传参方式
function test2(a,b){
return a b
}不可变变量
指的是一个变量一旦创建后就不能再进行修改任何修改都会生成一个新的变量
var obj Immutable({ a: 1 });
var obj2 obj.set(a, 2);
console.log(obj); // Immutable({ a: 1 })
console.log(obj2); // Immutable({ a: 2 })函数是一等公民
指的是函数与其他数据类型一样处于平等地位 可以赋值给其他变量也可以作为参数传入另一个函数 或者作为别的函数的返回值
常见的函数式编程模型
闭包高阶函数 - map - filter - reduce函数柯里化函数组合
面向对象
面向对象也是一种开发模型主要围绕着数据或者对象而不是功能和逻辑来组织代码 他让开发者的关注点由逻辑转为想要操纵的数据他将数据和方法都包装在一个类中 这样有利于代码的重用和可扩展性。
class Person{constructor(name) {this.namename}say(){console.log(我叫this.nane)}
}let person1new Person(张三)
let person2new Person(李四)为什么要使用面向对象
面向对象是以对象功能来划分问题而不是步骤
面向对象程序开发思想中每一个对象都是功能中心具有明确的分工面试对象编程具有灵活性、代码可复用、容易维护和开发的优点更合适多人合作的大型软件项目面向对象三大特点封装、继承、多态
封装
所有的数据和方法都被封装在对象内由开发者自己选择性的去公开哪些属性和方法对于创建的实例来说他能访问的只能是这些公开的属性和方法而对于其他对象来说是无权访问此类或者进行更改封装这一特性为程序提供了更高的安全性。
继承
继承意味着代码的可重用性子类和父类这两个概念就是很好的体现子类拥有父类所有的属性和方法避免数据和方法的重复定义同时也能够保持独特的层析结构
多态
多态意味着设计对象以共享行为使用继承子类可以用新的方法去覆盖父类共享的行为多态性允许同一个方法执行两种不同的行为覆盖和重载。
对比
面向过程
优点性能比面向对象高适合跟硬件联系很紧密的东西例如单片机就采用面向过程编程 缺点没有面向对象易维护、易复用、易扩展
函数式编程
优点代码简洁易于理解并发速度快使用 immutable 数据管理方式可以避免掉很多情况的 lock并发处理速度会很快。出错率少 缺点性能消耗大、资源占用大
面向对象
优点易维护、易复用、易扩展由于面向对象有封装、继承、多态的特性可以设计出低耦合的系统使系统更加灵活、更加易于维护 缺点状态的共享、耗内存、性能低
构造函数
用来创建对象 Object Array 原生构造函数
new Object()
new Array()function Person(name,age){this.namenamethis.ageagethis.sayName function (){console.log(this.name,this.age)}
}//实例
let person1new Person(张三,18)
let person2new Person(李四,25)person1.sayName()
person2.sayName()console.log(person1 person2)
console.log(person1.sayNameperson2.sayName)通过this实现数据的共享 不同的是通过构造函数创建出的实例对象他们之间彼此是不影响的
构造函数体现了面向对象的封装构造函数实例对象彼此是互不影响的
存在浪费内存的问题
试图解决一下
function Person(name, age) {this.name name;this.age age;this.sayName sayName
}function sayName() {console.log(this.name);
}let person1 new Person(小明, 18)
let person2 new Person(小红, 20)person1.sayName() // 小明
person2.sayName() // 小红虽然解决了相同逻辑的函数重复定义的问题但全局作用域也因此被搞乱了因为那个函数实际上只能在一个对象上调用。如果这个对象需要多个方法那么就要在全局作用域中定义多个函数。这会导致自定义类型引用的代码不能很好地聚集一起。这个新问题可以通过原型模式来解决。
原型
目的能够利用原型对象实现方法共享
构造函数通过原型分配的函数是所有对象所共享的每个函数都会创建一个 prototype 属性这个属性是一个对象称为原型对象原型对象可以挂载函数对象实例化不会多次创建原型函数节约内存可以把那些不变的方法直接定义在原型对象上面定义的属性和方法可以被对象实例共享构造函数和原型对象中的this都指向实例化的对象
!DOCTYPE html
html langen
headmeta charsetUTF-8titleTitle/title
/head
body
scriptfunction Person(name,age){this.namenamethis.ageagePerson.prototype.sayNamefunction(){console.log(我叫${this.name}今年${this.age}岁了)}}//实例let person1new Person(张三,18)let person2new Person(李四,25)person1.sayName()person2.sayName()console.log(person1 person2)console.log(person1.sayNameperson2.sayName)console.dir(Person)
/script
/body
/html constructor
默认情况下所有原型对象自动获得一个名为 constructor 的属性 作用该属性指向该原型对象的构造函数 对前面的例子而言Person.prototype.constructor 指向 Person
原型对象上面默认只会获取constructor属性其他的所有方法都继承Object 也可以这样理解 简单理解来说
使用场景
下面这段代码相当于将prototype原型对象重新赋值了替换掉了默认的constructor函数所以为了代码的完整性还要加上constructor:Person这一行
Person.prototype{sayName(){},...
}!DOCTYPE html
html langen
headmeta charsetUTF-8titleTitle/title
/head
body
scriptfunction Person(name,age) {this.name namethis.age age}//Person.prototype本身是一个对象所以直接复用//相当于Person.prototypenew Object() Person.prototype{}//此时constructor就是挂载到Object上的Person.prototype{constructor:Person, //如果没有这一行代码此时constructor就是挂载到Object上的因此改变constructor的挂载挂载到Person上sayName(){console.log(我叫${this.name})},sing(){console.log(唱歌)},dance(){console.log(跳舞)}}//实例let person1new Person(张三,18)let person2new Person(李四,25)person1.sayName()person2.sayName()person1.sing()person2.dance()console.dir(Person)
/script
/body
/html 对象原型
构造函数可以创建实例对象构造函数还有一个原型对象一些公共的属性或者方法放到这个原型对象身上 但是为啥实例对象可以访问原型对象里面的属性和方法呢 对象都会有一个属性__proto__指向构造函数的prototype原型对象之所以我们对象可以使用构造函数prototype原型对象的属性和方法就是因为对象有__proto__原型的存在。
new 构造函数 实例 [[prototype]] → 构造函数的原型对象 prototype
每次调用构造函数创建一个新实例这个实例的内部[[Prototype]]指针就会被赋值为构造函数的原型对象,脚本中没有访问这个[[Prototype]]特性的标准方式但 Firefox、Safari 和 Chrome会在每个对象上暴露__proto__属性通过这个属性可以访问对象的原型
所以我们对象可以使用构造函数prototype原型对象的属性和方法就是因为对象有__proto__原型的存在 对象原型指向原型对象
function Person() {
}console.log(typeof Person.prototype)let person new Person()
let person2 new Person()
console.log(person.__proto__ Person.prototype) // true
console.log(person.__proto__.constructor Person) // true
console.log(person.__proto__ person2.__proto__) // true正常的原型链都会终止于 Object 的原型对象Object 原型的原型是 null
console.log(Person.prototype.__proto__ Object.prototype); // true
console.log(Person.prototype.__proto__.constructor Object); // true
console.log(Person.prototype.__proto__.__proto__ null); // true
console.log(Person.prototype.__proto__);
{constructor: ƒ Object()hasOwnProperty: ƒ hasOwnProperty()isPrototypeOf: ƒ isPrototypeOf()propertyIsEnumerable: ƒ propertyIsEnumerable()toLocaleString: ƒ toLocaleString()toString: ƒ toString()valueOf: ƒ valueOf()
}