一、构造函数模式
// 工厂函数模式function Person(name, age) {var obj = {};obj.name = name;obj.age = age;obj.sayHello = function () {console.log("My name is" + this.name, "I am " + this.age + " years old");}return obj;}var p1 = Person("chengxiaohui", 18);p1.sayHello();
// 构造函数模式function Person(name, age) {var obj = {};obj.name = name;obj.age = age;obj.sayHello = function () {console.log("My name is" + this.name, "I am " + this.age + " years old");}return obj;}// 多了一个newvar p1 = new Person("chengxiaohui", 18);p1.sayHello();
构造函数模式和工厂函数模式的区别?
- 1、执行的时候
- 普通函数执行Person函数
- 构造函数模式是通过new 执行,那Person就是一个类了
- 函数执行的返回值(p1)就是Person这个类的一个实例
2、在函数代码执行的时候
- 相同点:
- 都是形成一个私有作用域,然后形参赋值->预解析(变量提升)->代码从上向下执行
- 不同点:
- 在代码执行之前,不用自己手动创建对象,浏览器会默认创建一个对象数据类型的值(这个对象其实就是当前类的一个实例)
- this代表的就是当前的实例,然后把属性名和属性值赋值给当前的实例
- 最后浏览器会默认把创建的这个对象返回
// 创建一个数组var ary=[ ];//字面量方式创建var ary2=new Array();//构造函数创建// 无论通过哪种方式去创建,ary和ary2都是Array这个类的实例
- 相同点:
1、JS中所有的类都是函数数据类型,他通过new执行变成一个类,但是本质上他也是一个普通函数。
- 2、在构造函数模式中,类中(函数体)出现的this.xxx=xxx中的this是当前类的一个实例
- 3、p1和p2都是Person这个类的实例,所以都拥有sayHello这个方法,但是不同实例之间的方法是不一样的,实例和实例之间是单独的个体,所有的私有属性不是同一个。
- console.log(p1.sayHello===p2.sayHello);//false
构造函数里面代码执行的时候的不同点
- console.log(p1.sayHello===p2.sayHello);//false
// 构造函数模式function Person(name, age) {//在构造函数里,浏览器会默认给你创建一个对象//var obj = {};obj.name = name;obj.age = age;obj.sayHello = function () {console.log("My name is" + this.name, "I am " + this.age + " years old");}//浏览器默认返回了//return obj;}// 多了一个newvar p1 = new Person("chengxiaohui", 18);var p2 = new Person("zhanghuan", 19);p1.sayHello();
构造函数执行的时候不传参数可以省略()
function Fn() {}//没有写调用的小括号,但是依然会执行这个函数var f1 = new Fn;//作为普通函数执行必须要加小括号Fn();
this的问题:在类中的出现的this.xxx=xxx中的this都是当前类的实例,而某一个属性值(方法),方法中的this需要看方法执行的时候,前面是否有点,才能知道this指向谁
function Fn(name, age) {// 这个this指的是f1this.name = name;this.age = age;this.sayHello = function () {//这里的this要看这个函数执行的时候才知道console.log(this)}}var f1 = new Fn("chengxiaohui", 18);f1.sayHello();//this 指的是f1var f2=f1.sayHello;f2();//this指的是window
类有普通函数的一面,当函数执行的时候,var num其实只是当前形成的私有作用域中的私有变量而已,他和我们的f1这个实例没有任何的关系
function Fn(name, age) {//创建的变量var num;this.name = name;this.age = age;this.sayHello = function () {console.log(this)}}var f1 = new Fn("chengxiaohui", 18);f1.sayHello();var f2=f1.sayHello;f2();
构造函数返回值的情况
- 默认类中给返回了一个对象
- 如果写了return,return的是基本数据类型的话,还是返回那个默认对象
- 如果写了return,return的是引用数据类型,返回的就是return的那个东西
instanceof
检测某一个实例是都属于这个类(引伸用途:检测数据类型) 语法: 实例 instanceof 类
console.log(f1 instanceof Fn);console.log(f1 instanceof Object)
f1和f2都是Fn这个类的一个实例,都拥有name和sayHello两个属性,但是这两个属性是各自的私有属性
function Fn(name) {
this.name = name;
this.sayHello = function () {
console.log(this)
}
}
var f1 = new Fn("chengxiaohui");
var f2 = new Fn("zhanghuan");
二、原型
构造函数模式中拥有了类和实例的概念,并且实例和实例之间是相互独立的—>实例识别
如何将一个私有属性提升为公有属性呢?
function Fn(name) {
this.name = name;
}
//放在原型上成了公有属性
Fn.prototype.sayHello=function(){
console.log("I can say hello~");
}
var f1 = new Fn("chengxiaohui");
var f2 = new Fn("zhanghuan");
需要焊死在脑子里的三句话
- 1、每一个函数数据类型都有一个天生自带的属性:prototype(原型),这个属性值是一个对象数据类型
- 2、在prototype上浏览器天生给他加了一个constructor属性,属性值是当前函数(类)本身
- 3、每一个对象也天生自带一个属性:proto,属性值是当前实例所属类的原型
- 所有的函数:普通函数、类(内置类,自定义类)都是Function的实例,Function 和Object 都是Function的实例
- 所有的函数身上都有一个prototype 和proto
🖼画图解析

Object是JS中所有对象数据类型的基类(最顶层的类)
f1 instanceof Object->true因为f1通过proto可以向上查找,不管有多少级,最终都会找到Object上
三、原型链查找机制
f1.hasOwnProperty(“x”)
1、通过对象.属性名的方式获取到属性值的时候,首先在对象的私有属性上进行查找,如果私有属性上有,就是私有的这个
- 2、如果私有属性没有,则通过proto找到所属类的原型(类的原型上定义的属性和方法都是当前实例的公有属性和方法)
- 3、如果原型上也没有,则继续通过原型的proto继续向上查找,一直到Object.prototype为止
四、习题
var num=10;
var obj={num:20};
obj.fn=(function(num){
this.num=num*3;
num++;
return function(n){
this.num+=n;
num++;
console.log(num);
}
})(obj.num);
var fn=obj.fn;
fn(5);
obj.fn(10);
console.log(num,obj.num)
function Fn(){
this.x=100;
this.y=200;
this.getX=function(){
console.log(this.x);
}
}
Fn.prototype.getX=function(){
console.log(this.x);
}
Fn.prototype.getY=function(){
console.log(this.y);
}
var f1=new Fn;
var f2=new Fn;
console.log(f1.getX==f2.getX);
console.log(f1.getY==f2.getY);
console.log(f1.__proto__.getY==Fn.prototype.getY);
console.log(f1.__proto__.getX==f2.getX);
console.log(f1.getX===Fn.prototype.getX);
console.log(f1.constructor);
console.log(Fn.prototype.__proto__.constructor);
f1.getX();
f1.__proto__.getX();
f2.getY();
Fn.prototype.getY();
var fullName="languge";
var obj={
fullName:'javascript',
prop:{
getFullName:function(){
return this.fullName;
}
}
};
console.log(obj.prop.getFullName());
var test=obj.prop.getFullName;
console.log(test());
var name="window";
var Tom={
name:"Tom",
show:function(){
console.log(this.name);
},
wait:function(){
var fun=this.show;
fun();
}
};
Tom.wait();
function fun(){
this.a=0;
this.b=function(){
alert(this.a);
}
}
fun.prototype={
b:function(){
this.a=20;
alert(this.a);
},
c:function(){
this.a=30;
alert(this.a)
}
};
var my_fun=new fun();
my_fun.b();
var n=2;
var obj={
n:3,
fn:(function(n){
n+=2;
this.n+=2;
var n=5;
return function (m){
this.n*=2;
console.log(m+(++n));
}
})(n)
};
var fn=obj.fn;
fn(3);
obj.fn(3);
console.log(n,obj.n)
