JS高级必须知道的几个点!

1.1 函数声明


//ES5

function getSum(){}

function (){}//匿名函数

//ES6()=>{}

//如果{}内容只有一行{}和return关键字可省,

1.2 函数表达式(函数字面量)


//ES5

var sum=function(){}

//ES6

let sum=()=>{}//如果{}内容只有一行{}和return关键字可省,

1.3 构造函数


var sum=new GetSum(num1,num2)

1.4 三种方法的对比


1.函数声明有预解析,而且函数声明的优先级高于变量;

2.使用Function构造函数定义函数的方式是一个函数表达式,这种方式会导致解析两次代码,影响性能。第一次解析常规的JavaScript代码,第二次解析传入构造函数的字符串


2.ES5中函数的4种调用


在ES5中函数内容的this指向和调用方法有关


2.1 函数调用模式


包括函数名()和匿名函数调用,this指向window


function getSum() {

    console.log(this) //window

}

getSum()

(function() {

      console.log(this) //window

})()

      var getSum=function() {

    console.log(this) //window

}

getSum()

2.2 方法调用


对象.方法名(),this指向对象


var objList = {

  name: 'methods', 

  getSum: function() { 

    console.log(this) //objList对象

  }

}

objList.getSum()

2.3 构造器调用


new 构造函数名(),this指向构造函数


function Person() {

  console.log(this); //指向构造函数Person

}

var personOne = new Person();

2.4 间接调用


利用call和apply来实现,this就是call和apply对应的第一个参数,如果不传值或者第一个值为null,undefined时this指向window


function foo() {

  console.log(this);

}

foo.apply('我是apply改变的this值');//我是apply改变的this值

foo.call('我是call改变的this值');//我是call改变的this值



3.ES6中函数的调用


箭头函数不可以当作构造函数使用,也就是不能用new命令实例化一个对象,否则会抛出一个错误。

箭头函数的this是和定义时有关和调用无关。

调用就是函数调用模式。


(() => {

  console.log(this)//window

})()

 

