var obj1 = {'a': 'obj2','b':'2'};

var obj2 = {name: 'obj3'};

function extend() {

var length = arguments.length;

var target = arguments[0] || {};

if (typeof target!="object" && typeof target != "function") {

target = {};

}

if (length == 1) {

target = this;

i--;

}

for (var i = 1; i < length; i++) {

var source = arguments[i];

for (var key in source) {

// 使用for in会遍历数组所有的可枚举属性,包括原型。

if (Object.prototype.hasOwnProperty.call(source, key)) {

target[key] = source[key];

}

}

}

return target;

}

console.log(extend(obj1,obj2));

extend 要实现的是给任意对象扩展

分析一下

在extend()函数中没有写死参数,是为了更好的扩展性,永远也不知道需要扩展的对象有几个。

而是通过arguments来获取传进来的参数。

arguments对象不是一个 Array 。它类似于Array,但除了length属性和索引元素之外没有任何Array属性。

// 可以转换为数组 ES2015

const args = Array.from(arguments);

console.log(typeof arguments); // 'object'

target

target是传进来的第一个参数,也就是需要扩展的对象。

var target = arguments[0] || {}; // 如果没有传参,则设为一个空对象

// 进行这一步判断是为了保证代码的可执行性,如果传进来的是个数字、布尔值,则设为一个空对象

if (typeof target!="object" && typeof target != "function") {

target = {};

}

循环遍历赋值

for (var i = 1; i < length; i++) {

var source = arguments[i];

for (var key in source) {

// 使用for in会遍历数组所有的可枚举属性,包括原型。

if (Object.prototype.hasOwnProperty.call(source, key)) {

target[key] = source[key];

}

}

}

这一步就是将扩展源里的属性、方法循环遍历赋值到扩展项中。

如果扩展项和扩展源中有相同的属性、方法,后面的会覆盖前面的。 这个思想也是插件开发中,实现用户配置覆盖默认设置的实现思想。

hasOwnProperty

为什么需要使用hasOwnProperty,这跟for in有密切关系。

使用for in会遍历所有的可枚举属性,包括原型。

所以需要判断一下,是否是对象自身的属性,而不是继承于原型的。

那为什么不直接使用source.hasOwnProperty(source[key])呢?

JavaScript 并没有保护 hasOwnProperty 属性名,因此某个对象是有可能存在使用这个属性名的属性,使用外部的 hasOwnProperty 获得正确的结果是需要的:

var foo = {

hasOwnProperty: function() {

return false;

},

bar: 'Here be dragons'

};

foo.hasOwnProperty('bar'); // 始终返回 false

// 如果担心这种情况,可以直接使用原型链上真正的 hasOwnProperty 方法

({}).hasOwnProperty.call(foo, 'bar'); // true

// 也可以使用 Object 原型上的 hasOwnProperty 属性

Object.prototype.hasOwnProperty.call(foo, 'bar'); // true

call apply

上面用到的call和apply,就在这里记录一下。

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

2.相同点:这两个方法的作用是一样的。

都是在特定的作用域中调用函数,等于设置函数体内this对象的值,以扩充函数赖以运行的作用域。

一般来说,this总是指向调用某个方法的对象,但是使用call()和apply()方法时,就会改变this的指向。

3.不同点:接收参数的方式不同。

- apply()方法 接收两个参数,一个是函数运行的作用域(this),另一个是参数数组。

语法:apply([thisObj [,argArray] ]);,调用一个对象的一个方法,2另一个对象替换当前对象。

说明:如果argArray不是一个有效数组或不是arguments对象,那么将导致一个TypeError,如果没有提供argArray和thisObj任何一个参数,那么Global对象将用作thisObj。

- call()方法 第一个参数和apply()方法的一样,但是传递给函数的参数必须列举出来。

语法:call([thisObject[,arg1 [,arg2 [,…,argn]]]]);,应用某一对象的一个方法,用另一个对象替换当前对象。

说明: call方法可以用来代替另一个对象调用一个方法,call方法可以将一个函数的对象上下文从初始的上下文改变为thisObj指定的新对象,如果没有提供thisObj参数,那么Global对象被用于thisObj。

// call

window.name = 'FinGet';

document.name = 'FinGet1';

var boy = {name: 'FinGet2' };

function showName(){

console.log(this.name);

}

showName.call();         //FinGet (默认传递参数)  this 是指向window

showName.call(window);   //FinGet

showName.call(document); //FinGet1

showName.call(this);     //FinGet

showName.call(boy);       //FinGet2

var Pet = {

words : 'hello',

speak : function (say) {

console.log(say + ''+ this.words)

}

}

Pet.speak('Speak'); // 结果:Speakhello

var Dog = {

words:'Wang'

}

//将this的指向改变成了Dog

Pet.speak.call(Dog, 'Speak'); //结果: SpeakWang

可以将上面代码中的call换成apply,也是可以执行的。

Object.assign

Object.assign(target, …sources)

- target 目标对象

- sources 源对象

如果目标对象中的属性具有相同的键,则属性将被源中的属性覆盖。后来的源的属性将类似地覆盖早先的属性。

注意,Object.assign 会跳过那些值为 null 或 undefined 的源对象。

var obj1 = {a:'1',b:'2'};

var obj2 = {c:'3',d:'4'};

Object.assign(obj1,obj2); // Object {a: "1", b: "2", c: "3", d: "4"}

