温馨提示×

温馨提示×

您好,登录后才能下订单哦!

密码登录×
登录注册×
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》

JavaScript高级部分

发布时间:2020-06-30 16:05:04 来源:网络 阅读:846 作者:超级极客 栏目:开发技术

一、代码模块

1.js里面代码可以放在不同的文件里, 称为模块

2.一个模块需要引用其他模块代码的时候,使用require()

3.require:

    (1)如果是第一次调用,那么就加载,执行脚本

    (2)每个代码模块由module.exports导出的对象

    (3)每次require的时候,都返回module.exports(模块出口)

    他可以指向任何类型, 函数,对象, 值.....

4.requirefunction Person(name,height){
 this.name=name;
 this.height=height;
 this.hobby=function(){
 return 'watching movies';
}
}

var boy=new Person('keith',180);
 var girl=new Person('rascal',153);
 console.log(boy.name); //'keith'
 console.log(girl.name); //'rascal'
 console.log(boy.hobby===girl.hobby);//false

, 如果是第一次执行,他就把

js里所有代码加载进来, 在执行这整个js文件, 然后返回module.exports.

require得到的就是module.exports指向的对象.

5.如果不是第一次require,他就直接返回module.exports.






二、this


显示传递this call


1.每个函数都包含两个非继承而来的方法:call()方法和apply()方法。

    (1)相同点: 两个方法的作用是一样的

    (2)不同点: 接收参数的方式不同.

2.作用:

.在特定的作用于中调用函数,等于设置函数体内this对象的值,

扩充函数赖以运行的作用域

(1)call方法使用

function test_func(name,sex){
    this.name = name;
    this.sex = sex;
}

var xiaoming = {};
test_func.call(xiaoming func,"xiaoming",10);
console.log(xiaoming);

(2)apply使用 两个参数 一个是函数的作用域(this),另一个是参数数组.

function test_func(name,sex){
    this.name = name;
    this.sex = sex;
}

var xiaoming = {};
test_func.apply(xiaoming,["xiaoming",10]);
console.log(xiaoming);



3.隐式传递this

这个this就是对象, 也就是对象直接调用,this被隐式传到函数里,

var xiaohong = {
    name: "xiaohong",
    test_func: function(){
        console.log(this);
    },
}
xiaohong.test_func();




4.强制传递绑定this

强制设置函数体this的值, 参数是一个表.


但是对象却不会引用这个函数>

var func = function(){
    console.log(this);
}.bind(xiaohong);
func();



5.定义完函数体,在绑定对象。

在定义完函数体后, 这个函数对象的this一定不是绑定的;

因为,函数对象来绑定对象的时候,不是把对象绑定到func函数对象里,

而是产生了一个新的函数对象,然后返回这个函数对象.

(1)错误,没有获得绑定好的函数对象

func = function(){
    console.log(this);
}
func.bind(xiaohong);


(2)正确,先获得绑定好的函数对象,再调用

func = function(){
    console.log(this);
}
func = func.bind(xiaohong);
func();



7.优先级

(1)绑定的优先级 大于 隐式传递

绑定一般用在回调函数。

var xiaohong = {
    name: "xiaohong",
    test_func: function(){
        console.log(this);
    }.bind(5),
}
xiaohong.test_func(); //输出的是5


(2)显示传递 大于 隐式传递

强制  >   显示   >  隐式








三、实现面向对象

.在javascript中不存在类的概念, 而是通过 构造函数

和原型链(prototype chains)实现的

function person(name, sex){
    this.name = name;
    this.sex = sex;    
}

person.prototype.test_func = function(){
    console.log("person test_func");
    console.log(this);
}

var p = new person("xiaohong",10);
console.log(p);


var p2 = new person("xiaotian",12);
console.log(p2);

p.test_func();
p2.test_func();





构造函数
(1)构造函数提供一个生成对象的模板并描述对象的基本结构,

