JS原型,构造函数,匿名函数(2)

1.匿名函数和构造函数的理解

1.匿名函数(没有实际名字的函数)
–1--首先我们声明一个函数

function test(){
console.log("a");
}
test();

–2--将函数名去掉就是匿名函数

function (){
console.log("a");
}
test();

运行一个匿名函数,由于不符合语法要求,报错啦!解决方法只需要给匿名函数包裹一个括号即可。

(function (){
console.log("a");
})
test();

倘若需要传值,直接将参数写到括号内即可:

(function (a,b){
console.log(a+b);
})(1,2) //3

2.匿名函数的作用
1.绑定事件函数

var oDiv = document.getElementById('box');
oDiv.addEventListener('click',function(){
console.log('a');
},false)

2.对象

var obj = {
name:'kang',
age:20,
sayMessage:function(){
return this.name + this.age
}
}
console.log(obj.sayMessage());

3.作为一个函数表达式

var test = function(){
console.log("a")
}
test(); //a

4.回调函数

var i = 0;
setInterval(function(){
i++;
console.log(i)
},1000)

5.将匿名函数作为返回值
第一种调用方法

function test(){
return function(){
console.log('a');
}
}
test()();

第二种调用方法

function test(){
return function(){
console.log('a');
}
}
var a = test();
a();

2.构造函数(javascript中用new关键字来调用的函数称为构造函数)
–1--什么要使用构造函数

在js中,创建对象有两种方法:对象字面量和使用new表达式。
对象字面量是一种灵活方便的书写方式:
学习每一个概念,不仅要知道它是什么,还要知道为什么,以及解决什么样的问题。举个例子,我们要录入一年级一班中每一位同学的个人信息,那么我们可以创建一些对象,比如

var person1 = {
name:"zs",
age:6,
gender:'men'
}
var person2 = {
name:"ls",
age:6,
gender:'men'
}
var person1 = {
name:"ww",
age:6,
gender:'women'
}

像上面这样,我们可以把每一位同学的信息当做一个对象来处理。但是,我们会发现,我们重复地写了很多无意义的代码。比如 name、age、gender、hobby 。如果这个班上有60个学生,我们得重复写60遍。
这个时候,构造函数的优势就体现出来了。我们发现,虽然每位同学都有 name、gender、hobby 这些属性, 但它们都是不同的,那我们就把这些属性当做构造函数的参数传递进去。而由于都是一年级的学生,age 基本都是6岁,所以我们就可以写死,遇到特殊情况再单独做处理即可。此时,我们就可以创建以下的函数:

function Person(name,age,gender){
this.name = name;
this.age = age;
this.gender = gender;
}

当创建上面的函数以后, 我们就可以通过 new 关键字调用,也就是通过构造函数来创建对象了。

function Person(name,age,gender){
this.name = name;
this.age = age;
this.gender = gender;
}
var person1 = new Person('zs',6,'men');
var person2 = new Person('ls',6,'men');
var person3 = new Person('ww',7,'women');

此时你会发现,创建对象会变得非常方便。所以,虽然封装构造函数的过程会比较麻烦,但一旦封装成功,我们再创建对象就会变得非常轻松,这也是我们为什么要使用构造函数的原因。
在使用对象字面量创建一系列同一类型的对象时,这些对象可能具有一些相似的特征(属性)和行为(方法),此时会产生很多重复的代码,而使用构造函数就可以实现代码的复用。

那么,在使用new操作符来调用一个构造函数的时候,发生了什么呢?其实很简单,就发生了四件事:

1.var obj = {};
2.Obj.__proto__ = Person.prototype;
3.Person.call(obj);
4.Return obj;

第一行,创建一个空对象obj。
第二行,将这个空对象的__proto__成员指向了构造函数对象的prototype成员对象,这是最关键的一步,具体细节将在下文描述。
第三行,将构造函数的作用域赋给新对象,因此Person函数中的this指向新对象obj,然后再调用Person函数。于是我们就给obj对象赋值了一个成员变量p,这个成员变量的值是” I’min constructed object”。
第四行,返回新对象obj。当构造函数里包含返回语句时情况比较特殊,这种情况会在下文中说到。

我们说最重要的是第二步,将新生成的对象的__prop__属性赋值为构造函数的prototype属性,使得通过构造函数创建的所有对象可以共享相同的原型。这意味着同一个构造函数创建的所有对象都继承自一个相同的对象,因此它们都是同一个类的对象。

2.原型和原型链

在这里插入图片描述

//person.prototype --原型
//person.prototype --是祖先
Person.prototype.name = "kang";
function Person(){

}
var person1 = new Person();
var person2 = new Person();

当对象身上有自己的属性时,取自己的属性。

Person.prototype.name = "kang";
function Person(){
this.name = "kangwang"
}
var person1 = new Person(); //'kangwang
var person2 = new Person();

一个对象应该有自己的属性也有继承来的属性。
这里的person1和person2均是Person的一个实例,而实例都有一个constructor属性。

person1.constructor == Person  //true

