1. 构造函数原型对象:prototype

构造函数独立创建对象,消耗性能

function Person(name) {

this.name = name;

this.sayHello = function () {

console.log("Hello,my name is " + this.name)

}

}

var P1 = new Person("Tom");

var P2 = new Person("Tom");

P1.sayHello();

P2.sayHello();

console.log(P1.sayHello == P2.sayHello)   返回值为false

返回值为false说明通过同一个构造函数独立创建的两个构造函数对象P1和P2的sayHello方法不相等,说明他们分别在内存中开辟了存储空间,消耗性能

② prototype:每一个函数都会有一个prototype属性

将同一个构造函数创建出的不同对象的不同函数方法,创建在该构造函数的prototype属性中,可实现只创建一次,所有该构造函数对象都可以调用这一方法

prototype是构造函数的原型属性,也是构造函数对象例如图中P1、P2的原型对象

prototype代码演示

1)动态添加方法属性,方法是独立分布添加上的,保留prototype指向构造函数的constructor属性

function Person(name) {

this.name = name;

}

Person.prototype.sayHello = function () {

console.log("sayHello");

}

Person.prototype.study = function () {

console.log("study");

}

Person.prototype.goHome = function () {

console.log("goHome");

}

var P1 = new Person("Tom");

var P2 = new Person("Jim");

var P3 = new Person("Jack");

P1.sayHello();

P2.study();

P3.goHome();

2)直接替换,创建一个对象添加方法属性,原本指向构造函数的constructor属性消失,        该替换添加在构造函数实例对象声明之前

function Person(name) {

this.name = name;

}

Person.prototype = {

    constructor:Person,      手动添加constructor属性

        sayHello: function () {

            console.log("sayHello");

        },

        study: function () {

            console.log("study");

        },

        goHome: function () {

            console.log("goHome");

        }

    }

var P1 = new Person("Tom");    声明构造函数对象

var P2 = new Person("Jim");

var P3 = new Person("Jack");

P1.sayHello();

P2.study();

P3.goHome();

__proto__:实例对象访问原型属性(双下划线)  IE8以下不支持

构造函数通过prototype访问原型

实例对象通过__proto__访问原型

(1)示例代码如下:

var object = {};

object.name = "Tom";

object.age = 18;

object.__proto__ = {

hello: "hello",

color: "red"

}

console.log(object.hello);

通过这个方法,可以给实例对象统一添加方法属性

(2)兼容性处理   IE8兼容处理

利用构造函数,访问constructorprototype,这样就可以访问原型

function Person(name) {

this.name = name;

}

function __getProto__(object) {

return object.constructor.prototype;

}

var ob = new Person("Jack");

console.log(__getProto__(ob) === ob.__proto__);    返回值为true

2. 继承

HTML对象原型继承关系,示例div:

② 混入

通过给对象添加一个extend方法,动态给对象添加属性

arguments: 函数中默认的类似数组类型对象,里面存储了所有传入的参数

相关代码示例如下:

var object = {

 extend: function (obj) {

for (var i = 0; i < arguments.length; i++) {

for (var k in arguments[i]) {

this[k] = arguments[i][k];

}

}

}

}

object.extend({name: "Tom"}, {age: 20, gender: "male"}, {

sayHello: function () {

console.log("Hello");

}

});

console.log(object)

混合式继承   通过给构造函数的原型属性添加方法实现

示例代码如下:

function Person() {

Person.prototype.extend = function (obj) {

for (var i = 0; i < arguments.length; i++) {

for (var k in arguments[i]) {

this[k] = arguments[i][k];

}

}

}

}

var p = new Person();

p.extend({name: "Tom"}, {age: 20, gender: "male"}, {

sayHello: function () {

console.log("Hello");

}

});

console.log(p);

Object.create( )  创建对象    IE8以下不支持该方法

示例代码如下:

var o = {name: "Tom", age: 20, gender: "male"};

var obj = Object.create(o);

console.log(obj);

创建的对象obj的属性和方法均继承自传入的对象o

Object.create( ) 方法的实现原理如下:

Object.create = function (obj) {

function F() { };

F.prototype = obj;

return new F();

}

IE8兼容性封装:

function createWithObject(obj) {

if (Object.create) {

return Object.create(obj);

} else {

function F() { };

F.prototype = obj;

return new F();

}

}

3. 对象的原型链  (构造函数)

示例代码如下:

function Person(name, age, gender) {

this.name = name;

this.age = age;

this.gender = gender;

};

function Student() { };

Student.prototype = new Person("Tom", 18, "male");

var student = new Student();

function Instance (){ };     所有构造函数都指向相同的原型

以上代码所对应的原型链结构示意图如下:

4. Function创建函数

Function是一个构造函数  new Function得到一个函数