一个构造函数可以生成多个对象,每个对象都有相同的结构,

构造函数就是对象的模板,  对象就是构造函数的实例,

构造函数特点:

    a:内部使用的this对象,指向要生成的对象实例,

    b:使用new操作符来调用构造函数,并返回对象实例,



(2)构造函数的缺点: 同一个对象实例之间, 当你new调用构造函数

返回一个实例的时候,里面的所有函数都会新创建出来, 这个函数

都是一个新创建的函数, 是不被实例共享的, 这样很浪费资源.

function Person(name,height){
 this.name=name;
 this.height=height;
 this.hobby=function(){
 return 'watching movies';
}
}

var boy=new Person('keith',180);
 var girl=new Person('rascal',153); 
 console.log(boy.name); //'keith'
 console.log(girl.name); //'rascal'
 console.log(boy.hobby===girl.hobby);//false




prototype属性

(1) 为了解决构造函数的对象之间无法共享属性的缺点,js提供了prototype属性.


(2)js中所有类型都是对象,(除了null和undefined),而每个对象都继承自另一个

对象, 称为"原型"对象 (prototype object) ,   null没有原型对象,


(3)原型对象上的所有属性和方法,都会被对象实例所享.


(4)通过构造函数生成对象实例时, 会将对象实例的原型指向构造函数

的prototype属性, 每一个构造函都有一个prototype属性,

这个属性就是对象实例的原型对象,  


(5)对于构造函数prototype是作为构造函数的属性,对于对象实例来说

prototype是对象实例的原型对象, 所以prorotype即是属性,又是对象.

function Person(name,height){
 this.name=name;
 this.height=height;

}

 Person.prototype.hobby = function(){
     return 'watching movies';
}

var boy = new Person('keith',180);
 var girl = new Person('rascal',153); 
 console.log(boy.name); //'keith'
 console.log(girl.name); //'rascal'
 console.log(boy.hobby===girl.hobby);//true

(6)原型对象的属性不是对象实例的属性,对象实例的属性是继承自

构造函数定义的属性,因为构造函数内部有一个this关键字,来指向

要生成的对象实例,对象实例属性, 其实就是构造函数内部定义的属性.

所以只要你修改原型对象上的属性和方法, 变动会离开体现在所有对象实例上.


(7)当某个对象实例没有该属性或方法时, 就会到原型对象上去查找

如果实例对象自身有某个对象或方法, 就不会去原型对象上查找,


如下,当boy对象实例hobby方法修改时, 就不会在继承原型对象

上的hobby方法了,  不会girl没有修改, 所以它依旧继承原型对象的方法.

function Person(name,height){
 this.name=name;
 this.height=height;

}
 Person.prototype.hobby = function(){
     console.log("aaa");
} 
var boy = new Person('keith',180);
var girl = new Person('rascal',153);  
boy.hobby = function(){
    console.log("bbb");
}

boy.hobby(); //bbb
girl.hobby(); //aaa


(8).原型链

对象的属性和方法,可能是定义在自身,也可能是原型对象,由于

原型对象本身对于对象实例来说也是对象,它也有自己的原型, 所以形成了

一条原型链(prototype chain),比如a对象是b对象的原型,b对象是c对象的原型

以此类推, 所有对象的原型顶端, 都是object.prototype,即object构造

函数的prototype指向的哪个对象, 而object.prototype也有自己的原型对象,

这个对象就是 "null" 没有任何属性和方法, 而null对象则没有原型.

特点:

    a.读取对象某个属性时,javaScript先找对象本身的属性,如果找不到,就去他的原型找,

    如果还是找不到,则去原型的原型找,直到object.portotype找不到则返回 undefined.

    b.如果对象自身和它的原型定义了同名属性,优先读取对象自身属性,称为 "覆盖"

    c.一级级向上找属性, 对性能有影响, 越上层,影响越大,



new 操作符

1.javascript也有new关键字, js中万物皆对象, 为何还要new关键字.