而原型对象就是Person.prototype
在默认情况下,所有的原型对象都会自动获得一个 constructor(构造函数)属性,这个属性(是一个指针)指向 prototype 属性所在的函数(Person)
上面这句话有点拗口,我们「翻译」一下:A 有一个默认的 constructor 属性,这个属性是一个指针,指向 Person。即:

Person.prototype.constructor == Person

Person.prototype.lastname = "kang";
function Person(name,age,sex){
this.name = name;
this.age = age;
this.sex = sex;
}
var person1 = new Person("jiahao",20,'men'); //'kangwang
var person2 = new Person();

在这里插入图片描述
2.原型的应用

//原型的应用:
function Car(color,owner){
this.owner = owner;
this.color = color;
this.carname = "BMW";
this.lang = 1400;
this.length = 4900;
}
var car1 = new Car('red','kang');

上述属性中除了color和owner是选配的其余都是固定的,每次都会执行一次,造成了代码冗余,所以将固定的属性放在原型上,继承来更好。

//原型的应用:
Car.prototype.carname = "BMW";
Car.prototype.lang = '1400';
Car.prototype.lengh = '4900';
function Car(color,owner){
this.owner = owner;
this.color = color;
}
var car1 = new Car('red','kang');

在这里插入图片描述
构造函数都可以继承原型对象的属性。并且只执行一次
利用原型的概念和特点,可以提取公有属性。
3.原型的增删改查:

Person.prototype.lastname = 'deng'
function Person (name){
this.name = name;
}
var person1 = new Person('xuming')

在这里插入图片描述
通过对象修改原型的lastname属性是不行的,只是给对象增加了一个lastname属性而已。想要修改原型的lastname属性必须调用Person.Prototype.lastname来修改。(给对象自己身上增加一个属性)
不能删除原型属性,可以删除对象属性。
4.原型的对象字面量写法:

Car.prototype = {
carname:'bmv',
lang:1400,
length:4900
}
function Car(color,owner){
this.owner = owner;
this.color = color;
}
var car1 = new Car('red','kang');

5.Constructor
Constructor会返回调用该对象的构造函数。
Constructor也是可以手动修改的。
Constructor指向原型对象,
6.proto
JS 在创建对象(不论是普通对象还是函数对象)的时候,都有一个叫做__proto__ 的内置属性,用于指向创建它的构造函数的原型对象。
对象 person1 有一个 __proto__属性,创建它的构造函数是 Person,构造函数的原型对象是 Person.prototype ,所以:

 person1.__proto__ == Person.prototype //true

在这里插入图片描述
只有函数对象才有__proto__属性。

Grand.prototype.__proto__ == Object.prototype
true
Object.prototype.__proto__
null

3.原型链

原型链

Grand.prototype.lastname = "kang"
function Grand(){

}
var grand = new Grand();
Father.prototype = grand;
function Father(){
this.name = "jiahao"
}
var father = new Father();
Son.prototype = father;
function Son(){
this.hobbit = "ball"
}
var son = new Son();
var son = new Son();

此时son肯定可以访问到自己的属性hobbit(‘ball’),当son访问name属性时,自己属性内没找到,于是访问自己的__proto__属性里的原型对象,即son.__proto__指向Son.prototype.在father中寻找取得son.name = “jiahao”,然后访问son.lastname ,过程一样。

Grand.prototype.__proto__ == Object.prototype
true
Object.prototype.__proto__
null

Object.prototype 是所有对象的最终原型对象(×)。(原型链终端) 有特例。 undefined, null

Object.create(原型)只能放null和object
举个栗子:

var person = {
name:'kang',
age:20
}
var person1 = Object.create(person);
Person1.__proto__ == person  //true

Person.prototype.name = "kang"
function Person(){

}
var person = Object.create(Person.prototype)
Person.__proto__ == Person.prototype  //true

5.call和apply
JavaScript的call和apply有什么作用,有什么区别?
作用:改变this指向;
区别:传参列表不同;
Call 改变了Person中的this指向。

var person = function (name,age){
//call 让person中的this 指向了 obj
this.name = name;
this.age = age;
}
var person1 = new person();
var obj = {

}
person.call(obj,'kang',20)

function person(name,age,sex){
this.name = name;
this.age = age;
this.sex = sex;
}
function student(name,age,sex,tel,grade){
//person.call(this,name,age,sex); //借用别人的函数执行自己的功能。
this.name = name;
this.age = age;
this.sex =sex;
this.tel = tel;
this.grade = grade;
}

apply
Call需要把实参按照形参的个数传进去。
apply只能传一个参数,必须是数组形式。

function person(name,age,sex){
this.name = name;
this.age = age;
this.sex = sex;
}
function student(name,age,sex,tel,grade){
person.apply(this,[name,age,sex]); //借用别人的函数执行自己的功能。
// this.name = name;
// this.age = age;
// this.sex =sex;
this.tel = tel;
this.grade = grade;
}
var student1 = new student('kang',20,'men',15686942972,2017);
  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值