额外小知识
- with语句:可以形成自己的作用域 它会先在with的参数中寻找变量 之后再往上寻找
with(obj){
console.log(obj)
}
- eval函数 eval可以传入字符串参数 这个可以执行字符串代码 一般情况都在webpack配置中 设置devtool='eval' 它的作用是把字符串代码 编程了es5代码
var jsString='var name='11''
eval(jsString)
面向对象编程
定义:
每个对象都应该有属于自己的对象
属性描述符分类:(默认都是false) 所以都不会有默认的
- 数据属性描述符
- configurable:Boolean 是否可以通过delect删除 是否可以修改它的特性
- enumerable:Boolean 是否可以通过for-in或者Object.keys()返回该属性 是否可以看到或者枚举到
- writable:Boolean 是否可以修改属性
- value : 属性值 2.存取属性描述符
- configurable: Boolean 是否可以通过delect删除 是否可以修改的它特性 是否可以修改存取属性描述符
- enumerable: boolean 是否可以通过for-in或者Object.keys()返回该属性 是否可以查看到 枚举到
- get:function(){ // 在进行一些操作逻辑 return this.name },
- set:function(value){ // 在进行一些操作逻辑 return this.name=value } 3.其他的api 对象的get set方法
var obj={
name:111,
set name(value){
return this.name=value
}
get name(){
return this.name
}
}
获取对象上某一属性的属性描述符
object.getOwnpropertyDescriptot(obj,'name')
获取对象上全部属性描述符
object.getOwnpropertyDescriptots(obj)
禁止对象继续添加新的属性
object.preventExtensions(obj)
禁止对象配置/删除里面的属性
object.seal(obj)
禁止对象属性不可修改
object.freeze(obj)
object.defineProperty('哪一个对象','哪一个属性/如果没有这个属性就会自动添加',{这个属性的描述配置(object)})
object.defineProperties(obj,{
name:{
configurable : true,
enumerable: false
},
age:{
configurable : true,
enumerable: false
}
})
构造函数(构造器)
定义
通常是我们在创建对象时执行的函数 通过new调用 首先会在内存创建一个新的对象,他内部的proto会被赋值为该构造函数的prototype属性 然后把this赋予给这个对象 执行函数内部代码 自动返回那个对象(this)
let obj={}
function foo (){
obj=this
this._ _proto_ _=foo.prototype
return obj
}
let p=new foo()
原型[proto]
早期ECMA没有提供原型 都是浏览器提供的_ proto _ 方便查看 ES5之后提供了object.getPrototypeOf(ob) 来查看这个对象的原型
用处
当我们从一个对象获取某一属性 他会获取该对象的get操作 在当前对象中查找get操作 如果没有找到 会找他的原型链去寻找get方法 可以在他的原型添加 **obj._ proto _.age=18 在原型里面添加 **是为了以后的实现继承
原型[prototype]这是一个属性
在new中把这个函数的原型给了这个函数的prototype但是因为foo.prototype中的enymerable(可枚举 查看属性)是false 所以看不见 所有函数原型里有个constructor属性 这个属性其实就是函数本身 也可以通过foo.prototype.constructor.name 拿到函数的名称
foo.prototype.name=11
foo.prototype.age=877
也可以
foo.prototype={
name:11,
age:877
}
他就把foo指向新的prototype对象 因为没有constructor 他的枚举还是false 所以要用Object.defindPropertye(foo.prototype,'constructor',
{
configurable: true 是否可以通过delect删除 是否可以修改的它特性 是否可以修改存取属性描述符
enumerable: false 是否可以通过for-in或者Object.keys()返回该属性
writable: true 是否可以修改属性
value:foo 属性值
}
)
可以把共性的东西放在原型里面
function Person(name, age, height, address) {
this.name = name
this.age = age
this.height = height
this.address = address
}
Person.prototype.eating = function() {
console.log(this.name + "在吃东西~")
}
Person.prototype.running = function() {
console.log(this.name + "在跑步~")
}
var p1 = new Person("why", 18, 1.88, "北京市")
var p2 = new Person("kobe", 20, 1.98, "洛杉矶市")
p1.eating()
p2.eating()
面向对象的特征
封装
我们将属性和方法封装在一个函数里面(编写函数的过程)
继承
重复利用一些代码(复用) 继承时多肽的前提(利用原型链实现继承)
多态
不同的对象在执行时表现的不同的形态
继承 1.使用原型链实现继承
function Person(name) {
this.name = "why"
this.friends = []
}
Person.prototype.eating = function() {
console.log(this.name + " eating~")
}
// 子类: 特有属性和方法 这个this就是student对象
function Student(name,age) {
// 解决弊端的方案
Person.call(this,name,age)
this.sno = 111
}
Student.prototype = new Person()
// 这种可以运行 但是从面向对象角度来说不正确 这样就可以其他人分享student添加原型的东西了
// Student.prototype = Person.prototype
Student.prototype.studying = function() {
console.log(this.name + " studying~")
}
var stu = new Student("why", 18, ["kobe"], 111, 100)
console.log(stu)
stu.eating()
这样做有三个弊端
- 继承的属性看不到 因为时放在原型里面了
- 获取引用 修改引用原型的值会互相影响 因为他是通过get操作寻找到原型链直接找到了这个方法
stu.friend.push('kobe') 这样改变了原型链上的方法但是直接修改本对象的值 是新增到自己的空间里stu.name='xsh' stu.friend=[] - 不好传参数 改造 借用构造函数 在子类引用父类函数 Person.call(this,name,age) 这种方法也是有弊端的
- Person 被调用了多次 并且创建一次调用一次
- stu原型对象回多出一些属性 但是这些属性没必要存在的 因为stu里面已经有了
通过对象的原型链继承 来实现函数的寄生式继承
第一种 使用 Object.setPrototypeOf(新对象,需要继承的对象)
function foo (obj){
var newObject={}
Object.setPrototypeOf(newObject,obj)
}
第二种 使用new函数 赋值创建关系
function foo1(obj){
function fn(){}
fn.prototype=obj
var result = new fn()
return result
}
第三种直接使用Object.create
var newObject = Object.create(obj)
寄生式继承
定义 原生式继承加上工厂函数
var personObj = {
running: function() {
console.log("running")
}
}
// 工厂函数
function createStudent(name) {
// 运用了第三种方式
var stu = Object.create(personObj)
stu.name = name
stu.studying = function() {
console.log("studying~")
}
return stu
}
var stuObj = createStudent("why")
var stuObj1 = createStudent("kobe")
var stuObj2 = createStudent("james")
最终版本 寄生组合式继承
// 是为了创建新的对象 来继承父类的原型
function createObject(o) {
function Fn() {}
Fn.prototype = o
return new Fn()
}
// 是为了把父与子原型建立关系
function inheritPrototype(SubType 子类, SuperType 父类) {
SubType.prototype = Objec.createObject(SuperType.prototype)
// 也可以直接用Object的create
// SubType.prototype = Objec.create(SuperType.prototype)
// 因为直接继承创建的是一个对象 没有constructor这个属性 这个属性对应的是这个调用的方法本身this 所以在打印的时候不会显示name
Object.defineProperty(SubType.prototype, "constructor", {
enumerable: false,
configurable: true,
writable: true,
value: SubType
})
}
// 夫类
function Person(name, age, friends) {
this.name = name
this.age = age
this.friends = friends
}
Person.prototype.running = function() {
console.log("running~")
}
Person.prototype.eating = function() {
console.log("eating~")
}
function Student(name, age, friends, sno, score) {
Person.call(this, name, age, friends)
this.sno = sno
this.score = score
}
// 建立父与子原型关系
inheritPrototype(Student, Person)
Student.prototype.studying = function() {
console.log("studying~")
}
var stu = new Student("why", 18, ["kobe"], 111, 100)
console.log(stu)
stu.studying()
stu.running()
stu.eating()
console.log(stu.constructor.name)
额外扩展
// Objec.create(obj,{
// 这个属性是添加到返回对象的本身上面 而不是原型上面
age:{
// 添加的是属性描述符
configurable: Boolean 是否可以通过delect删除 是否可以修改的它特性 是否可以修改存取属性描述符
enumerable: boolean 是否可以通过for-in或者Object.keys()返回该属性
writable: boolean 是否可以修改属性
value:111 属性值
}
})
// 判断是否为自己的还是原型的
// obj.hasOwnProprtype(name)
// in 操作符 (不管是在原型还是本身的)== for(var key in obj){}
// 'name' in obj
// instanceof 检测构造函数的pototype 是否出现在对象的原型链上 inf必须是个函数
// stu instanceof inf 检查stu的原型是否在inf的原型链上
// isPrototypeOf 某一个对象是否出现在原型链上 后面是必须对象
// console.log(Person.prototype.isPrototypeOf(p))
函数的proto prototype与对象的proto prototype有啥区别
var obj = {
name: "why"
}
console.log(obj.__proto__)
// 对象里面是有一个__proto__对象: 隐式原型对象
// Foo是一个函数, 那么它会有一个显示原型对象: Foo.prototype
// Foo.prototype来自哪里?
// 答案: 创建了一个函数, Foo.prototype = { constructor: Foo }
// Foo是一个对象, 那么它会有一个隐式原型对象: Foo.__proto__
// Foo.__proto__来自哪里?
// 答案: new Function() Foo.__proto__ = Function.prototype
// Function.prototype = { constructor: Function }
// var Foo = new Function()
function Foo() {
}
console.log(Foo.prototype === Foo.__proto__)
console.log(Foo.prototype.constructor)
console.log(Foo.__proto__.constructor)
var foo1 = new Foo()
var obj1 = new Object()
console.log(Object.getOwnPropertyDescriptors(Function.__proto__))