其实js中new关键字不是用来创建一个类的实例对象,而是用于继承,

function Animal(name){
  this.name = name;
}
Animal.color = "black";
Animal.prototype.say = function(){
  console.log("I'm " + this.name);
};
var cat = new Animal("cat");

console.log(
  cat.name, //cat
  cat.height //undefined
);
cat.say(); //I'm cat

console.log(
  Animal.name, //Animal
  Animal.color //back
);
Animal.say(); //not function

2.代码解读

1-3 行创建一个函数Animal,并在其this上定义了属性:name,

4 行在Animal对象(Animal本身是函数对象)上定义了一个静态属性:color,并复制"black"

5-7行在Animal函数的属性prototype上定义一个say方法,say输出了this的name值

8行使用new关键字创建了一个新对象cat,

10-14行cat对象常识方位name和color属性,并调用say方法

16-20行Animal对象访问name和color属性,并调用say方法



3.重点解析  new方法做了什么?

js引擎在执行new 这行代码的时候,做了很懂工作,伪代码如下

var obj = {};
obj.__proto__ = Animal.prototype;
var result = Animal.call(obj,"cat"); //显示传递this,和参数到构造函数
return typeof result === 'obj'? result : obj ;  //

a)__proto__(隐式原型)与prototype(显式原型)

每个对象都有__proto__属性, 但只有函数对象才有prototype属性.

b ) 首先会创建一个空对象obj,  把obj的__proto__指向Animal的原型对象

prototype, 此时便简历了obj对象的原型链:

obj -> Animal.prototype -> object.prototype -> null

c)在obj对象执行空间调用构造函数并传递参数"cat"

    这里这个obj就是构造函数里的this对象,this指向的就是obj;

d ) 判断返回值 如果无返回值或者返回非对象值, 则将obj作为新对象, 否则返回值

坐位新对象,



4.了解new运行机制后,cat就是d过程的返回值 表, 他有一个原型链,

cat上新增了一个新的属性: name


5.再次参照上面的代码分析

(1)cat.naem 在过程c  中obj作为this,传递到构造函数,构造产生name属性,

因此cat.name就是obj.name

(2)cat.color cat首先在自身找color,没有则言责原型链查找,我们仅在Animal

对象是哪个定义color,没有再其原型链上定义, 因此找不到

(3)cat.say() 首先找自身,没有,找原型链Animal的prototype属性定义了say

因此可以再原型链是上找到say方法

(4)Animal.color 对于Animal来说它本身是一个对象,因此他在访问属性也遵守

上述查找规则, 所以他能找到

(5)Animal.name 先查找自身naem 但这个name不是我们定义的name,

而是这个函数对象内部本身就存在这个属性,一般情况下,函数对象在产生内置name

属性会将函数名作为赋值(仅函数对象).

(6)Animal.say() Animal在自身查找, 没有,沿着原型链查找,

这是Animal函数对象的原型链

Animal的原型对象是Function.prototype 

原型链: Animal -> Function.prototype  -> Objecct.prototype -> null

JavaScript高级部分

在Animal原型链上并没有找到,say方法,  因为Animal的prototype

只是Animal的一个属性, 并不是它的原型对象,

Animal的原型对象是Function.prototype 

(7)所有实例化的对象,他们的__protp__都指向构造函数的prototype属性

只要有一个实例对象修改其中的内容, 其他的实例对象也会跟这改变.

(8)根据上面的知识实现面向对象

function Point(){
    this.xpos = 0;
    this.ypos = 0;
}
Point.prototype.set_pos = function(x,y){
    this.xpos = x;
    this.ypos = y;
}

Point.prototype.get_posy = function(){
    return this.ypos;
}

var p1 = new Point();
var p2 = new Point();
p1.set_pos(10,20);
p2.set_pos(100,200);
console.log(p1.get_posy());
console.log(p2.get_posy());




类的继承(原型实现)

