JavaScript实例属性与构造器属性

在构造器上设置属性

首先在js中函数也是对象,所以在js中函数也可以挂载属性和方法

function Bar(){} 
Bar.name="i m bar"; 
Bar.sayname=function(){ 
   console.log(this.name) 
} 
Bar.sayname();//Bar; 

var sum=Bar; 
sum.sayname="no this function"; 
console.log(Bar.sayname);//"no this function" 
Bar=null; 
console.log(sum.sayname);//no this function 

首先Bar.sayname()结果并不是”i m bar”而是一个”Bar” 而且你是无法改写这个name属性的 说明函数自身就带了一个name属性,保存的是他的名字.所以弹出的会是”Bar”下面我们声明了一个变量sum并且把Bar赋值给他.同时改写了一下sum的sayname属性.然后调用了Bar.sayname得出的结果是”no this function” 接着我们把Bar设置为null 然后再调用一下sum的.sayname方法发现还是存在的。

JavaScript高级程序设计里有段话说的挺好的 #110

由于函数名仅仅是指向函数的指针,因此函数名与包含对象指针的其他变量没有什么不同.换句话说函数可能会有多个名字.即时我们将Bar设置为null但是sum是他的另外一个名字.

构造器的属性去哪了?

Function.prototype.testname="i m test name"; 
function Bar(){} 
Bar.sayTestName=function(){ 
   console.log("%c "+this.testname,"color:red;") 
} 
Bar.sayTestName();//i m test name 
Bar instanceof Function//true 

okay,我们知道Function的是指向Function的原型的.那么我们把属性挂载到原型.那么函数就是Function的实例,实例中找不到的属性自然就会顺着原型链去原型上面找了.

在Object.prototype和Object添加会产生什么效果?

Object.testname="i m ObjectEntry name"; 
Object.prototype.testname="i m Object prototype name "; 
function Bar(){} 
Bar.sayTestName=function(){ 
   console.log("%c "+this.testname,"color:red;") 
} 
Bar.sayTestName();//i m Object prototype name 

首先我们知道所有的Function.prototype都来自于Object.prototype那么在Function.prototype找不到的自然就会去Object.prototype上面寻找了.Object是Object的实例所以并不会在这上面找.实例的方法与原型的方法是相隔的.具体解释看下面的

new 构造器是什么鬼?

Function.prototype.testname="i m test name"; 
Object.prototype.testname="i m bar object name"; 
function Bar(){ 
   this.sayTrueName=function(){ 
       console.log("%c "+this.testname,"color:green;") 
   } 
} 
Bar.sayTestName=function(){ 
   console.log("%c "+this.testname,"color:red;") 
} 
Bar.sayTestName();//i m test name 

var bar=new Bar() 
console.log("can you find bar.sayname ?",bar.sayname);//undefined 
bar.sayTrueName();// 

okay.从上述代码我们可以看出了一些道理了

  • new 一个函数 实际上是创建了Object的一个实例
  • 声明一个函数实际上是创建了一个Function实例

写点继承来理解下实例与构造器

var XiaoMing=function(){ 
   this.info="i m xiaoming today i  choose death"; 
   this.sayHello=function(){ 
       console.log(this.info) 
   } 
} 

XiaoMing.prototype.goToDie=function(){ 
   console.log(this.name+" go die") 
} 

var XiaoHong=function(){ 
   this.name="xiaohong"; 
} 

XiaoHong.prototype=new XiaoMing(); 
var xiaohong=new XiaoHong(); 
xiaohong.goToDie();//xiaohong go die; 
xiaohong.sayHello();//i m xiaoming today i  choose death; 

通过设置XiaoHong的原型来构建成一条原型链,下面来大概解释下new XiaoHong=>XiaoHong.prototype=>new XiaoMing()=>XiaoMing.prototype=>Object.prototype=>null;首先我们实例化小明的时候.那么小明会有以下的属性

xiaoming:{ 
   info:"i m xiaoming today i  choose death"; 
   sayHello:function(){ 
       console.log(this.info) 
   } 
   _proto_:xiaoming.prototype 
} 
xiaoming.prototype:{ 
   goToDie:function(){ 
       .... 
   } 
} 

那么实例化小红的时候也是同理.当调用xiaohong的goToDie()方法实际上是去顺着这个属性来寻找.

  • A:xiaohong本身(this)有没有这个goToDie方法啊?
  • B:不好意思,没有
  • A:那麻烦你去xiaohong的原型链(prototype)上找找好不到
  • B:okay let me find… oh. i find new XiaoMing..i must instantiate(实例化) XiaoMing
  • B:我在实例化XiaoMing..让我在实例化的XiaoMing本身找找…恩..貌似没有.但是它有proto让我去它原型链上找找
  • B:找到了!在实例化XiaoMing的原型链上 来给你
  • A:thanks

