Skip to content
1StepEngineer edited this page Oct 28, 2018 · 28 revisions

什么是闭包

闭包是指有权访问另一个函数作用域中变量的函数。
创建闭包的方式就是在一个函数内部创建另外一个函数。

闭包的应用

保存现场
封装

闭包的典型问题

错误示例:

function addHandlers(nodes){
   for(var i=0; i< nodes.length; i ++){
    nodes[i].onclick = function(){
      alert(i)
}
}
}
/**
* 每次点击节点的alert数字都是一样。
* 因为:node.onclick是在实际点击的时候才会调用,此时的i已经变成了nodes.length;
* 所以:无论点击的节点是那个结果都是nodes.length。
*/

正确示例:

function addHandlers(nodes){
  function helper(i){
    return function(){
       alert(i)
    } 
  }
  for(var i=0;i<nodes.length;i++){
       nodes[i].onclick = helper(i)
  }
}

原型相关

通过_proto_指向原型对象 avatar

方法一:Object.create

let landRover = {
 name:"car",
 start:function(){
   console.log(`start ${this.logo}`)
 }
}
let landWind = Object.create(landRover)
landWind.logo = 'landWind'

let landCruiser = Object.create(landRover)
landCruiser.logo = 'landCruiser'

方法二:构造函数

//Car构造函数
function Car(logo){
this.logo = logo || "unknown name"
}
//设置Car的prototype属性
Car.prototype = {
 name:'car',
 start:function(){
	console.log(`start ${this.logo}`)
 }
}
//创建对象
let landRover = new Car('landRover')
let landWind = new Car('landWind')
//调用方法
landRover.start()

原型链示例

//Car构造函数
function Car(logo){
this.logo = logo || "unknown name"
}
//设置Car的prototype属性
Car.prototype = {
 name:'car',
 start:function(){
	console.log(`start ${this.logo}`)
 }
}
//创建对象
let landRover = new Car('landRover')

//LandRover构造函数
function LandRover(num){
 this.num = num;
}
//设置LandRover的prototype属性
LandRover.prototype = landRover
//创建LandRover对象
let landRover1 = new LandRover(10)
let landRover2 = new LandRover(20)

avatar

面向对象(oop)

ES6:https://github.com/Mirror198829/front-end/wiki/ES6#class%E5%9F%BA%E6%9C%AC%E4%BD%BF%E7%94%A8

var arr = new Array() //[]  这些个是系统自带的对象,就叫系统对象
var date = new Date()

//自定义对象
var tab = new Tab()

面向对象编程(oop)的特点

  • 封装:只能通过对象来访问方法
  • 继承:从已有对象上继承新的对象
  • 多态:用的不多,不像java/php,多对象的不同形态

对象的组成

  • 方法(行为、操作)——函数:过程、动态的
  • 属性——变量:状态、静态的

面向对象模式

工厂模式

封装函数

function createPerson(name){
  var obj = new Object()
  obj.name = name
  obj.showName = function(){
     alert(this.name)
 }
  return obj
}
createPerson('小明').showName()
createPerson('小强').showName()

工厂模式虽然解决了创建多个类似的对象,并没有解决对象识别的问题。因此引出构造函数模式

构造函数模式

当new去调用函数,函数中的this就是创建出来的对象,并且函数返回值(隐式返回)就是this的这个对象。这个是规则。

function CreatePerson(name){
   this.name = name 
   this.showName = function(){
     alert(this.name)
 }
}
new CreatePerson('小明').showName()
var p1 = CreatePerson('x')
var p2 = CreatePerson('y')
p1.showName == p2.showName //false
/* 这个false代表:
* p1和p2定义的showName用的是两个地址,会占用多次内存。如果每次都构建,就会极大消耗内存
* 解决上述问题,引入下面原型模式
*/

原型模式

原型:prototype,要写在构造函数的下面

function (name){
   this.name = name 
}
CreatePerson.prototype.sayName = function(){
  alert(this.name)
}
new CreatePerson('小明').sayName()
var p1 = new CreatePerson('x')
var p2 = new CreatePerson('y')
p1.sayName == p2.sayName //true

面相对象模式总结 常规写法是:构造函数+原型模式
原型模式里面放入的不会改变的方法和属性,会改变的属性均放入构造函数

function 构造函数(){
   this.属性
}
构造函数.原型.方法 = function(){}
let 对象1 = new 构造函数()
对象1.方法()

继承

ES6: https://github.com/Mirror198829/front-end/wiki/ES6#class%E7%BB%A7%E6%89%BF
在原有对象的基础上,修改后得到一个新的对象,不影响原有对象的功能
继承:子类不影响父类,子类可以继承父类的一些功能(代码复用)
属性的继承:调用父类的构造函数 call
方法的继承:父类原型赋值给子类原型

//父类
function CreatePerson(name){
   this.name = name
}
CreatePerson.prototype.sayName = function(){
   alert(this.name)
}
let p1 = new CreatePerson('小明')
p1.sayName()
//子类
function CreateStar(name,job){
  CreatePerson.call(this,name)  //子类属性继承父类的方法,同时要改变this的指向
  this.job = job
}
CreateStar.prototype.showJob = function(){
  alert(this.job)
}
//方法的继承,产生问题是引用地址的赋值,会导致父类也获取到子类的方法。
CreateStar.prototype = CreatePerson.prototype  
//优化如下
//继承函数封装
function extend(obj1,obj2){
   for(var attr in obj2){
     obj1[attr] = obj2[attr]
 }
}
extend( CreateStar.prototype, CreatePerson.prototype ) //优化之后的结果

深拷贝与浅拷贝?如何实现深拷贝

浅拷贝:只是将数据中存放的引用拷贝下来,依旧指向同一个存放地址
深拷贝:将数据中所有的数据拷贝下来,而不是引用。拷贝下来的数据的修改不会影响原数据。
Object.assign()实现的依然是浅拷贝

深拷贝的实现

let obj2 = JSON.parse(JSON.stringify(obj))
但是该方法在function等内容的时候,无法拷贝

let obj1 = {
  name:'111',
  age:12,
  fn:function(){
    
 }
}
let obj2 = JSON.parse(JSON.stringify(obj1)) //{name:"111",age:12},其中的fun是无法被拷贝出来的
Clone this wiki locally