obj1 也改变

Object {a: "1", b: "2", c: "3", d: "4"}

obj2

Object {c: "3", d: "4"}

原生javascript实现extend的更多相关文章

  1. 原生JavaScript技巧大收集100个

    原生JavaScript技巧大收集 1.原生JavaScript实现字符串长度截取function cutstr(str, len) { var temp; var icount = 0; var p ...

  2. 原生 JavaScript 代替 jQuery【转】

    目录 用原生JavaScript代替jQuery Query Selector CSS & Style DOM Manipulation Ajax Events Utilities Promi ...

  3. 原生javascript封装动画库

    ****转载自自己发表于牛人部落专栏的文章**** 一.前言 本文记录了自己利用原生javascript构建自己的动画库的过程,在不断改进的过程中,实现以下动画效果: 针对同一个dom元素上相继发生的 ...

  4. 100个常用的原生JavaScript函数

    1.原生JavaScript实现字符串长度截取 复制代码代码如下: function cutstr(str, len) {    var temp;    var icount = 0;    var ...

  5. 原生javascript 实现 animate

    原生javascript 实现 animate //animate function getstyle(obj,name){ if(obj.currentStyle){ return obj.curr ...

  6. 浅谈 原生javaScript&&react 实现全局触摸按钮(附带对addeventlistener的了解)

    1.采用原生javaACript 实现全局触摸按钮 首先在控制台输出,观察事件有哪些关于触摸的字段可以使用,然后拿这些字段的数据开始来写方法. 因为要做的是全局触摸按钮,我需要拿到的是按钮时时的坐标位 ...

  7. 你可能不需要 jQuery!使用原生 JavaScript 进行开发

    很多的 JavaScript 开发人员,包括我在内,都很喜欢 jQuery.因为它的简单,因为它有很多丰富的插件可供使用,和其它优秀的工具一样,jQuery 让我们开发人员能够更轻松的开发网站和 We ...

  8. 原生JavaScript技巧大收集(11~20)-(终于又被我找到这篇文章了)

    11.原生JavaScript加入收藏夹 function AddFavorite(sURL, sTitle) { try { window.external.addFavorite(sURL, sT ...

  9. 原生javascript加载运行

    原生javascript加载运行 (function(){ //TODO sometings }()); 在要运行相应代码的位置加入script标签,创建函数并自执行; 关于window.onload ...

随机推荐

  1. 27.QT-QProgressBar动态实现多彩进度条(详解)

    如下图所示: 效果如下: (gif录制的动画效果不好,所以颜色有间隙) 介绍 通过qss实现,只需要一个多彩背景图,通过QImage获取颜色,然后来设置进度条,便可以实现动态多彩进度条(根据图片设定颜 ...

  2. (6)Microsoft office Word 2013版本操作入门_文件封面,页首,页尾

    1插入封面: 1.1光标移动到首段,按住 Ctrl+Enter键可以插入一个新页面. 1.2 插入--->封面 可以在封面插入一个文件封面,里面的图片可以自己修改,文字标题也可以自己修改. 1. ...

  3. myeclipse无法部署项目的解决

    一.问题 myeclipse无法部署项目,点击这个部署按钮没有反应. 二.解决办法 1.找到myeclipse的工作空间,也就是启动时的那个项目保存的空间,我的是在D:\myeclipse_works ...

  4. Spring Boot(Spring的自动整合框架)

    Spring Boot 是一套基于Spring框架的微服务框架,由于Spring是一个轻量级的企业开发框架,主要功能就是用于整合和管理其他框架,想法是将平时主流使用到的框架的整合配置预先写好,然后通过 ...

  5. IntelliJ IDEA生成live template(代码模板)

    IntelliJ IDEA生成live template(代码模板) 一.进入live template模板 快捷键:Ctrl+Shift+A进入Find Action,输入live template ...

  6. vue+vuecli+webpack中使用mockjs模拟后端数据

    前言 使用mockjs可以事先模拟数据,前提是和后端约定好了数据接口,怎样的数据.使用mock就可以生成你要的数据了,从而实现开发时前后端分离. 其主要功能是: 基于数据模板生成模拟数据. 基于HTM ...

  7. 纯CSS+HTML实现checkbox的思路与实例

    checkbox应该是一个比较常用的html功能了,不过浏览器自带的checkbox往往样式不怎么好看,而且不同浏览器效果也不一样.出于美化和统一视觉效果的需求,checkbox的自定义就被提出来了. ...

  8. 从换脸到换姿势,AI 在图像处理的道路上越走越魔幻

    从换脸到换姿势,AI 在图像处理的道路上越走越魔幻 https://mp.weixin.qq.com/s/VFq3BWLpzyKZ3sqVWf1HKA [导读]加州大学伯克利分校的研究人员,近日在著名 ...

  9. C# 实现连连看功能

    本文是利用C#实现连连看的小例子,以供学习分享使用.如有不足之处,还望指正. 思路: 初始化布局(横竖十行十列,共100个单元格,每一个格一个按钮,背景图为水果图片,随机生成) . 初始化对应棋盘(用 ...

  10. Java的优先级任务队列的实践

    队列的基本理解 在说队列之前说两个名词:Task是任务,TaskExecutor是任务执行器 而我们今天要说的队列就完全符合某机构这个情况,队列在有Task进来的时候TaskExecutor就立刻开始 ...