(正在学习英语..让我写几句渣渣英语 大神勿喷..)

大概就是这么一个寻找过程..如果在中间任何一个环节找到了就不会继续往下寻找了.那么我们也可以通过设置原型链的模式来继承

var XiaoMing=function(){ 
   this.info="i m xiaoming today i  choose death"; 
   this.sayHello=function(){ 
       console.log(this.info) 
   } 
} 

XiaoMing.prototype.goToDie=function(){ 
   console.log(this.name+" go die") 
} 

var XiaoHong=function(){ 
   this.name="xiaohong"; 
} 

XiaoHong.prototype=XiaoMing.prototype; 
var xiaohong=new XiaoHong(); 
console.log(xiaohong) 
xiaohong.goToDie();//xiaohong go die; 
xiaohong.sayHello();//error; 

~~ 通过设置XiaoHong.prototype来获得继承也是可以的. ~~

如果是new XiaoMing()这样会把XiaoMing本身的属性也就是this.xxx=xxx给继承下来.我们仅仅是需要原型链上的属性.所以我们可以用Object.create(XiaoMing.prototype)来继承.

同时实例之间的属性并不会相互影响 下面摘录JavaScript高级程序设计中的代码 #150

function Person(){ 
   this.name="123"; 
   this.sayName=function(){ 
       console.log(this.name) 
   } 
} 
var person1=new Person(); 
var person2=new Person(); 
person2.name="456" 
person1.sayName()//123 
person2.sayName()//456 
console.log(person1.sayName===person2.sayName)//false 

但是通过构造函数实例化后.不同实例上的同名函数是不想等的.但是原型就不同了.下面把上面的例子改写一下

function Person(){ 
   
} 
Person.prototype.name="123"; 
Person.prototype.sayName=function(){ 
       console.log(this.name) 
} 
var person1=new Person(); 
var person2=new Person(); 
person2.name="456"; 
person1.sayName()//123 
person2.sayName()//456 
console.log(person1.sayName===person2.sayName)//true 

当然原型上的属性是不会相等的.

所以我们会这样称呼上述的属性 代码转自here

(function(){ 
   //私有静态成员 
   var user = ""; 
    
   //私有静态方法 
   function privateStaticMethod(){ 
   } 

    
   Box = function(value){ 
       //私有成员 
       privateStaticUser = value;  
        
       //这个是私有方法 
       function privateMethod(){ 
       } 

        
       //公有方法,因为能访问私有成员,也可以说是特权函数,也可以说是实例方法 
       this.getUser = function(){ 
           return user; 
       };       
        
       //公有成员 
       this.user = 1; 
   }; 
    
   //公有共享访问 
   Box.prototype.sharedMethod = function () {}; 
    
   //公有共享属性 
   Box.prototype.sharedProperty = function () {}; 

    
   //公有静态方法  
   Box.staticMethod = function(){}; 
    
   //公有静态成员 
   Box.staticProperty = 1;  
})(); 

那么问题来了

什么是公有共享 公有静态?

首先私有的很好理解 就是外面不能访问到的.那么公有共享就是原型链上面的方法和属性了 包括函数内部的this.xxx 因为在实例化后都能访问到 这些都是公有共享那么公有静态是什么?公有静态是直接挂载到函数上的还是用一段代码来演示 转自here

function Man(name, age) {  
//定义实例属性  
this.name = name;  
this.age = age;  
}  

//定义静态属性。默认性别是男,不排除变性,^v^  
Man.sex = '男';  
//定义原型属性  
Man.prototype.phone = '123456';  
//除了name.sex和Man.prototype.phone其余全部是Undefined  
alert(Man.sex + "-----" + Man.prototype.phone + "--" + Man.name + "--" + Man.age + "--" + Man.phone);  
var man = new Man("Tom", 24);  
alert(Man.sex + "--" + man.name + "--" + man.age + "--" + man.phone);  
/**  
* 通过例子说明:原型属性在实例化之后作为类的实例属性。  
* 但是实例属性在实例化之后却不能作为原型属性。  
*/ 

okay 上面有两个公有属性 this.name和this.age 一个公有共享的属性Man.prototype.phone 一个公有静态方法 Man.sex那么没有实例化之前 我们只能访问到prototype和Man.sex 其他的都需要实例化后才能获取到.实例化后.我们能够访问到Man.sex但是访问不到man(实例).sex 因为公有静态方法是不会通过原型继承的.而公有共享和公有方法是可以通过原型继承的.

今天就说这么多吧.有什么坑后续再填