1.继承就是父类有的方法或属性, 子类继承后其方法和属性子类也可以使用的.

2.继承实现方法: A类有个prototype, 类B也有个prototype

把类A的prototype的内容  复制(浅复制) 给类B的prototype,

这样的话,类A和类B公用了这个prototype

3.首先定义一个人类

var Person = function(){};
Person.prototype.set_name = function(name){
    this.naem = name; //设置姓名
};
Person.prototype.set_age = function(age){
    this.age = age; //设置年龄
};

4.定义一个男人类, 继承自人类, 有两种做法

(1)男人类.prototype = Person.prototype;

但是这样会造成一个问题:这样赋值就是引用赋值 (浅赋值),

导致这两个prototype指向的是同一个对象, 如果子类修改一个

方法属性, 父类的也会跟着改变,  显然是不行的.


(2)new出来的是新的实例,会把原来的prototype拷贝过来

这样就可以扩展自己的方法了, 实际上这个prototype的__ptoto还是

指向父类的prototype,  而prototype则共享__ptoto__里的属性方法,

扩展子类prototype的时候,不影响父类ptototype, 应为是new出来的, 他的

__proto__才指向父类prototype,  ptototype只是共享这个方法属性.

//定义一男人类
var Man = function(){};
//做法(1)

//做法(2)
var Super = function(){};
Super.prototype = Person.prototype;
Man.prototype = new Super();
//这里就是继承
Man.prototype.set_sex = function(sex){
    this.sex = sex;
}

console.log(Super.prototype);
console.log(Man.prototype);
console.log(Man.prototype.__proto__);
var m = new Man();
//使用父类方法
m.set_name("小王");
m.set_age(10);
//使用子类方法
m.set_sex(0);
console.log(m);


(3) 只要你扩展自己方法,和父类同名,就会隐藏父类方法,

因给根据原型链原则, 查找方法属性 先到实例本身进行查找 然后原型对象

这个原型其实就是他的父类.

Man.prototype.set_name = function(name){
    console.log("子类重写该方法");
}

(4) 如果要调用父类的函数, 使用父类的ptototype 把子类实例传给父类方法

Man.prototype.set_name = function(name){
    person.prototype.set_name.call(name);
    console.log("子类重写该方法");
}



(5)Class实现  可以继承 也可以继承

function Class(param){
    var new_class = function(){};
    //如果有要继承的父类
    if(param.extend != null){
        var Super = function(){};
        Super.prototype = param.extend.prototype;
        new_class.prototype = new Super();
    }
    //遍历参数 把内容添加到新对象里
    for(var key in param){
        if(key == "extend"){
            continue;
        }
        new_class.prototype[key] = param[key];
    }

    return new_class;
}


(6)使用Class函数 实现继承和 扩展方法属性

//Student学生类 传入参数表
var Student = Class({
    //继承自 Person
    extend: Person,

    //定义方法
    set_class: function(classa){
        console.log("set_class",classa);
    },

    //定义属性
    name: "学生类",
});

//实例化对象
var s = new Student();
s.set_class(12312);
console.log(s.name);



闭包

1. 看一段闭包代码

function a(){
    var n = 0;
    function inc(){
        n++;
        console.log(n);
    }
    inc(n);
    inc(n);
}
a(); //输出1  输出2

2.再 看一段闭包代码

function a(){
    var n = 0;
    this.inc = function(){
        n++;
        console.log(n);
    };
}
var c = new a();
c.inc(); //1
c.inc(); //2

3.闭包 有权访问另一个函数作用域内的遍历都是闭包, Inc函数访问

构造函数a里面的遍历n,所以形成一个闭包


4.匿名函数,lambda表达式,闭包区别:

从功能行上说他们是一个东西, 只是不同语言的不同称呼罢了,

它们都是匿名函数, 若匿名函数捕获了一个外部变量,它就是闭包.




qq交流群:140066160




向AI问一下细节

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

AI