new Function(arg0,arg1,…,argN,body );最后一个参数body是函数执行的代码块(函数体),其他参数都是传入函数代码块的参数

代码示例如下:

var getSum = new Function(“num1” , ”num2” , ”return num1+num2”);

函数代码块、函数体中内容太多时书写方法:

1.直接书写:  高斯求和函数

var getSum = new Function(“min” , ”max” , ” var sum = 0;for (var i = min; i <= max; i++) { sum = sum + i;}return sum;”);

2.字符串拼接书写:

var getSum = new Function("min", "max",

"var sum = 0;" +

"for (var i = min; i <= max; i++) {" +

"sum = sum + i;" +

"}" +

"return sum;");

3.获取HTML中的value书写:

封装一个tool函数:

function tool(idName) {

var ele = document.getElementById(idName);

var code = ele.innerText;

ele.parentNode.removeChild(ele);

ele = null;

return code;

}

将需要传入的参数内容写入HTML中:

<div id="div">

var sum = 0;

for (var i = min; i <= max; i++) {

sum = sum + i;

}

return sum;

</div>

再创建函数:

var getSum = new Function("min", "max",tool("div"));

5.函数的原型链

js中任何函数都是Function的实例

console.log(Function)   结果:function Function() { [native code] }

函数的基本原型链结构如下图所示:

6.完整的原型链结构图(对象与函数)

instanceof:判断构造函数的原型属性是否在该对象的原型链上

function Person() {};

var p = new Person();

console.log(p instanceof Object)             返回ture

console.log(p instanceof Person)            返回ture

console.log(Person instanceof Function)       返回ture

console.log(Person instanceof Object)        返回ture

不应该过多依赖原型链继承,非常消耗性能,解决办法如下:

var o = {

method: function () {

console.log("这是一个方法");

}

}

function Person() { };

Person.prototype = o;

function Student() {

  this.method = Person.prototype.method;   通过这种方式快速访问method

}

Student.prototype = new Person();      这样访问消耗性能,可以省略

var s = new Student();

s.method();

7.闭包   js中函数是具有作用域隔离特性的内存结果,可以作为一个闭包

返回函数

function func() {

var num = Math.random();

function fn() {

console.log(num);

return num;

}

return fn;

}

var foo = func();

var f1 = foo();

var f2 = foo();

因为在func中返回了fn,所以func只会被调用一次,fn被调用两次,打印结果相同

沙箱模式    一个隔离的执行环境

1)递归函数性能优化,以斐波拉契数列为例:

var count1 = 0;

function fib1(n) {

count1++;

if (n == 1 || n == 2) {

return 1;

} else {

return fib1(n - 1) + fib1(n - 2);

}

}

console.log(fib1(30));

console.log(count1);

var count2 = 0;

var data = [1, 1];        声明一个数组接收创建的fib(n)

function fib2(n) {

count2++;

if (data[n-1]) {       如果数组中有值,直接返回该值

return data[n-1];

} else {

return data[n-1] = arguments.callee(n - 1) + arguments.callee(n - 2);

}

}

console.log(fib2(30));

console.log(count2);

通过比较count1与count2的值可以发现,使用数组接收存储fib2(n)值的函数递归次数明显小于直接递归的fib1函数,性能得到极大优化

对斐波拉契数列函数进行闭包封装:封装一个自执行函数fib

var fib = (function () {

var data = [1, 1];

return function(n) {

if (data[n - 1]) {

return data[n - 1];

} else {

return data[n - 1] = arguments.callee(n - 1) + arguments.callee(n - 2);

}

}

})();

2)闭包应用:封装一个带有事件添加和移除的函数

var tabbLoad = (function () {

var data = [];

window.onload = function () {

for (var i = 0; i < data.length; i++) {

data[i]();

}

}

return {

addEvent: function (fn) {

data.push(fn);

}, removeEvent: function (fn) {

for (var i = data.length - 1; i >= 0; i--) {

if (fn.toString() === data[i].toString()) {

data.splice(i, 1);

}

}

}

}

})();

   tabbLoad.addEvent(function () {

console.log("执行函数1")

})

 tabbLoad.addEvent(function () {

console.log("执行函数2")

})

 tabbLoad.removeEvent(function () {

console.log("执行函数2")

})

3)闭包应用:创建一个可以缓存的函数cache

var createCache = (function () {

 var data = [], max = 3;     max为设置的缓存最大值,在查看data数据时可以将var去掉,将data变为全局变量,但在实际应用时一定不能去掉

function cache(key, value) {

data.push(key);

 cache[key] = value;

if (data.length > max) {

var temp = data.shift();

delete cache[temp];

}

}

return cache;

})();

cache("name1","Tom")

cache("name2","Jim")

 cache("name3","Jack")

    cache("name4","Lily")