let arrowFun = () => {

  console.log(this)//window}

arrowFun()

 

let arrowObj = {

  arrFun: function() {

  (() => { 

    console.log(this)//arrowObj

  })()

  }

}

arrowObj.arrFun();



4.call,apply和bind


1.IE5之前不支持call和apply,bind是ES5出来的;

2.call和apply可以调用函数,改变this,实现继承和借用别的对象的方法;


4.1 call和apply定义


调用方法,用一个对象替换掉另一个对象(this)

对象.call(新this对象,实参1,实参2,实参3.....)

对象.apply(新this对象,[实参1,实参2,实参3.....])


4.2 call和apply用法


1.间接调用函数,改变作用域的this值

2.劫持其他对象的方法


var foo = {

  name:"张三", 

  logName:function(){

    console.log(this.name);

  }

}

var bar={

  name:"李四"

};

foo.logName.call(bar);//李四

实质是call改变了foo的this指向为bar,并调用该函数

3.两个函数实现继承


function Animal(name){ 

  this.name = name; 

  this.showName = function(){ 

    console.log(this.name);

  } 

function Cat(name){ 

  Animal.call(this, name); 

}   

var cat = new Cat("Black Cat"); 

cat.showName(); //Black Cat

4.为类数组(arguments和nodeList)添加数组方法push,pop


(function(){

  Array.prototype.push.call(arguments,'王五');

  console.log(arguments);//['张三','李四','王五']

})('张三','李四')

5.合并数组


let arr1=[1,2,3];

let arr2=[4,5,6];

Array.prototype.push.apply(arr1,arr2); //将arr2合并到了arr1中

6.求数组最大值


Math.max.apply(null,arr)

7.判断字符类型


Object.prototype.toString.call({})

4.3 bind


bind是function的一个函数扩展方法,bind以后代码重新绑定了func内部的this指向,不会调用方法,不兼容IE8。


var name = '李四'

var foo = {

  name: "张三",   

  logName: function(age) { 

  console.log(this.name, age);

  }

}

var fooNew = foo.logName;

var fooNewBind = foo.logName.bind(foo);

fooNew(10)//李四,10

fooNewBind(11)//张三,11  因为bind改变了fooNewBind里面的this指向



5.JS常见的四种设计模式

5.1 工厂模式


简单的工厂模式可以理解为解决多个相似的问题。


function CreatePerson(name,age,sex) {

    var obj = new Object();

    obj.name = name;

    obj.age = age;

    obj.sex = sex;

    obj.sayName = function(){   

        return this.name;

    }   

    return obj;

}

var p1 = new CreatePerson("longen",'28','男');

var p2 = new CreatePerson("tugenhua",'27','女');

console.log(p1.name); // longen

console.log(p1.age);  // 28

console.log(p1.sex);  // 男

console.log(p1.sayName()); // longen


console.log(p2.name);  // tugenhua

console.log(p2.age);  // 27

console.log(p2.sex);  // 女

console.log(p2.sayName()); // tugenhua 

5.2单例模式


只能被实例化(构造函数给实例添加属性与方法)一次


// 单体模式

var Singleton = function(name){

    this.name = name;

};

Singleton.prototype.getName = function(){

    return this.name;

}

// 获取实例对象

var getInstance = (function() {

    var instance = null;   

    return function(name) {   

        if(!instance) {//相当于一个一次性阀门,只能实例化一次

            instance = new Singleton(name);

        }       

        return instance;

    }

})();

// 测试单体模式的实例,所以a===b

var a = getInstance("aa");

var b = getInstance("bb");

5.3 沙箱模式


将一些函数放到自执行函数里面,但要用闭包暴露接口,用变量接收暴露的接口,再调用里面的值,否则无法使用里面的值。


let sandboxModel=(function(){   

    function sayName(){};   

    function sayAge(){};   

    return{   

        sayName:sayName,

        sayAge:sayAge

    }

})()

5.4 发布者订阅模式


就例如如我们关注了某一个公众号,然后他对应的有新的消息就会给你推送


//发布者与订阅模式

    var shoeObj = {}; // 定义发布者

    shoeObj.list = []; // 缓存列表 存放订阅者回调函数


    // 增加订阅者

    shoeObj.listen = function(fn) {

        shoeObj.list.push(fn); // 订阅消息添加到缓存列表

    }


    // 发布消息

    shoeObj.trigger = function() {

          for (var i = 0, fn; fn = this.list[i++];) {

              fn.apply(this, arguments);//第一个参数只是改变fn的this,

            }

        }

    // 小红订阅如下消息

    shoeObj.listen(function(color, size) {   

        console.log("颜色是:" + color);       

        console.log("尺码是:" + size);

    });

       

    // 小花订阅如下消息

    shoeObj.listen(function(color, size) {   

        console.log("再次打印颜色是:" + color);       

        console.log("再次打印尺码是:" + size);

    });

    shoeObj.trigger("红色", 40);

    shoeObj.trigger("黑色", 42); 

代码实现逻辑是用数组存贮订阅者, 发布者回调函数里面通知的方式是遍历订阅者数组,并将发布者内容传入订阅者数组。




6.原型链


6.1 定义


对象继承属性的一个链条


6.2构造函数,实例与原型对象的关系


var Person = function (name) { this.name = name; }//person是构造函数

var o3personTwo = new Person('personTwo')//personTwo是实例



原型对象都有一个默认的constructor属性指向构造函数

6.3 创建实例的方法


1.字面量


let obj={'name':'张三'}

2.Object构造函数创建


let Obj=new Object()

Obj.name='张三'

3.使用工厂模式创建对象


function createPerson(name){

var o = new Object();

o.name = name;

};

return o;

}

var person1 = createPerson('张三');

4.使用构造函数创建对象


function Person(name){

this.name = name;

}

var person1 = new Person('张三');

6.4 new运算符


1.创了一个新对象;

2.this指向构造函数;

3.构造函数有返回,会替换new出来的对象,如果没有就是new出来的对象

4.手动封装一个new运算符


var new2 = function (func) {

    var o = Object.create(func.prototype); //创建对象

    var k = func.call(o);          //改变this指向,把结果付给k

    if (typeof k === 'object') {      //判断k的类型是不是对象

        return k;              //是,返回k

    } else {   

        return o;               //不是返回返回构造函数的执行结果

    }

6.5 对象的原型链





7.继承的方式


JS是一门弱类型动态语言,封装和继承是他的两大特性


7.1原型链继承

将父类的实例作为子类的原型

1.代码实现

定义父类:


// 定义一个动物类

function Animal (name) {

  // 属性

  this.name = name || 'Animal';

  // 实例方法

  this.sleep = function(){ 

    console.log(this.name + '正在睡觉!');

  }

}

// 原型方法

Animal.prototype.eat = function(food) {

  console.log(this.name + '正在吃:' + food);

};

子类:


function Cat(){

}

Cat.prototype = new Animal();

Cat.prototype.name = 'cat';


// Test Code

var cat = new Cat();

console.log(cat.name);//cat

console.log(cat.eat('fish'));//cat正在吃:fish  undefined

console.log(cat.sleep());//cat正在睡觉! undefined

console.log(cat instanceof Animal); //true

console.log(cat instanceof Cat); //true

2.优缺点

简单易于实现,但是要想为子类新增属性和方法,必须要在new Animal()这样的语句之后执行,无法实现多继承


7.2 构造继承


实质是利用call来改变Cat中的this指向

1.代码实现

子类:


function Cat(name){

  Animal.call(this);

  this.name = name || 'Tom';

}

2.优缺点

可以实现多继承,不能继承原型属性/方法


7.3 实例继承


为父类实例添加新特性,作为子类实例返回

1.代码实现

子类


function Cat(name){

  var instance = new Animal();

  instance.name = name || 'Tom';

  return instance;

}

2.优缺点

不限制调用方式,但不能实现多继承


7.4 拷贝继承


将父类的属性和方法拷贝一份到子类中

1.子类:


function Cat(name){

  var animal = new Animal();

  for(var p in animal){

    Cat.prototype[p] = animal[p];

  }

  Cat.prototype.name = name || 'Tom';

}

2.优缺点

支持多继承,但是效率低占用内存


7.5 组合继承


通过调用父类构造,继承父类的属性并保留传参的优点,然后通过将父类实例作为子类原型,实现函数复用

1.子类:


function Cat(name){

  Animal.call(this);

  this.name = name || 'Tom';

}

Cat.prototype = new Animal();

Cat.prototype.constructor = Cat;

7.6 寄生组合继承


function Cat(name){

  Animal.call(this);

  this.name = name || 'Tom';

}

(function(){

  // 创建一个没有实例方法的类

  var Super = function(){};

  Super.prototype = Animal.prototype;

  //将实例作为子类的原型

  Cat.prototype = new Super();

})();

7.7 ES6的extends继承


ES6 的继承机制是先创造父类的实例对象this(所以必须先调用super方法),然后再用子类的构造函数修改this,


class ColorPoint extends Point {

  constructor(x, y, color) {

    super(x, y); // 调用父类的constructor(x, y)

    this.color = color;

  }


  toString() {    return this.color + ' ' + super.toString(); // 调用父类的toString()

  }

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,491评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,856评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,745评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,196评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,073评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,112评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,531评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,215评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,485评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,578评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,356评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,215评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,583评论 3 299
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,898评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,174评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,497评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,697评论 2 335

推荐阅读更多精彩内容

  • 工厂模式类似于现实生活中的工厂可以产生大量相似的商品,去做同样的事情,实现同样的效果;这时候需要使用工厂模式。简单...
    舟渔行舟阅读 7,697评论 2 17
  • 单例模式 适用场景:可能会在场景中使用到对象,但只有一个实例,加载时并不主动创建,需要时才创建 最常见的单例模式,...
    Obeing阅读 2,045评论 1 10
  • "use strict";function _classCallCheck(e,t){if(!(e instanc...
    久些阅读 2,025评论 0 2
  • 鲁家庙的庙早就不存在了,只剩下人们对它的回忆,以及那处名叫“庙道口”的地名。 据老人们讲述,那所庙里原来是有和尚的...
    草石阅读 720评论 0 1
  • 哈哈!今天又是忙碌的一天,答应给儿子包多彩的饺子,我今天的兑现,不然0当妈的说话不算数,以后怎么教育...
    爱你的贝贝阅读 186评论 0 4