发表于: 2019-11-15 18:48:14
1 1135
今天完成的事:
复习css和js深度思考,整理相关知识点
明天计划的事:
再复习、复习准备复盘评审
遇到的问题:
对学会的知识点,了解会用,但不能完整的叙述,流畅的讲出自己的理解
收获:
原型和原型链
原型
- 所有引用类型(数组、对象、函数)都有一个__proto__隐式原型属性,属性值是一个普通对象。 此外,Object.prototype.__proto__指向null
- 所有函数都有一个prototype显式原型属性,属性值是一个普通对象。 Function.prototype.bind()没有prototype属性
- 所有引用类型(数组、对象、函数)的__proto__执行它的构造函数的prototype属性
构造函数
构造函数特点:函数名首字母大写,它就类似一个模板,可以new出多个实例
var a={} // var a=new Object()的语法糖 var a=[] // var a=new Array()的语法糖 function Foo(){} // var Foo=new Function()的语法糖 复制代码
instanceof
instanceof判断引用类型属于哪个构造函数
f instanceof Foo的判断逻辑:f的__proto__一层层往上,能否找到Foo.prototype。
但是因为原型链上所有特殊对象的__proto__最终都会指向Object.prototype,所以instanceof判断类型也不完全准确
new操作符具体干了什么?
- 创建一个空对象
- 将对象的__proto指向构造函数的原型prototype
- 执行构造函数中的代码,传递参数,并将this指向这个对象
- 返回对象
function _new(){ let obj = {}; let con=[].shift.call(arguments); obj.__proto__ = con.prototype; let res = con.apply(obj, arguments); return res instanceof Object ? res : obj; } 复制代码
通过new的方式创建对象和通过字面量创建的区别
更推荐字面量的方式创建对象,性能和可读性都更好。使用var o=new Object()和var o={}的区别是前者会调用构造函数
hasOwnProperty
hasOwnProperty判断该对象本身是否有指定属性,不会到原型链上查找。
使用方法:object.hasOwnProperty(proName)
利用它可以循环对象自身属性
for(let item in f){ if(f.hasOwnProperty(item)){ console.log(item) } } 复制代码
原型链
访问一个对象的属性时,先在基本属性中查找,如果没有,再沿着__proto__这条链向上找,这就是原型链
面向对象
创建对象的几种方式
- 工厂模式
function createPerson(name, age){ var o = new Object(); o.name = name; o.age = age; o.sayName = function(){ console.log(this.name) } return o; } var person1 = createPerson('chen',21) 复制代码
- 构造函数模式
没有显示创建对象,直接将属性方法赋给this,没有return语句
function Person(name, age){ this.name = name; this.age = age; this.sayName = function(){ console.log(this.name) } } var person1 = new Person('chen',21) 复制代码
缺点:每个方法都要在每个实例上重新定义一遍,无法得到复用
- 原型模式
function Person(){} Person.prototype.name="chen" Person.prototype.age=21 Person.prototype.sayName=function(){ console.log(this.name) } var person1 = new Person() 复制代码
缺点:所有实例都取得相同属性值
- 混合构造函数原型模式 构造函数模式用于定义实例属性,原型模式用于定义方法和共享的属性。
function Person(name,age){ this.name=name; this.age=age; } Person.prototype = { constructor: Person, sayName: function(){ console.log(this.name) } } var person1=new Person('chen',21) 复制代码
实现继承
JavaScript通过原型链实现继承
- 原型链继承 核心:将父类的实例作为子类的继承
function Parent(){ this.name = 'parent' } Parent.prototype.sayName = function(){ return this.name } function Child(){ } // 继承了Parent Child.prototype = new Parent(); var child1=new Child(); child1.say(); 复制代码
缺点:对象实例共享所有继承的属性和方法
- 借用构造函数 核心:在子构造函数内部调用父构造函数
function Parent(){ this.arr=[1,2,3] } function Child(){ // 继承了Parent Parent.call(this) } var child1 = new Child(); child.arr.push(4); // [1,2,3,4] var child2 = new Child(); child.arr; // [1,2,3] 复制代码
- 组合继承
使用原型链继承共享的属性和方法,通过借用构造函数继承实例属性
function Parent(name){ this.name = name; this.arr = [1,2,3] } Parent.prototype.sayName = function(){ console.log(this.name) } function Child(name,age){ // 继承属性 Parent.call(this, name) this.age=age } // 继承方法 Child.prototype = new Parent() Child.prototype.constructor = Child; Child.prototype.sayAge = function(){ console.log(this.age) } var child1=new Child('chen',21); child1.arr.push(4); //[1,2,3,4] child1.sayName() // 'chen' child1.sayAge() // 21 var child2=new Child('miao', 12) child2.arr // [1,2,3] child2.sayName() // "miao" child2.sayAge() // 12 复制代码
缺点:无论在什么情况都会调用两次父构造函数,一次是创建子类型原型,另一次是在子构造函数内部
- 原型式继承 核心:执行对给定对象的浅复制
var person = { name: 'chen', arr: [1,2,3] } var person1 = Object.create(person); person1.name = 'run' person1.arr.push(4) var person2 = Object.create(person); person2.name = 'miao' person2.arr.push(5) person.arr; // [1,2,3,4,5] 复制代码
- 寄生式继承 核心:基于某个对象创建一个对象,然后增强对象,返回对象。
function create(original){ // 通过调用函数创建一个新对象 var clone = object(original); // 以某种方式增强对象 clone.sayHi = function(){ console.log('hi') } return clone; } var person = { name: 'chen' } var person1 = create(person); person1.sayHi(); 复制代码
- 寄生组合式继承
function Parent(name){ this.name = name; this.arr = [1,2,3] } // 将共享的属性/方法放到原型上 Parent.prototype.sayName = function(){ console.log(this.name) } // 借用构造函数增强子类实例属性(支持传参和避免篡改) function Child(name,age){ // 继承属性 Parent.call(this, name) this.age=age } function inheritPrototype(Child, Parent){ var prototype=Object.create(Parent.prototype); prototype.constructor=Child; Child.prototype=prototype; } // 将父类原型指向子类 inheritPrototype(Child, Parent); Child.prototype.sayAge=function(){ console.log(this.age) } var child1=new Child('chen',21); child1.arr.push(4); //[1,2,3,4] 继承自父类实例属性 child1.sayName() // 'chen' 继承自父类原型方法 child1.sayAge() // 21 继承自子类原型方法 var child2=new Child('miao', 12) child2.arr // [1,2,3] child2.sayName() // "miao" child2.sayAge() // 12 复制代码
class如何实现继承,class本质是什么?
class只是语法糖,本质是函数
class Parent{ constructor(value){ this.val=value } getValue(){ console.log(this.val) } } class Child extends Parent{ constructor(value){ super(value) this.val = value } } let child = new Child(1) child.getValue() // 1 child instanceof Parent // true 复制代码
核心:使用extends表明继承自哪个父类,并且在子类构造函数中必须使用super,可以看做是Parent.call(this,value)
什么是面向对象编程及面向过程编程,它们的异同和优缺点
面向过程就是分析出解决问题所需的步骤,然后用函数把这些步骤一步步实现,使用的时候一个个依次调用
面向对象是把构成问题的事务分解成各个对象,奖励对象的目的不是为了完成一个步骤,而是为了描述某个事物在整个解决问题的步骤中的行为。
优点:易维护,可读性高,易扩展,继承性高,降低重复工作量,缩短了开发
评论