逆战班
ECMAScript有两种开发模式
1.函数式(过程化) 面向过程( Procedure Oriented Programming )(POP); 关注过程,分布执行
2.面向对象( Object Oriented Programming )(OOP)关注整体,按模执行
面向对象的语言有一个标志,那就是类的概念,而通过类可以创建任意多个具有相同属性和方法的对象。但是,ECMAScript 没有类的概念,因此它的对象也与基于类的语言中的对象有所不同。
js本身是没有class类型的,但是每个函数都有一个prototype属性。prototype指向一个对象,当函数作为构造函数时,prototype则起到类似class的作用。
面向对象里的几种创建对象的方式:字面量,内置构造函数,工厂函数,自定义构造函数,原型对象,原型链,__proto__
{ }
弊端:代码冗余
//字面量创建
var stu1 = {
name:"yuzitong",
age:18,
sayHello:function(){
console.log(this.name);
}
}
var stu2 = {
name:"yangli",
age:18,
sayHello:function(){
console.log(this.name);
}
}
new Object()
弊端:代码冗余
//借助内置构造函数创建具体的对象
var stu1 = new Object();
stu1.name = "jiangdachen";
stu1.age = 20;
stu1.sayHello = function(){
console.log(this.name);
}
var stu2 = new Object();
function createObj(){
// statements
}
弊端:无法判断对象属于哪一个类型
//通过工厂函数创建具体的对象
function createObj(name,age){
var obj = new Object();
obj.name = name;//属性
obj.age = age;
obj.sayHello = function(){//方法
console.log(obj.name);
}
return obj;
}
var stu1 = createObj("john1",21);
var stu2 = createObj("yanghang",20);
var mimiao = createObj("xiaohua",2);
console.log(stu1);
console.log(stu2);
console.log(mimiao);
//instanceof 判断某一个具体的对象(实例)是否属于某一个类型(类)
console.log(stu1 instanceof Object);
console.log(mimiao instanceof Object);
console.log(stu1 instanceof Person);
console.log(mimiao instanceof Animal);
function Person(){
//statements
}
var person = new Person();
弊端:每个实例调用的方法应该是一致的,但是实际上在生成实例时,各自都创建了自己的方法。消耗了内存。
function Person(name,age){ //构造函数
//添加两个属性,一个方法
this.name = name;
this.age = age;
this.sayHello = function(){
console.log(this.name);
}
}
function Animal(name,age){//构造函数
this.name = name;
this.age = age;
this.sound = function(){
console.log("声音");
}
}
//创建两个实例
var person1 = new Person("john1",21);
var person2 = new Person("john2",22);
//创建两个实例
var animal1 = new Animal("miaomiao",2);
var animal2 = new Animal("wangwang",2);
//测试
console.log(person1,person2);
//测试person1和perosn2属于哪一个类型的实例
console.log(person1 instanceof Person);//true
console.log(person1 instanceof Object);//true
console.log(animal1 instanceof Animal);
person2.sayHello();
animal2.sound();
//判断出实例方法是否是同一个
console.log(person1.sayHello===person2.sayHello);//false
//普通函数
function foo(){
console.log(this);//window
}
foo(); //window.foo()
//对象方法里this
var obj = {
age:21,
sayHello:function(){
console.log(this);//obj
}
}
obj.sayHello();
//事件
btn.onclick = function(){
console.log(this);//btn
}
"use strict"
function foo(){
console.log(this);//严格模式下普通函数里this是指向undefined
}
foo();//没有具体的调用对象
window.foo();
指导思想:谁调用这个函数或者方法,this就指向谁
var name = "window";
var obj = {
name:"obj",
sayHello:function(){
console.log(this);//obj
setTimeout(()=>{
console.log(this.name);//obj
})
}
}
obj.sayHello();
function Person(name,age){
this.name = name; //给实例添加属性 实例属性
this.age = age;
this.sayHello = function(){ //给实例添加方法 实例方法
console.log(this.name);
}
}
var person = new Person("john",20);
//构造函数里this是指向实例
console.log(person.name,person.age);
function Person(){
}
//给原型对象添加属性和方法
Person.prototype.name = "john";
Person.prototype.age = 20;
Person.prototype.sayHello = function(){
console.log(this.name);
}
var person1 = new Person();
var person2 = new Person();
console.log(person1.sayHello === person2.sayHello);//true
console.log(person1.name,person2.name);
function Person(name,age){
this.name = name;
this.age = age;
}
Person.prototype.sayHello = function(){ //原型方法
console.log(this.name);//this也是指向实例
}
var person1 = new Person("john1",21);
var person2 = new Person("john2",22);
console.log(person1.name,person2.name);
constructor 作为原型对象的一个默认属性存在,表示创建实例的构造函数的引用
function Foo(){
}
//console.dir(Foo);
console.log(Foo.prototype);
console.log(Foo.prototype.constructor);
指的是一个虚拟的链条
Js中都有一个隐藏的属性__proto__
隐式原型其实它也是一个指针 它指向只有可能是原型对象(prototype)
所有原型对象都是由object创建的
fa.__proto__ === FnA.prototype
function FnA(){
this.a = "aa";
}
function FnB(){
this.b = "bb";
}
function FnC(){
this.c = "cc";
}
FnA.prototype = new FnB();
console.log(FnA.prototype);
var fa = new FnA();
console.log(fa.__proto__);
让一个类型(构造函数)的原型对象 等于另外一个类型的实例的话
FnA.prototype = new FnB(); //new FnB()创建了一个FnB的实例,这个实例里面有一个__proto__,指向FnB.prototype
console.log(FnA.prototype.__proto__ === FnB.prototype);
FnB.prototype = new FnC();
onsole.log(FnB.prototype.__proto__ === FnC.prototype);
var fa = new FnA();
console.log(fa.b);//bb
console.log(fa.c);//undefined
总结:每一个构造函数都有一个原型对象,每一个原型对象上都有一个指向构造函数的指针(constructor),每一个实例上有指向这个原型对象的内部指针__proto__
,原型对象上的属性和方法能被实例所访问到
FnB.prototype = new FnC(); //让FnB原型对象具有c属性
var fb = new FnB();
console.log(fb.c);//cc
FnA.prototype = new FnB();//让FnA原型对象里具有b属性
var fa = new FnA();
console.log(fa.b);
console.log(fa.c);
console.log(fa.__proto__=== FnA.prototype);
console.log(FnA.prototype.__proto__ === FnB.prototype);
console.log(FnB.prototype.__proto__=== FnC.prototype);
Foo.__proto__===Function.prototype
对象都是由(构造)函数创建的
函数时由函数的构造函数创建的
function Function(){}函数都是由此创建的
Function.__proto__===Function.prototype
console.log(fa.__proto__.__proto__.__proto__.__proto__.__proto__);
var arr = [];
console.log(arr.__proto__===Array.prototype);
console.log(arr.__proto__.__proto__);
console.log(arr.__proto__.__proto__.__proto__);
找到Object.prototype如果还没有就放回undefined
能力检测
所谓的能力检测就是用来处理兼容问题的
class Person{
//statements
}
var person = new Person();
class 类 自定义数据类型
es新增关键字 class
在JavaScript 是没有类的,由于 构造函数 的语法 对后端程序员不太友好
class的本质 是一个语法糖 构造函数的语法糖
构造函数 的意义 是创建 对象
class Person{
constructor(name,age){ //默认存在
this.name = name;
this.age = age;
}
sayHello(){ //自定义
console.log(this.name);
}
}
var person = new Person("john",20);
person.sayHello();
console.log(Person.prototype);
class和构造函数的关系
function Person(name,age){
this.name = name;
this.age = age;
}
Person.prototype.sayHello = function(){
console.log(this.name);
}
console.log(Person.prototype);
class Person{
constructor(name,age){ //默认存在
this.name = name;
this.age = age;
}
sayHello(){ //自定义
console.log(this.name);
}
}