JavaScript (JS) 面向对象编程 浅析 (含对象、函数原型链、闭包解析)的更多相关文章

  1. JS面向对象组件(一) ---包装对象与原型链

    首先我们可以看看平时我们常用的 var str = 'hello'; alert(typeof str); //string var str = new String("hello" ...

  2. 04面向对象编程-01-创建对象 和 原型理解(prototype、__proto__)

    1.JS中对象的"不同":原型概念 从Java中我们可以很好地去理解 "类" 和 "实例" 两个概念,可是在JavaScript中,这个概念 ...

  3. Js面向对象编程

    Js面向对象编程 1.     什么是面向对象编程? 我也不说不清楚什么是面向对象,反正就那么回事吧. 编程有时候是一件很快乐的事,写一些小游戏,用编程的方式玩游戏等等 2.     Js如何定义一个 ...

  4. 页面循环绑定(变量污染问题),js面向对象编程(对象属性增删改查),js字符串操作,js数组操作

    页面循环绑定(变量污染问题) var lis = document.querySelectorAll(".ul li") for ( var i = 0 ; i < lis. ...

  5. JS面向对象编程,对象,属性,方法。

    document.write('<script type="text/javascript" src="http://api.map.baidu.com/api?v ...

  6. JavaScript的面向对象编程(OOP)(一)——类

    在学习JavaScript面向对象的编程之前,需要知道,并了解面向对象的一些基本的常识.初学者中大多数都以为面向对象中,面向对象的编程是很重要和占据很大一部分精力.笔者在之前也是认为OOP是面向对象的 ...

  7. JS面向对象编程(进阶理解)

    JS 面向对象编程 如何创建JS对象 JSON语法声明对象(直接量声明对象) var obj = {}; 使用 Object 创建对象 var obj = new Object(); JS对象可以后期 ...

  8. js面向对象编程 ---- 系列教程

    原 js面向对象编程:数据的缓存 原 js面向对象编程:如何检测对象类型 原 js面向对象编程:if中可以使用那些作为判断条件呢? 原 js面向对象编程:this到底代表什么?第二篇 原 js面向对象 ...

  9. 简单粗暴地理解js原型链–js面向对象编程

    简单粗暴地理解js原型链–js面向对象编程 作者:茄果 链接:http://www.cnblogs.com/qieguo/archive/2016/05/03/5451626.html 原型链理解起来 ...

随机推荐

  1. macOS如何正确驱动集成显卡HDMI(包括视频和音频)

    聊聊如何正确驱动集成显卡HDMI(包括视频和音频)必备条件:1.必须使用AppleHDA驱动声卡(仿冒.clover.applealc都可以的),使用voodoo驱动声卡应该不行的.2.dsdt或者s ...

  2. D-bus交叉编译

    在嵌入式中如果需要Qt系统支持U盘插拔,则需要Qt支持D-bus. D-bus的交叉编译依赖expat库,此库为XML解析库. 交叉编译expat库: #./configure --host=XXX ...

  3. 【图论】[USACO]控制公司 Controlling Companies

    玄妙的搜索 题目描述 有些公司是其他公司的部分拥有者,因为他们获得了其他公司发行的股票的一部分.(此处略去一句废话)据说,如果至少满足了以下三个条件之一,公司A就可以控制公司B了: 公司A = 公司B ...

  4. SSH实验

    跳板机实验1:本地转发 实验环境: 三台主机:A,B,C 目标A与C通过telnet连接 A主机和B,C主机之间有防火墙相隔,A与B之间可以通过SSH协议连接,BC之间可以通过telnet协议连接 环 ...

  5. python字典形list 去重复

    data_list = [{"}] run_function = lambda x, y: x if y in x else x + [y] return reduce(run_functi ...

  6. 判断Datable是否有数据

    采用any()方法 检查表格的数据是否为空 var table = $('#example').DataTable(); if ( ! table.data().any() ) { alert( 'E ...

  7. SpringBoot AOP综合例子

    完整源码:https://github.com/947133297/cgLibDemo 通过AOP来便捷地输出日志,能更加方便排查系统的bug,这个例子中简单输出自定义文件和函数执行时的参数,函数要不 ...

  8. python3.7 迭代器和生成器

    #!/usr/bin/env python __author__ = "lrtao2010" #python3.7 迭代器和生成器 #迭代器协议: ''' 1.迭代器协议是指:对象 ...

  9. Python中的dict

    dict_lst = [ ('字典的键必须可哈希',), ('字典的键重复覆盖',), ('字典可迭代') ('增',), ('删',), ('改',), ('查',), ('练习',), ] 字典的 ...

  10. Spring---浅谈IOC

    概念 IOC(Inversion of Control 控制反转)是spring的核心,贯穿始终.所谓IOC,对于spring框架来说,就是由spring来负责控制对象的生命周期和对象间的关系. 传统 ...